Refactoring, some bugfixes, GSI bindings for L2N methods.

This commit is contained in:
Matthias Koefferlein 2019-01-20 23:12:27 +01:00
parent 4c7f43d749
commit f83e1dae43
16 changed files with 682 additions and 284 deletions

View File

@ -46,6 +46,7 @@ public:
DeepRegion (const RecursiveShapeIterator &si, DeepShapeStore &dss, const db::ICplxTrans &trans, bool merged_semantics = true, double area_ratio = 3.0, size_t max_vertex_count = 16);
DeepRegion (const DeepRegion &other);
DeepRegion (const DeepLayer &dl);
virtual ~DeepRegion ();
@ -94,10 +95,9 @@ protected:
private:
DeepRegion &operator= (const DeepRegion &other);
DeepRegion (const DeepLayer &dl);
DeepLayer m_deep_layer;
// @@@ have hierarchical merged polygons later
// TODO: have hierarchical merged polygons later
mutable db::Shapes m_merged_polygons;
mutable bool m_merged_polygons_valid;

View File

@ -195,7 +195,7 @@ struct DeepShapeStore::LayoutHolder
void remove_layer_ref (unsigned int layer)
{
if ((layer_refs[layer] -= 1) <= 0) {
layout.clear_layer (layer);
layout.delete_layer (layer);
layer_refs.erase (layer);
}
}
@ -343,7 +343,9 @@ DeepLayer DeepShapeStore::create_polygon_layer (const db::RecursiveShapeIterator
db::Layout &layout = m_layouts.back ()->layout;
layout.hier_changed_event.add (this, &DeepShapeStore::invalidate_hier);
layout.dbu (si.layout ()->dbu ());
if (si.layout ()) {
layout.dbu (si.layout ()->dbu ());
}
m_layout_map[si] = layout_index;

View File

@ -36,13 +36,22 @@ static HierarchyBuilderShapeInserter def_inserter;
int
compare_iterators_with_respect_to_target_hierarchy (const db::RecursiveShapeIterator &iter1, const db::RecursiveShapeIterator &iter2)
{
if ((iter1.layout () == 0) != (iter2.layout () == 0)) {
return (iter1.layout () == 0) < (iter2.layout () == 0);
}
if ((iter1.top_cell () == 0) != (iter2.top_cell () == 0)) {
return (iter1.top_cell () == 0) < (iter2.top_cell () == 0);
}
// basic source (layout, top_cell) needs to be the same of course
if (iter1.layout () != iter2.layout ()) {
// NOTE: pointer compare :-(
return iter1.layout () < iter2.layout () ? -1 : 1;
}
if (iter1.top_cell ()->cell_index () != iter2.top_cell ()->cell_index ()) {
return iter1.top_cell ()->cell_index () < iter2.top_cell ()->cell_index () ? -1 : 1;
if (iter1.top_cell ()) {
if (iter1.top_cell ()->cell_index () != iter2.top_cell ()->cell_index ()) {
return iter1.top_cell ()->cell_index () < iter2.top_cell ()->cell_index () ? -1 : 1;
}
}
// max depth controls the main hierarchical appearance
@ -51,10 +60,11 @@ compare_iterators_with_respect_to_target_hierarchy (const db::RecursiveShapeIter
}
// if a region is set, the hierarchical appearance is the same only if the layers and
// complex region are indentical
// complex region are identical
if ((iter1.region () == db::Box::world ()) != (iter2.region () == db::Box::world ())) {
return (iter1.region () == db::Box::world ()) < (iter2.region () == db::Box::world ()) ? -1 : 1;
}
if (iter1.region () != db::Box::world ()) {
if (iter1.has_complex_region () != iter2.has_complex_region ()) {
return iter1.has_complex_region () < iter2.has_complex_region () ? -1 : 1;
@ -174,30 +184,36 @@ HierarchyBuilder::begin (const RecursiveShapeIterator *iter)
m_cell_stack.clear ();
m_cells_seen.clear ();
if (! iter->layout () || ! iter->top_cell ()) {
return;
}
std::pair<db::cell_index_type, std::set<db::Box> > key (iter->top_cell ()->cell_index (), std::set<db::Box> ());
m_cm_entry = m_cell_map.find (key);
m_cm_new_entry = false;
if (m_cm_entry == m_cell_map.end ()) {
db::cell_index_type new_top_index = mp_target->add_cell (iter->layout ()->cell_name (key.first));
m_cm_entry = m_cell_map.insert (std::make_pair (key, new_top_index)).first;
m_cm_new_entry = true;
}
db::Cell &new_top = mp_target->cell (m_cm_entry->second);
m_cells_seen.insert (key);
// NOTE: we consider the top cell "new" if it does not have instances.
// We can do so as the recursive shape iterator will always deliver all instances
// and not a partial set of instances.
m_cm_new_entry = new_top.begin ().at_end ();
m_cell_stack.push_back (std::make_pair (m_cm_new_entry, &new_top));
}
void
HierarchyBuilder::end (const RecursiveShapeIterator * /*iter*/)
HierarchyBuilder::end (const RecursiveShapeIterator *iter)
{
tl_assert (m_cell_stack.size () == 1);
tl_assert (! iter->layout () || ! iter->top_cell () || m_cell_stack.size () == 1);
m_initial_pass = false;
m_cells_seen.clear ();
mp_initial_cell = m_cell_stack.front ().second;
mp_initial_cell = m_cell_stack.empty () ? 0 : m_cell_stack.front ().second;
m_cell_stack.clear ();
m_cm_entry = cell_map_type::const_iterator ();
m_cm_new_entry = false;

View File

@ -36,6 +36,7 @@ static bool is_deep (const db::Region &r)
}
// the iterator provides the hierarchical selection (enabling/disabling cells etc.)
LayoutToNetlist::LayoutToNetlist (const db::RecursiveShapeIterator &iter)
: m_iter (iter), m_netlist_extracted (false)
{
@ -44,6 +45,17 @@ LayoutToNetlist::LayoutToNetlist (const db::RecursiveShapeIterator &iter)
throw tl::Exception (tl::to_string (tr ("The netlist extractor cannot work on clipped layouts")));
}
init ();
}
LayoutToNetlist::LayoutToNetlist ()
: m_iter (), m_netlist_extracted (false)
{
init ();
}
void LayoutToNetlist::init ()
{
m_dss.set_text_enlargement (1);
m_dss.set_text_property_name (tl::Variant ("LABEL"));
}
@ -83,11 +95,11 @@ db::Region *LayoutToNetlist::make_layer (const std::string &n)
db::RecursiveShapeIterator si (m_iter);
si.shape_flags (db::ShapeIterator::Nothing);
db::Region *region = new db::Region (si, m_dss);
std::auto_ptr <db::Region> region (new db::Region (si, m_dss));
if (! n.empty ()) {
name (*region, n);
register_layer (*region, n);
}
return region;
return region.release ();
}
db::Region *LayoutToNetlist::make_layer (unsigned int layer_index, const std::string &n)
@ -96,11 +108,11 @@ db::Region *LayoutToNetlist::make_layer (unsigned int layer_index, const std::st
si.set_layer (layer_index);
si.shape_flags (db::ShapeIterator::All);
db::Region *region = new db::Region (si, m_dss);
std::auto_ptr <db::Region> region (new db::Region (si, m_dss));
if (! n.empty ()) {
name (*region, n);
register_layer (*region, n);
}
return region;
return region.release ();
}
db::Region *LayoutToNetlist::make_text_layer (unsigned int layer_index, const std::string &n)
@ -109,11 +121,11 @@ db::Region *LayoutToNetlist::make_text_layer (unsigned int layer_index, const st
si.set_layer (layer_index);
si.shape_flags (db::ShapeIterator::Texts);
db::Region *region = new db::Region (si, m_dss);
std::auto_ptr <db::Region> region (new db::Region (si, m_dss));
if (! n.empty ()) {
name (*region, n);
register_layer (*region, n);
}
return region;
return region.release ();
}
db::Region *LayoutToNetlist::make_polygon_layer (unsigned int layer_index, const std::string &n)
@ -122,11 +134,11 @@ db::Region *LayoutToNetlist::make_polygon_layer (unsigned int layer_index, const
si.set_layer (layer_index);
si.shape_flags (db::ShapeIterator::Paths | db::ShapeIterator::Polygons | db::ShapeIterator::Boxes);
db::Region *region = new db::Region (si, m_dss);
std::auto_ptr <db::Region> region (new db::Region (si, m_dss));
if (! n.empty ()) {
name (*region, n);
register_layer (*region, n);
}
return region;
return region.release ();
}
void LayoutToNetlist::extract_devices (db::NetlistDeviceExtractor &extractor, const std::map<std::string, db::Region *> &layers)
@ -148,6 +160,9 @@ void LayoutToNetlist::connect (const db::Region &l)
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);
@ -167,6 +182,12 @@ void LayoutToNetlist::connect (const db::Region &a, const db::Region &b)
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"))));
}
if (! is_persisted (b)) {
throw (tl::Exception (tl::to_string (tr ("Only named layers can be used in inter-layer connectivity (second layer) for netlist extraction"))));
}
// we need to keep a reference, so we can safely delete the region
db::DeepLayer dla (a), dlb (b);
@ -182,7 +203,10 @@ size_t LayoutToNetlist::connect_global (const db::Region &l, const std::string &
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"))));
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
@ -232,6 +256,14 @@ const db::Cell *LayoutToNetlist::internal_top_cell () const
return &m_dss.const_initial_cell ();
}
void LayoutToNetlist::ensure_internal_layout ()
{
if (m_dss.layouts () == 0) {
// the dummy layer acts as a reference holder for the layout
m_dummy_layer = m_dss.create_polygon_layer (db::RecursiveShapeIterator ());
}
}
db::Layout *LayoutToNetlist::internal_layout ()
{
return &m_dss.layout ();
@ -242,13 +274,69 @@ db::Cell *LayoutToNetlist::internal_top_cell ()
return &m_dss.initial_cell ();
}
void LayoutToNetlist::name (const db::Region &region, const std::string &name)
void LayoutToNetlist::register_layer (const db::Region &region, const std::string &n)
{
unsigned int li = layer_of (region);
db::Layout &ly = m_dss.layout ();
db::LayerProperties lp = ly.get_properties (li);
lp.name = name;
ly.set_properties (li, lp);
if (m_named_regions.find (n) != m_named_regions.end ()) {
throw tl::Exception (tl::to_string (tr ("Layer name is already used: ")) + n);
}
db::DeepRegion *delegate = dynamic_cast<db::DeepRegion *> (region.delegate());
if (! delegate) {
throw tl::Exception (tl::to_string (tr ("Layer is not a deep region")));
}
if (is_persisted (region)) {
std::string prev_name = name (region);
m_named_regions.erase (prev_name);
}
m_named_regions [n] = delegate->deep_layer ();
m_name_of_layer [layer_of (region)] = n;
}
std::string LayoutToNetlist::name (const db::Region &region) const
{
std::map<unsigned int, std::string>::const_iterator n = m_name_of_layer.find (layer_of (region));
if (n != m_name_of_layer.end ()) {
return n->second;
} else {
return std::string ();
}
}
std::string LayoutToNetlist::name (unsigned int l) const
{
std::map<unsigned int, std::string>::const_iterator n = m_name_of_layer.find (l);
if (n != m_name_of_layer.end ()) {
return n->second;
} else {
return std::string ();
}
}
bool LayoutToNetlist::is_persisted (const db::Region &region) const
{
return m_name_of_layer.find (layer_of (region)) != m_name_of_layer.end ();
}
db::Region *LayoutToNetlist::layer_by_name (const std::string &name)
{
std::map<std::string, db::DeepLayer>::const_iterator l = m_named_regions.find (name);
if (l == m_named_regions.end ()) {
return 0;
} else {
return new db::Region (new db::DeepRegion (l->second));
}
}
db::Region *LayoutToNetlist::layer_by_index (unsigned int index)
{
std::map<unsigned int, std::string>::const_iterator n = m_name_of_layer.find (index);
if (n == m_name_of_layer.end ()) {
return 0;
} else {
return layer_by_name (n->second);
}
}
unsigned int LayoutToNetlist::layer_of (const db::Region &region) const
@ -433,8 +521,10 @@ LayoutToNetlist::build_net_rec (db::cell_index_type ci, size_t cid, db::Layout &
bool consider_cell = any_connections;
for (std::map<unsigned int, const db::Region *>::const_iterator l = lmap.begin (); l != lmap.end () && !consider_cell; ++l) {
StopOnFirst sof;
consider_cell = deliver_shapes_of_net_nonrecursive (mp_netlist.get (), m_net_clusters, ci, cid, layer_of (*l->second), tr, sof);
if (l->second) {
StopOnFirst sof;
consider_cell = !deliver_shapes_of_net_nonrecursive (mp_netlist.get (), m_net_clusters, ci, cid, layer_of (*l->second), tr, sof);
}
}
if (! consider_cell) {
@ -452,7 +542,9 @@ LayoutToNetlist::build_net_rec (db::cell_index_type ci, size_t cid, db::Layout &
}
for (std::map<unsigned int, const db::Region *>::const_iterator l = lmap.begin (); l != lmap.end (); ++l) {
deliver_shapes_of_net_nonrecursive (mp_netlist.get (), m_net_clusters, ci, cid, layer_of (*l->second), tr, target_cell->shapes (l->first));
if (l->second) {
deliver_shapes_of_net_nonrecursive (mp_netlist.get (), m_net_clusters, ci, cid, layer_of (*l->second), tr, target_cell->shapes (l->first));
}
}
if (! circuit_cell_name_prefix && ! device_cell_name_prefix) {

View File

@ -73,6 +73,8 @@ class DB_PUBLIC LayoutToNetlist
: public gsi::ObjectBase, public tl::Object
{
public:
typedef std::map<unsigned int, std::string>::const_iterator layer_iterator;
/**
* @brief The constructor
*
@ -80,6 +82,11 @@ public:
*/
LayoutToNetlist (const db::RecursiveShapeIterator &iter);
/**
* @brief The default constructor
*/
LayoutToNetlist ();
/**
* @brief Sets the number of threads to use for operations which support multiple threads
*/
@ -115,28 +122,74 @@ public:
size_t max_vertex_count () const;
/**
* @brief Names a layer
* @brief Register a layer under the given name
* This is a formal name for the layer. Using a name or layer properties
* (see below) enhances readability of backannotated information
* if layers are involved. Use this method or the other variants to
* attach a name or standard layer properties to a region delivered
* by "make_layer" or derived from other regions through boolean
* operations.
* if layers are involved. Use this method to attach a name to a region
* derived by boolean operations for example.
* Named regions are persisted inside the LayoutToNetlist object. Only
* named regions can be put into "connect".
*/
void name (const db::Region &region, const std::string &name);
void register_layer (const db::Region &region, const std::string &name);
/**
* @brief Gets the name of the given layer
* @brief Gets the name of the given region
* Returns an empty string if the region does not have a name.
*/
std::string name (const db::Region &region) const
std::string name (const db::Region &region) const;
/**
* @brief Gets the name of the given layer by index
* Returns an empty string if the layer does not have a name.
*/
std::string name (unsigned int) const;
/**
* @brief Returns true, if the region is a persisted region
* Persisted regions have a name and are kept inside the LayoutToNetlist
* object.
*/
bool is_persisted (const db::Region &region) const;
/**
* @brief Gets the region (layer) with the given name
* If the name is not valid, this method returns 0. Otherwise it
* will return a new'd Region object referencing the layer with
* the given name. It must be deleted by the caller.
*/
db::Region *layer_by_name (const std::string &name);
/**
* @brief Gets the region (layer) by index
* If the index is not valid, this method returns 0. Otherwise it
* will return a new'd Region object referencing the layer with
* the given name. It must be deleted by the caller.
* Only named layers are managed by LayoutToNetlist and can
* be retrieved with this method.
*/
db::Region *layer_by_index (unsigned int index);
/**
* @brief Iterates over the layer indexes and names managed by this object (begin)
*/
layer_iterator begin_layers () const
{
return internal_layout ()->get_properties (layer_of (region)).name;
return m_name_of_layer.begin ();
}
/**
* @brief Iterates over the layer indexes and names managed by this object (end)
*/
layer_iterator end_layers () const
{
return m_name_of_layer.end ();
}
/**
* @brief Creates a new empty region
* This method returns a new'd object which must be deleted by the caller.
*/
db::Region *make_layer (const std::string &n);
db::Region *make_layer (const std::string &name = std::string ());
/**
* @brief Creates a new region representing an original layer
@ -144,6 +197,11 @@ public:
* This variant produces polygons and takes texts for net name annotation.
* A variant not taking texts is "make_polygon_layer". A Variant only taking
* texts is "make_text_layer".
* All variants return a new'd object which must be deleted by the caller.
* Named regions are considered "precious". The LayoutToNetlist object will
* keep a reference on all named layers, so they persist during the lifetime
* of the LayoutToNetlist object.
* Only named layers can be used for connect (see below).
*/
db::Region *make_layer (unsigned int layer_index, const std::string &name = std::string ());
@ -179,18 +237,21 @@ public:
* a derived layer. Certain limitations apply. It's safe to use
* boolean operations for deriving layers. Other operations are applicable as long as they are
* capable of delivering hierarchical layers.
* Regions put into "connect" need to be named.
*/
void connect (const db::Region &l);
/**
* @brief Defines an inter-layer connection for the given layers.
* The conditions mentioned with intra-layer "connect" apply for this method too.
* Regions put into "connect" need to be named.
*/
void connect (const db::Region &a, const db::Region &b);
/**
* @brief Connects the given layer with a global net with the given name
* Returns the global net ID
* Regions put into "connect" need to be named.
*/
size_t connect_global (const db::Region &l, const std::string &gn);
@ -237,6 +298,11 @@ public:
*/
db::Cell *internal_top_cell ();
/**
* @brief Ensures the internal layout is made
*/
void ensure_internal_layout ();
/**
* @brief Gets the connectivity object
*/
@ -406,8 +472,12 @@ private:
db::hier_clusters<db::PolygonRef> m_net_clusters;
std::auto_ptr<db::Netlist> mp_netlist;
std::set<db::DeepLayer> m_dlrefs;
std::map<std::string, db::DeepLayer> m_named_regions;
std::map<unsigned int, std::string> m_name_of_layer;
bool m_netlist_extracted;
db::DeepLayer m_dummy_layer;
void init ();
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;

View File

@ -29,46 +29,6 @@ namespace db
namespace l2n_std_reader {
class Layers
{
public:
Layers () { }
~Layers ()
{
for (std::map<std::string, db::Region *>::const_iterator i = m_layers.begin (); i != m_layers.end (); ++i) {
delete i->second;
}
m_layers.clear ();
}
void add (const std::string &name, db::Region *region)
{
if (m_layers.find (name) != m_layers.end ()) {
delete region;
throw tl::Exception (tl::to_string (tr ("Duplicate layer name: ")) + name);
}
m_layers.insert (std::make_pair (name, region));
}
bool has_layer (const std::string &name) const
{
return m_layers.find (name) != m_layers.end ();
}
db::Region &layer (const std::string &name)
{
std::map<std::string, db::Region *>::const_iterator l = m_layers.find (name);
if (l == m_layers.end ()) {
throw tl::Exception (tl::to_string (tr ("Not a valid layer name: ")) + name);
}
return *l->second;
}
private:
std::map<std::string, db::Region *> m_layers;
};
class Brace
{
public:
@ -185,9 +145,13 @@ void LayoutToNetlistStandardReader::read (db::LayoutToNetlist *l2n)
}
}
const db::Region *LayoutToNetlistStandardReader::layer_by_name (const std::string &name)
static db::Region &layer_by_name (db::LayoutToNetlist *l2n, const std::string &name)
{
return mp_layers->has_layer (name) ? &mp_layers->layer (name) : 0;
db::Region *l = l2n->layer_by_name (name);
if (! l) {
throw tl::Exception (tl::to_string (tr ("Not a valid layer name: ")) + name);
}
return *l;
}
void LayoutToNetlistStandardReader::do_read (db::LayoutToNetlist *l2n)
@ -196,13 +160,17 @@ void LayoutToNetlistStandardReader::do_read (db::LayoutToNetlist *l2n)
std::string description;
// TODO: there probably is a more efficient way to force the layout inside l2n to be made
l2n->make_layer (std::string ());
l2n->ensure_internal_layout ();
tl_assert (l2n->internal_layout ());
l2n->internal_layout ()->dbu (1.0); // mainly for testing
if (l2n->internal_layout ()->cells () == 0) {
l2n->internal_layout ()->add_cell ("TOP");
}
tl_assert (l2n->internal_top_cell () != 0);
l2n->make_netlist ();
mp_layers.reset (new Layers ());
while (! at_end ()) {
if (test (skeys::version_key) || test (lkeys::version_key)) {
@ -237,7 +205,7 @@ void LayoutToNetlistStandardReader::do_read (db::LayoutToNetlist *l2n)
Brace br (this);
std::string layer;
read_word_or_quoted (layer);
mp_layers->add (layer, l2n->make_layer (layer));
delete l2n->make_layer (layer);
br.done ();
} else if (test (skeys::connect_key) || test (lkeys::connect_key)) {
@ -248,7 +216,7 @@ void LayoutToNetlistStandardReader::do_read (db::LayoutToNetlist *l2n)
while (br) {
std::string l2;
read_word_or_quoted (l2);
l2n->connect (mp_layers->layer (l1), mp_layers->layer (l2));
l2n->connect (layer_by_name (l2n, l1), layer_by_name (l2n, l2));
}
br.done ();
@ -260,7 +228,7 @@ void LayoutToNetlistStandardReader::do_read (db::LayoutToNetlist *l2n)
while (br) {
std::string g;
read_word_or_quoted (g);
l2n->connect_global (mp_layers->layer (l1), g);
l2n->connect_global (layer_by_name (l2n, l1), g);
}
br.done ();
@ -377,7 +345,7 @@ LayoutToNetlistStandardReader::read_geometry (db::LayoutToNetlist *l2n)
Brace br (this);
read_word_or_quoted (lname);
unsigned int lid = l2n->layer_of (mp_layers->layer (lname));
unsigned int lid = l2n->layer_of (layer_by_name (l2n, lname));
db::Coord l = read_coord ();
db::Coord b = read_coord ();
@ -394,7 +362,7 @@ LayoutToNetlistStandardReader::read_geometry (db::LayoutToNetlist *l2n)
Brace br (this);
read_word_or_quoted (lname);
unsigned int lid = l2n->layer_of (mp_layers->layer (lname));
unsigned int lid = l2n->layer_of (layer_by_name (l2n, lname));
std::vector<db::Point> pt;

View File

@ -65,8 +65,6 @@ public:
void read (db::LayoutToNetlist *l2n);
const db::Region *layer_by_name (const std::string &name);
private:
friend class l2n_std_reader::Brace;
typedef l2n_std_reader::Brace Brace;
@ -85,7 +83,6 @@ private:
std::string m_path;
std::string m_line;
tl::Extractor m_ex;
std::auto_ptr<Layers> mp_layers;
void do_read (db::LayoutToNetlist *l2n);

View File

@ -63,14 +63,13 @@ std_writer_impl<Keys>::std_writer_impl (tl::OutputStream &stream)
// .. nothing yet ..
}
static std::string name_for_layer (const db::Layout *layout, unsigned int l)
static std::string name_for_layer (const db::LayoutToNetlist *l2n, unsigned int l)
{
const db::LayerProperties &lp = layout->get_properties (l);
if (lp.is_named ()) {
return tl::to_word_or_quoted_string (lp.name);
} else {
return "L" + tl::to_string (l);
std::string n = l2n->name (l);
if (n.empty ()) {
n = "L" + tl::to_string (l);
}
return n;
}
template <class Keys>
@ -104,7 +103,7 @@ void std_writer_impl<Keys>::write (const db::LayoutToNetlist *l2n)
*mp_stream << endl << "# Mask layers" << endl;
}
for (db::Connectivity::layer_iterator l = l2n->connectivity ().begin_layers (); l != l2n->connectivity ().end_layers (); ++l) {
*mp_stream << Keys::layer_key << "(" << name_for_layer (ly, *l) << ")" << endl;
*mp_stream << Keys::layer_key << "(" << name_for_layer (l2n, *l) << ")" << endl;
}
if (! Keys::is_short ()) {
@ -115,9 +114,9 @@ void std_writer_impl<Keys>::write (const db::LayoutToNetlist *l2n)
db::Connectivity::layer_iterator ce = l2n->connectivity ().end_connected (*l);
db::Connectivity::layer_iterator cb = l2n->connectivity ().begin_connected (*l);
if (cb != ce) {
*mp_stream << Keys::connect_key << "(" << name_for_layer (ly, *l);
*mp_stream << Keys::connect_key << "(" << name_for_layer (l2n, *l);
for (db::Connectivity::layer_iterator c = l2n->connectivity ().begin_connected (*l); c != ce; ++c) {
*mp_stream << " " << name_for_layer (ly, *c);
*mp_stream << " " << name_for_layer (l2n, *c);
}
*mp_stream << ")" << endl;
}
@ -136,7 +135,7 @@ void std_writer_impl<Keys>::write (const db::LayoutToNetlist *l2n)
}
any = true;
}
*mp_stream << Keys::global_key << "(" << name_for_layer (ly, *l);
*mp_stream << Keys::global_key << "(" << name_for_layer (l2n, *l);
for (db::Connectivity::global_nets_iterator g = gb; g != ge; ++g) {
*mp_stream << " " << tl::to_word_or_quoted_string (l2n->connectivity ().global_net_name (*g));
}
@ -260,7 +259,6 @@ void std_writer_impl<Keys>::write (const db::LayoutToNetlist *l2n, const db::Net
throw tl::Exception (tl::to_string (tr ("Can't write annotated netlist before extraction has been done")));
}
const db::Layout *ly = l2n->internal_layout ();
const db::hier_clusters<db::PolygonRef> &clusters = l2n->net_clusters ();
const db::Circuit *circuit = net.circuit ();
const db::Connectivity &conn = l2n->connectivity ();
@ -290,7 +288,7 @@ void std_writer_impl<Keys>::write (const db::LayoutToNetlist *l2n, const db::Net
}
*mp_stream << indent2;
write (si.operator-> (), si.trans (), name_for_layer (ly, *l));
write (si.operator-> (), si.trans (), name_for_layer (l2n, *l));
*mp_stream << endl;
prev_ci = ci;
@ -365,7 +363,6 @@ void std_writer_impl<Keys>::write (const db::LayoutToNetlist *l2n, const db::Dev
{
const std::vector<db::DeviceTerminalDefinition> &td = device_model.device_class ()->terminal_definitions ();
const db::Layout *ly = l2n->internal_layout ();
const db::hier_clusters<db::PolygonRef> &clusters = l2n->net_clusters ();
const db::Connectivity &conn = l2n->connectivity ();
@ -379,7 +376,7 @@ void std_writer_impl<Keys>::write (const db::LayoutToNetlist *l2n, const db::Dev
for (db::local_cluster<db::PolygonRef>::shape_iterator s = lc.begin (*l); ! s.at_end (); ++s) {
*mp_stream << indent2;
write (s.operator-> (), db::ICplxTrans (), name_for_layer (ly, *l));
write (s.operator-> (), db::ICplxTrans (), name_for_layer (l2n, *l));
*mp_stream << endl;
}

View File

@ -502,12 +502,36 @@ public:
Region &operator= (const Region &other);
/**
* @brief Constructor from an object
*
* Creates a region representing a single instance of that object
* @brief Constructor from a box
*/
template <class Sh>
Region (const Sh &s)
explicit Region (const db::Box &s)
: mp_delegate (0)
{
insert (s);
}
/**
* @brief Constructor from a polygon
*/
explicit Region (const db::Polygon &s)
: mp_delegate (0)
{
insert (s);
}
/**
* @brief Constructor from a simple polygon
*/
explicit Region (const db::SimplePolygon &s)
: mp_delegate (0)
{
insert (s);
}
/**
* @brief Constructor from a path
*/
explicit Region (const db::Path &s)
: mp_delegate (0)
{
insert (s);
@ -521,7 +545,7 @@ public:
* style.
*/
template <class Iter>
Region (const Iter &b, const Iter &e)
explicit Region (const Iter &b, const Iter &e)
: mp_delegate (0)
{
reserve (e - b);
@ -536,7 +560,7 @@ public:
* Creates a region from a recursive shape iterator. This allows feeding a region
* from a hierarchy of cells.
*/
Region (const RecursiveShapeIterator &si);
explicit Region (const RecursiveShapeIterator &si);
/**
* @brief Constructor from a RecursiveShapeIterator with a transformation
@ -545,7 +569,7 @@ public:
* from a hierarchy of cells. The transformation is useful to scale to a specific
* DBU for example.
*/
Region (const RecursiveShapeIterator &si, const db::ICplxTrans &trans, bool merged_semantics = true);
explicit Region (const RecursiveShapeIterator &si, const db::ICplxTrans &trans, bool merged_semantics = true);
/**
* @brief Constructor from a RecursiveShapeIterator providing a deep representation
@ -556,12 +580,12 @@ public:
* "area_ratio" and "max_vertex_count" are optimization parameters for the
* shape splitting algorithm.
*/
Region (const RecursiveShapeIterator &si, DeepShapeStore &dss, double area_ratio = 3.0, size_t max_vertex_count = 16);
explicit Region (const RecursiveShapeIterator &si, DeepShapeStore &dss, double area_ratio = 3.0, size_t max_vertex_count = 16);
/**
* @brief Constructor from a RecursiveShapeIterator providing a deep representation with transformation
*/
Region (const RecursiveShapeIterator &si, DeepShapeStore &dss, const db::ICplxTrans &trans, bool merged_semantics = true, double area_ratio = 3.0, size_t max_vertex_count = 16);
explicit Region (const RecursiveShapeIterator &si, DeepShapeStore &dss, const db::ICplxTrans &trans, bool merged_semantics = true, double area_ratio = 3.0, size_t max_vertex_count = 16);
/**
* @brief Gets the underlying delegate object

View File

@ -23,6 +23,7 @@
#include "gsiDecl.h"
#include "dbLayoutToNetlist.h"
#include "dbLayoutToNetlistWriter.h"
#include "dbLayoutToNetlistReader.h"
#include "tlStream.h"
namespace gsi
@ -33,6 +34,11 @@ static db::LayoutToNetlist *make_l2n (const db::RecursiveShapeIterator &iter)
return new db::LayoutToNetlist (iter);
}
static db::LayoutToNetlist *make_l2n_default ()
{
return new db::LayoutToNetlist ();
}
static db::Layout *l2n_internal_layout (db::LayoutToNetlist *l2n)
{
// although this isn't very clean, we dare to do so as const references are pretty useless in script languages.
@ -67,10 +73,31 @@ static void write_l2n (const db::LayoutToNetlist *l2n, const std::string &path,
writer.write (l2n);
}
static void read_l2n (db::LayoutToNetlist *l2n, const std::string &path)
{
tl::InputStream stream (path);
db::LayoutToNetlistStandardReader reader (stream);
reader.read (l2n);
}
static std::vector<std::string> l2n_layer_names (const db::LayoutToNetlist *l2n)
{
std::vector<std::string> ln;
for (db::LayoutToNetlist::layer_iterator l = l2n->begin_layers (); l != l2n->end_layers (); ++l) {
ln.push_back (l->second);
}
return ln;
}
Class<db::LayoutToNetlist> decl_dbLayoutToNetlist ("db", "LayoutToNetlist",
gsi::constructor ("new", &make_l2n, gsi::arg ("iter"),
"@brief The constructor\n"
"See the class description for details.\n"
"@brief Creates a new extractor connected to an original layout\n"
"This constructor will attach the extractor to an original layout through the "
"shape iterator.\n"
) +
gsi::constructor ("new", &make_l2n_default,
"@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::method ("threads=", &db::LayoutToNetlist::set_threads, gsi::arg ("n"),
"@brief Sets the number of threads to use for operations which support multiple threads\n"
@ -95,34 +122,65 @@ Class<db::LayoutToNetlist> decl_dbLayoutToNetlist ("db", "LayoutToNetlist",
gsi::method ("max_vertex_count", &db::LayoutToNetlist::max_vertex_count,
"See \\max_vertex_count= for details about this attribute."
) +
gsi::method ("name", &db::LayoutToNetlist::name, gsi::arg ("l"),
gsi::method ("name", (std::string (db::LayoutToNetlist::*) (const db::Region &region) const) &db::LayoutToNetlist::name, gsi::arg ("l"),
"@brief Get the name of the given layer\n"
) +
gsi::method ("name", (std::string (db::LayoutToNetlist::*) (unsigned int) const) &db::LayoutToNetlist::name, gsi::arg ("l"),
"@brief Get the name of the given layer (by index)\n"
) +
gsi::method ("register", (void (db::LayoutToNetlist::*) (const db::Region &region, const std::string &)) &db::LayoutToNetlist::register_layer, gsi::arg ("l"), gsi::arg ("n"),
"@brief Names the given layer\n"
"'l' must be a hierarchical region derived with \\make_layer, \\make_text_layer or \\make_polygon_layer or "
"a region derived from those by boolean operations or other hierarchical operations.\n"
"\n"
"Naming a layer allows the system to indicate the layer in various contexts, i.e. "
"when writing the data to a file.\n"
"when writing the data to a file. Named layers are also persisted inside the LayoutToNetlist object. "
"They are not discarded when the Region object is destroyed. Only named layers can be put into "
"\\connect.\n"
) +
gsi::method ("make_layer", &db::LayoutToNetlist::make_layer, gsi::arg ("layer_index"), gsi::arg ("name", std::string ()),
gsi::method_ext ("layer_names", &l2n_layer_names,
"@brief Returns a list of names of the layer kept inside the LayoutToNetlist object."
) +
gsi::factory ("layer_by_name", &db::LayoutToNetlist::layer_by_name, gsi::arg ("name"),
"@brief Gets a layer object for the given name.\n"
"The returned object is a copy which represents the named layer."
) +
gsi::factory ("layer_by_index", &db::LayoutToNetlist::layer_by_index, gsi::arg ("index"),
"@brief Gets a layer object for the given index.\n"
"Only named layers can be retrieved with this method. "
"The returned object is a copy which represents the named layer."
) +
gsi::method ("is_persisted?", &db::LayoutToNetlist::is_persisted, gsi::arg ("layer"),
"@brief Returns true, if the given layer is a persisted region.\n"
"Persisted layers are kept inside the LayoutToNetlist object and are not released "
"if their object is destroyed. Named layers are persisted, unnamed layers are not. "
"Only persisted, named layers can be put into \\connect."
) +
gsi::factory ("make_layer", (db::Region *(db::LayoutToNetlist::*) (const std::string &)) &db::LayoutToNetlist::make_layer, gsi::arg ("name", std::string ()),
"@brief Creates a new, empty hierarchical region\n"
"\n"
"The name is optional. If given, the layer will already be named accordingly (see \\register).\n"
) +
gsi::factory ("make_layer", (db::Region *(db::LayoutToNetlist::*) (unsigned int, const std::string &)) &db::LayoutToNetlist::make_layer, gsi::arg ("layer_index"), gsi::arg ("name", std::string ()),
"@brief Creates a new hierarchical region representing an original layer\n"
"'layer_index' is the layer index of the desired layer in the original layout.\n"
"This variant produces polygons and takes texts for net name annotation.\n"
"A variant not taking texts is \\make_polygon_layer. A Variant only taking\n"
"texts is \\make_text_layer.\n"
"\n"
"The name is optional. If given, the layer will already be named accordingly (see \\name).\n"
"The name is optional. If given, the layer will already be named accordingly (see \\register).\n"
) +
gsi::method ("make_text_layer", &db::LayoutToNetlist::make_text_layer, gsi::arg ("layer_index"), gsi::arg ("name", std::string ()),
gsi::factory ("make_text_layer", &db::LayoutToNetlist::make_text_layer, gsi::arg ("layer_index"), gsi::arg ("name", std::string ()),
"@brief Creates a new region representing an original layer taking texts only\n"
"See \\make_layer for details.\n"
"\n"
"The name is optional. If given, the layer will already be named accordingly (see \\name).\n"
"The name is optional. If given, the layer will already be named accordingly (see \\register).\n"
) +
gsi::method ("make_polygon_layer", &db::LayoutToNetlist::make_polygon_layer, gsi::arg ("layer_index"), gsi::arg ("name", std::string ()),
gsi::factory ("make_polygon_layer", &db::LayoutToNetlist::make_polygon_layer, gsi::arg ("layer_index"), gsi::arg ("name", std::string ()),
"@brief Creates a new region representing an original layer taking polygons and texts\n"
"See \\make_layer for details.\n"
"\n"
"The name is optional. If given, the layer will already be named accordingly (see \\name).\n"
"The name is optional. If given, the layer will already be named accordingly (see \\register).\n"
) +
gsi::method ("extract_devices", &db::LayoutToNetlist::extract_devices, gsi::arg ("extractor"), gsi::arg ("layers"),
"@brief Extracts devices\n"
@ -280,6 +338,10 @@ Class<db::LayoutToNetlist> decl_dbLayoutToNetlist ("db", "LayoutToNetlist",
gsi::method_ext ("write", &write_l2n, gsi::arg ("path"), gsi::arg ("short_format", false),
"@brief Writes the extracted netlist to a file.\n"
"This method employs the native format of KLayout.\n"
) +
gsi::method_ext ("read", &read_l2n, gsi::arg ("path"),
"@brief Reads the extracted netlist from the file.\n"
"This method employs the native format of KLayout.\n"
),
"@brief A generic framework for extracting netlists from layouts\n"
"\n"

View File

@ -59,6 +59,41 @@ TEST(1)
db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/hierarchy_builder_au1.gds");
}
TEST(1_WithEmptyLayer)
{
db::Layout ly;
{
std::string fn (tl::testsrc ());
fn += "/testdata/algo/hierarchy_builder_l1.gds";
tl::InputStream stream (fn);
db::Reader reader (stream);
reader.read (ly);
}
db::cell_index_type top_cell_index = *ly.begin_top_down ();
db::Layout target;
db::HierarchyBuilder builder (&target);
db::RecursiveShapeIterator iter (ly, ly.cell (top_cell_index), std::set<unsigned int> ());
iter.push (&builder);
for (db::Layout::layer_iterator li = ly.begin_layers (); li != ly.end_layers (); ++li) {
unsigned int li1 = (*li).first;
unsigned int target_layer = target.insert_layer (*(*li).second);
builder.set_target_layer (target_layer);
db::RecursiveShapeIterator iter (ly, ly.cell (top_cell_index), li1);
iter.push (&builder);
}
CHECKPOINT();
db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/hierarchy_builder_au1.gds");
}
TEST(2_WithoutClip)
{
db::Layout ly;
@ -251,6 +286,56 @@ TEST(2_WithEmptyResult)
db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/hierarchy_builder_au2e.gds");
}
TEST(2_WithClipAndSimplificationAndEmptyLayer)
{
db::Layout ly;
{
std::string fn (tl::testsrc ());
fn += "/testdata/algo/hierarchy_builder_l1.gds";
tl::InputStream stream (fn);
db::Reader reader (stream);
reader.read (ly);
}
db::Layout target;
db::ReducingHierarchyBuilderShapeReceiver red(0, 1.2, 4);
db::ClippingHierarchyBuilderShapeReceiver clip(&red);
db::HierarchyBuilder builder (&target, &clip);
db::cell_index_type target_top = target.add_cell ("CLIP_TOP");
db::Box clip_box (5000, -2000, 18500, 6000);
builder.set_target_layer (target.insert_layer (db::LayerProperties (100, 0)));
db::cell_index_type top_cell_index = *ly.begin_top_down ();
db::RecursiveShapeIterator iter (ly, ly.cell (top_cell_index), std::set<unsigned int> (), clip_box);
iter.push (&builder);
target.cell (target_top).insert (db::CellInstArray (db::CellInst (builder.initial_cell ()->cell_index ()), db::Trans ()));
for (db::Layout::layer_iterator li = ly.begin_layers (); li != ly.end_layers (); ++li) {
builder.reset ();
unsigned int li1 = (*li).first;
unsigned int target_layer = target.insert_layer (*(*li).second);
builder.set_target_layer (target_layer);
db::cell_index_type top_cell_index = *ly.begin_top_down ();
db::RecursiveShapeIterator iter (ly, ly.cell (top_cell_index), li1, clip_box);
iter.push (&builder);
target.cell (target_top).insert (db::CellInstArray (db::CellInst (builder.initial_cell ()->cell_index ()), db::Trans ()));
}
CHECKPOINT();
db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/hierarchy_builder_au2f.gds");
}
TEST(3_ComplexRegionWithClip)
{
db::Layout ly;

View File

@ -34,10 +34,7 @@
TEST(1_ReaderBasic)
{
db::Layout ly;
db::Cell &tc = ly.cell (ly.add_cell ("TOP"));
db::LayoutToNetlist l2n (db::RecursiveShapeIterator (ly, tc, std::set<unsigned int> ()));
db::LayoutToNetlist l2n;
std::string in_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "l2n_writer_au.txt");
tl::InputStream is_in (in_path);
@ -69,20 +66,20 @@ TEST(1_ReaderBasic)
{
db::Layout ly2;
ly2.dbu (ly.dbu ());
ly2.dbu (l2n.internal_layout ()->dbu ());
db::Cell &top2 = ly2.cell (ly2.add_cell ("TOP"));
db::CellMapping cm = l2n.cell_mapping_into (ly2, top2, true /*with device cells*/);
std::map<unsigned int, const db::Region *> lmap;
lmap [ly2.insert_layer (db::LayerProperties (10, 0))] = reader.layer_by_name ("psd");
lmap [ly2.insert_layer (db::LayerProperties (11, 0))] = reader.layer_by_name ("nsd");
lmap [ly2.insert_layer (db::LayerProperties (3, 0)) ] = reader.layer_by_name ("poly");
lmap [ly2.insert_layer (db::LayerProperties (4, 0)) ] = reader.layer_by_name ("diff_cont");
lmap [ly2.insert_layer (db::LayerProperties (5, 0)) ] = reader.layer_by_name ("poly_cont");
lmap [ly2.insert_layer (db::LayerProperties (6, 0)) ] = reader.layer_by_name ("metal1");
lmap [ly2.insert_layer (db::LayerProperties (7, 0)) ] = reader.layer_by_name ("via1");
lmap [ly2.insert_layer (db::LayerProperties (8, 0)) ] = reader.layer_by_name ("metal2");
lmap [ly2.insert_layer (db::LayerProperties (10, 0))] = l2n.layer_by_name ("psd");
lmap [ly2.insert_layer (db::LayerProperties (11, 0))] = l2n.layer_by_name ("nsd");
lmap [ly2.insert_layer (db::LayerProperties (3, 0)) ] = l2n.layer_by_name ("poly");
lmap [ly2.insert_layer (db::LayerProperties (4, 0)) ] = l2n.layer_by_name ("diff_cont");
lmap [ly2.insert_layer (db::LayerProperties (5, 0)) ] = l2n.layer_by_name ("poly_cont");
lmap [ly2.insert_layer (db::LayerProperties (6, 0)) ] = l2n.layer_by_name ("metal1");
lmap [ly2.insert_layer (db::LayerProperties (7, 0)) ] = l2n.layer_by_name ("via1");
lmap [ly2.insert_layer (db::LayerProperties (8, 0)) ] = l2n.layer_by_name ("metal2");
l2n.build_all_nets (cm, ly2, lmap, "NET_", 0, "DEVICE_");
@ -97,10 +94,7 @@ TEST(1_ReaderBasic)
TEST(1b_ReaderBasicShort)
{
db::Layout ly;
db::Cell &tc = ly.cell (ly.add_cell ("TOP"));
db::LayoutToNetlist l2n (db::RecursiveShapeIterator (ly, tc, std::set<unsigned int> ()));
db::LayoutToNetlist l2n;
std::string in_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "l2n_writer_au_s.txt");
tl::InputStream is_in (in_path);
@ -132,10 +126,7 @@ TEST(1b_ReaderBasicShort)
TEST(2_ReaderWithGlobalNets)
{
db::Layout ly;
db::Cell &tc = ly.cell (ly.add_cell ("TOP"));
db::LayoutToNetlist l2n (db::RecursiveShapeIterator (ly, tc, std::set<unsigned int> ()));
db::LayoutToNetlist l2n;
std::string in_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "l2n_writer_au_2.txt");
tl::InputStream is_in (in_path);
@ -167,24 +158,24 @@ TEST(2_ReaderWithGlobalNets)
{
db::Layout ly2;
ly2.dbu (ly.dbu ());
ly2.dbu (l2n.internal_layout ()->dbu ());
db::Cell &top2 = ly2.cell (ly2.add_cell ("TOP"));
db::CellMapping cm = l2n.cell_mapping_into (ly2, top2, true /*with device cells*/);
std::map<unsigned int, const db::Region *> lmap;
lmap [ly2.insert_layer (db::LayerProperties (10, 0))] = reader.layer_by_name ("psd");
lmap [ly2.insert_layer (db::LayerProperties (11, 0))] = reader.layer_by_name ("nsd");
lmap [ly2.insert_layer (db::LayerProperties (12, 0))] = reader.layer_by_name ("rbulk");
lmap [ly2.insert_layer (db::LayerProperties (13, 0))] = reader.layer_by_name ("ptie");
lmap [ly2.insert_layer (db::LayerProperties (14, 0))] = reader.layer_by_name ("ntie");
lmap [ly2.insert_layer (db::LayerProperties (1, 0)) ] = reader.layer_by_name ("nwell");
lmap [ly2.insert_layer (db::LayerProperties (3, 0)) ] = reader.layer_by_name ("poly");
lmap [ly2.insert_layer (db::LayerProperties (4, 0)) ] = reader.layer_by_name ("diff_cont");
lmap [ly2.insert_layer (db::LayerProperties (5, 0)) ] = reader.layer_by_name ("poly_cont");
lmap [ly2.insert_layer (db::LayerProperties (6, 0)) ] = reader.layer_by_name ("metal1");
lmap [ly2.insert_layer (db::LayerProperties (7, 0)) ] = reader.layer_by_name ("via1");
lmap [ly2.insert_layer (db::LayerProperties (8, 0)) ] = reader.layer_by_name ("metal2");
lmap [ly2.insert_layer (db::LayerProperties (10, 0))] = l2n.layer_by_name ("psd");
lmap [ly2.insert_layer (db::LayerProperties (11, 0))] = l2n.layer_by_name ("nsd");
lmap [ly2.insert_layer (db::LayerProperties (12, 0))] = l2n.layer_by_name ("rbulk");
lmap [ly2.insert_layer (db::LayerProperties (13, 0))] = l2n.layer_by_name ("ptie");
lmap [ly2.insert_layer (db::LayerProperties (14, 0))] = l2n.layer_by_name ("ntie");
lmap [ly2.insert_layer (db::LayerProperties (1, 0)) ] = l2n.layer_by_name ("nwell");
lmap [ly2.insert_layer (db::LayerProperties (3, 0)) ] = l2n.layer_by_name ("poly");
lmap [ly2.insert_layer (db::LayerProperties (4, 0)) ] = l2n.layer_by_name ("diff_cont");
lmap [ly2.insert_layer (db::LayerProperties (5, 0)) ] = l2n.layer_by_name ("poly_cont");
lmap [ly2.insert_layer (db::LayerProperties (6, 0)) ] = l2n.layer_by_name ("metal1");
lmap [ly2.insert_layer (db::LayerProperties (7, 0)) ] = l2n.layer_by_name ("via1");
lmap [ly2.insert_layer (db::LayerProperties (8, 0)) ] = l2n.layer_by_name ("metal2");
l2n.build_all_nets (cm, ly2, lmap, "NET_", "CIRCUIT_", "DEVICE_");

View File

@ -122,7 +122,52 @@ static unsigned int define_layer (db::Layout &ly, db::LayerMap &lmap, int gds_la
return lid;
}
TEST(1_Basic)
TEST(0_Basic)
{
db::LayoutToNetlist l2n;
std::auto_ptr<db::Region> reg (l2n.make_layer ("l1"));
EXPECT_EQ (l2n.is_persisted (*reg), true);
EXPECT_EQ (l2n.name (*reg), "l1");
EXPECT_EQ (l2n.layer_of (*reg), 0u);
EXPECT_EQ (l2n.internal_layout ()->is_valid_layer (0), true);
reg.reset (0);
EXPECT_EQ (l2n.internal_layout ()->is_valid_layer (0), true);
EXPECT_EQ (l2n.name (0u), "l1");
EXPECT_EQ (l2n.layer_by_index (1) == 0, true);
EXPECT_EQ (l2n.layer_by_name ("l2") == 0, true);
std::auto_ptr<db::Region> reg_copy (l2n.layer_by_name ("l1"));
EXPECT_EQ (reg_copy.get () != 0, true);
EXPECT_EQ (l2n.name (*reg_copy), "l1");
EXPECT_EQ (l2n.layer_of (*reg_copy), 0u);
reg_copy.reset (l2n.layer_by_index (0));
EXPECT_EQ (reg_copy.get () != 0, true);
EXPECT_EQ (l2n.name (*reg_copy), "l1");
EXPECT_EQ (l2n.layer_of (*reg_copy), 0u);
reg_copy.reset (0);
std::auto_ptr<db::Region> reg2 (l2n.make_layer ());
EXPECT_EQ (l2n.name (1u), "");
EXPECT_EQ (l2n.name (*reg2), "");
EXPECT_EQ (l2n.layer_of (*reg2), 1u);
EXPECT_EQ (l2n.internal_layout ()->is_valid_layer (1), true);
reg2.reset (0);
EXPECT_EQ (l2n.internal_layout ()->is_valid_layer (1), false);
std::auto_ptr<db::Region> reg3 (l2n.make_layer ("l3"));
EXPECT_EQ (l2n.name (*reg3), "l3");
EXPECT_EQ (l2n.layer_of (*reg3), 1u);
std::string s;
for (db::LayoutToNetlist::layer_iterator l = l2n.begin_layers (); l != l2n.end_layers (); ++l) {
s += tl::to_string (l->first) + ":" + l->second + ";";
}
EXPECT_EQ (s, "0:l1;1:l3;");
}
TEST(1_BasicExtraction)
{
db::Layout ly;
db::LayerMap lmap;
@ -157,17 +202,17 @@ TEST(1_Basic)
db::Cell &tc = ly.cell (*ly.begin_top_down ());
db::LayoutToNetlist l2n (db::RecursiveShapeIterator (ly, tc, std::set<unsigned int> ()));
std::auto_ptr<db::Region> rnwell (l2n.make_layer (nwell));
std::auto_ptr<db::Region> ractive (l2n.make_layer (active));
std::auto_ptr<db::Region> rpoly (l2n.make_polygon_layer (poly));
std::auto_ptr<db::Region> rpoly_lbl (l2n.make_text_layer (poly_lbl));
std::auto_ptr<db::Region> rdiff_cont (l2n.make_polygon_layer (diff_cont));
std::auto_ptr<db::Region> rpoly_cont (l2n.make_polygon_layer (poly_cont));
std::auto_ptr<db::Region> rmetal1 (l2n.make_polygon_layer (metal1));
std::auto_ptr<db::Region> rmetal1_lbl (l2n.make_text_layer (metal1_lbl));
std::auto_ptr<db::Region> rvia1 (l2n.make_polygon_layer (via1));
std::auto_ptr<db::Region> rmetal2 (l2n.make_polygon_layer (metal2));
std::auto_ptr<db::Region> rmetal2_lbl (l2n.make_text_layer (metal2_lbl));
std::auto_ptr<db::Region> rnwell (l2n.make_layer (nwell, "nwell"));
std::auto_ptr<db::Region> ractive (l2n.make_layer (active, "active"));
std::auto_ptr<db::Region> rpoly (l2n.make_polygon_layer (poly, "poly"));
std::auto_ptr<db::Region> rpoly_lbl (l2n.make_text_layer (poly_lbl, "poly_lbl"));
std::auto_ptr<db::Region> rdiff_cont (l2n.make_polygon_layer (diff_cont, "diff_cont"));
std::auto_ptr<db::Region> rpoly_cont (l2n.make_polygon_layer (poly_cont, "poly_cont"));
std::auto_ptr<db::Region> rmetal1 (l2n.make_polygon_layer (metal1, "metal1"));
std::auto_ptr<db::Region> rmetal1_lbl (l2n.make_text_layer (metal1_lbl, "metal1_lbl"));
std::auto_ptr<db::Region> rvia1 (l2n.make_polygon_layer (via1, "via1"));
std::auto_ptr<db::Region> rmetal2 (l2n.make_polygon_layer (metal2, "metal2"));
std::auto_ptr<db::Region> rmetal2_lbl (l2n.make_text_layer (metal2_lbl, "metal2_lbl"));
// derived regions
@ -215,6 +260,9 @@ TEST(1_Basic)
// net extraction
l2n.register_layer (rpsd, "psd");
l2n.register_layer (rnsd, "nsd");
// Intra-layer
l2n.connect (rpsd);
l2n.connect (rnsd);
@ -513,17 +561,17 @@ TEST(2_Probing)
db::Cell &tc = ly.cell (*ly.begin_top_down ());
db::LayoutToNetlist l2n (db::RecursiveShapeIterator (ly, tc, std::set<unsigned int> ()));
std::auto_ptr<db::Region> rnwell (l2n.make_layer (nwell));
std::auto_ptr<db::Region> ractive (l2n.make_layer (active));
std::auto_ptr<db::Region> rpoly (l2n.make_polygon_layer (poly));
std::auto_ptr<db::Region> rpoly_lbl (l2n.make_text_layer (poly_lbl));
std::auto_ptr<db::Region> rdiff_cont (l2n.make_polygon_layer (diff_cont));
std::auto_ptr<db::Region> rpoly_cont (l2n.make_polygon_layer (poly_cont));
std::auto_ptr<db::Region> rmetal1 (l2n.make_polygon_layer (metal1));
std::auto_ptr<db::Region> rmetal1_lbl (l2n.make_text_layer (metal1_lbl));
std::auto_ptr<db::Region> rvia1 (l2n.make_polygon_layer (via1));
std::auto_ptr<db::Region> rmetal2 (l2n.make_polygon_layer (metal2));
std::auto_ptr<db::Region> rmetal2_lbl (l2n.make_text_layer (metal2_lbl));
std::auto_ptr<db::Region> rnwell (l2n.make_layer (nwell, "nwell"));
std::auto_ptr<db::Region> ractive (l2n.make_layer (active, "active"));
std::auto_ptr<db::Region> rpoly (l2n.make_polygon_layer (poly, "poly"));
std::auto_ptr<db::Region> rpoly_lbl (l2n.make_text_layer (poly_lbl, "poly_lbl"));
std::auto_ptr<db::Region> rdiff_cont (l2n.make_polygon_layer (diff_cont, "diff_cont"));
std::auto_ptr<db::Region> rpoly_cont (l2n.make_polygon_layer (poly_cont, "poly_cont"));
std::auto_ptr<db::Region> rmetal1 (l2n.make_polygon_layer (metal1, "metal1"));
std::auto_ptr<db::Region> rmetal1_lbl (l2n.make_text_layer (metal1_lbl, "metal1_lbl"));
std::auto_ptr<db::Region> rvia1 (l2n.make_polygon_layer (via1, "via1"));
std::auto_ptr<db::Region> rmetal2 (l2n.make_polygon_layer (metal2, "metal2"));
std::auto_ptr<db::Region> rmetal2_lbl (l2n.make_text_layer (metal2_lbl, "metal2_lbl"));
// derived regions
@ -568,6 +616,9 @@ TEST(2_Probing)
// net extraction
l2n.register_layer (rpsd, "psd");
l2n.register_layer (rnsd, "nsd");
// Intra-layer
l2n.connect (rpsd);
l2n.connect (rnsd);
@ -754,19 +805,19 @@ TEST(3_GlobalNetConnections)
db::Cell &tc = ly.cell (*ly.begin_top_down ());
db::LayoutToNetlist l2n (db::RecursiveShapeIterator (ly, tc, std::set<unsigned int> ()));
std::auto_ptr<db::Region> rnwell (l2n.make_layer (nwell));
std::auto_ptr<db::Region> ractive (l2n.make_layer (active));
std::auto_ptr<db::Region> rpplus (l2n.make_layer (pplus));
std::auto_ptr<db::Region> rnplus (l2n.make_layer (nplus));
std::auto_ptr<db::Region> rpoly (l2n.make_polygon_layer (poly));
std::auto_ptr<db::Region> rpoly_lbl (l2n.make_text_layer (poly_lbl));
std::auto_ptr<db::Region> rdiff_cont (l2n.make_polygon_layer (diff_cont));
std::auto_ptr<db::Region> rpoly_cont (l2n.make_polygon_layer (poly_cont));
std::auto_ptr<db::Region> rmetal1 (l2n.make_polygon_layer (metal1));
std::auto_ptr<db::Region> rmetal1_lbl (l2n.make_text_layer (metal1_lbl));
std::auto_ptr<db::Region> rvia1 (l2n.make_polygon_layer (via1));
std::auto_ptr<db::Region> rmetal2 (l2n.make_polygon_layer (metal2));
std::auto_ptr<db::Region> rmetal2_lbl (l2n.make_text_layer (metal2_lbl));
std::auto_ptr<db::Region> rnwell (l2n.make_layer (nwell, "nwell"));
std::auto_ptr<db::Region> ractive (l2n.make_layer (active, "active"));
std::auto_ptr<db::Region> rpplus (l2n.make_layer (pplus, "pplus"));
std::auto_ptr<db::Region> rnplus (l2n.make_layer (nplus, "nplus"));
std::auto_ptr<db::Region> rpoly (l2n.make_polygon_layer (poly, "poly"));
std::auto_ptr<db::Region> rpoly_lbl (l2n.make_text_layer (poly_lbl, "poly_lbl"));
std::auto_ptr<db::Region> rdiff_cont (l2n.make_polygon_layer (diff_cont, "diff_cont"));
std::auto_ptr<db::Region> rpoly_cont (l2n.make_polygon_layer (poly_cont, "poly_cont"));
std::auto_ptr<db::Region> rmetal1 (l2n.make_polygon_layer (metal1, "metal1"));
std::auto_ptr<db::Region> rmetal1_lbl (l2n.make_text_layer (metal1_lbl, "metal1_lbl"));
std::auto_ptr<db::Region> rvia1 (l2n.make_polygon_layer (via1, "via1"));
std::auto_ptr<db::Region> rmetal2 (l2n.make_polygon_layer (metal2, "metal2"));
std::auto_ptr<db::Region> rmetal2_lbl (l2n.make_text_layer (metal2_lbl, "metal2_lbl"));
// derived regions
@ -819,6 +870,11 @@ TEST(3_GlobalNetConnections)
// net extraction
l2n.register_layer (rpsd, "psd");
l2n.register_layer (rnsd, "nsd");
l2n.register_layer (rptie, "ptie");
l2n.register_layer (rntie, "ntie");
// Intra-layer
l2n.connect (rpsd);
l2n.connect (rnsd);
@ -1021,20 +1077,20 @@ TEST(4_GlobalNetDeviceExtraction)
db::Cell &tc = ly.cell (*ly.begin_top_down ());
db::LayoutToNetlist l2n (db::RecursiveShapeIterator (ly, tc, std::set<unsigned int> ()));
std::auto_ptr<db::Region> rbulk (l2n.make_layer (ly.insert_layer ()));
std::auto_ptr<db::Region> rnwell (l2n.make_layer (nwell));
std::auto_ptr<db::Region> ractive (l2n.make_layer (active));
std::auto_ptr<db::Region> rpplus (l2n.make_layer (pplus));
std::auto_ptr<db::Region> rnplus (l2n.make_layer (nplus));
std::auto_ptr<db::Region> rpoly (l2n.make_polygon_layer (poly));
std::auto_ptr<db::Region> rpoly_lbl (l2n.make_text_layer (poly_lbl));
std::auto_ptr<db::Region> rdiff_cont (l2n.make_polygon_layer (diff_cont));
std::auto_ptr<db::Region> rpoly_cont (l2n.make_polygon_layer (poly_cont));
std::auto_ptr<db::Region> rmetal1 (l2n.make_polygon_layer (metal1));
std::auto_ptr<db::Region> rmetal1_lbl (l2n.make_text_layer (metal1_lbl));
std::auto_ptr<db::Region> rvia1 (l2n.make_polygon_layer (via1));
std::auto_ptr<db::Region> rmetal2 (l2n.make_polygon_layer (metal2));
std::auto_ptr<db::Region> rmetal2_lbl (l2n.make_text_layer (metal2_lbl));
std::auto_ptr<db::Region> rbulk (l2n.make_layer (ly.insert_layer (), "bulk"));
std::auto_ptr<db::Region> rnwell (l2n.make_layer (nwell, "nwell"));
std::auto_ptr<db::Region> ractive (l2n.make_layer (active, "active"));
std::auto_ptr<db::Region> rpplus (l2n.make_layer (pplus, "pplus"));
std::auto_ptr<db::Region> rnplus (l2n.make_layer (nplus, "nplus"));
std::auto_ptr<db::Region> rpoly (l2n.make_polygon_layer (poly, "poly"));
std::auto_ptr<db::Region> rpoly_lbl (l2n.make_text_layer (poly_lbl, "poly_lbl"));
std::auto_ptr<db::Region> rdiff_cont (l2n.make_polygon_layer (diff_cont, "diff_cont"));
std::auto_ptr<db::Region> rpoly_cont (l2n.make_polygon_layer (poly_cont, "poly_cont"));
std::auto_ptr<db::Region> rmetal1 (l2n.make_polygon_layer (metal1, "metal1"));
std::auto_ptr<db::Region> rmetal1_lbl (l2n.make_text_layer (metal1_lbl, "metal1_lbl"));
std::auto_ptr<db::Region> rvia1 (l2n.make_polygon_layer (via1, "via1"));
std::auto_ptr<db::Region> rmetal2 (l2n.make_polygon_layer (metal2, "metal2"));
std::auto_ptr<db::Region> rmetal2_lbl (l2n.make_text_layer (metal2_lbl, "metal2_lbl"));
// derived regions
@ -1089,6 +1145,11 @@ TEST(4_GlobalNetDeviceExtraction)
// net extraction
l2n.register_layer (rpsd, "psd");
l2n.register_layer (rnsd, "nsd");
l2n.register_layer (rptie, "ptie");
l2n.register_layer (rntie, "ntie");
// Intra-layer
l2n.connect (rpsd);
l2n.connect (rnsd);
@ -1294,20 +1355,20 @@ TEST(5_DeviceExtractionWithDeviceCombination)
db::Cell &tc = ly.cell (*ly.begin_top_down ());
db::LayoutToNetlist l2n (db::RecursiveShapeIterator (ly, tc, std::set<unsigned int> ()));
std::auto_ptr<db::Region> rbulk (l2n.make_layer (ly.insert_layer ()));
std::auto_ptr<db::Region> rnwell (l2n.make_layer (nwell));
std::auto_ptr<db::Region> ractive (l2n.make_layer (active));
std::auto_ptr<db::Region> rpplus (l2n.make_layer (pplus));
std::auto_ptr<db::Region> rnplus (l2n.make_layer (nplus));
std::auto_ptr<db::Region> rpoly (l2n.make_polygon_layer (poly));
std::auto_ptr<db::Region> rpoly_lbl (l2n.make_text_layer (poly_lbl));
std::auto_ptr<db::Region> rdiff_cont (l2n.make_polygon_layer (diff_cont));
std::auto_ptr<db::Region> rpoly_cont (l2n.make_polygon_layer (poly_cont));
std::auto_ptr<db::Region> rmetal1 (l2n.make_polygon_layer (metal1));
std::auto_ptr<db::Region> rmetal1_lbl (l2n.make_text_layer (metal1_lbl));
std::auto_ptr<db::Region> rvia1 (l2n.make_polygon_layer (via1));
std::auto_ptr<db::Region> rmetal2 (l2n.make_polygon_layer (metal2));
std::auto_ptr<db::Region> rmetal2_lbl (l2n.make_text_layer (metal2_lbl));
std::auto_ptr<db::Region> rbulk (l2n.make_layer ("bulk"));
std::auto_ptr<db::Region> rnwell (l2n.make_layer (nwell, "nwell"));
std::auto_ptr<db::Region> ractive (l2n.make_layer (active, "active"));
std::auto_ptr<db::Region> rpplus (l2n.make_layer (pplus, "pplus"));
std::auto_ptr<db::Region> rnplus (l2n.make_layer (nplus, "nplus"));
std::auto_ptr<db::Region> rpoly (l2n.make_polygon_layer (poly, "poly"));
std::auto_ptr<db::Region> rpoly_lbl (l2n.make_text_layer (poly_lbl, "poly_lbl"));
std::auto_ptr<db::Region> rdiff_cont (l2n.make_polygon_layer (diff_cont, "diff_cont"));
std::auto_ptr<db::Region> rpoly_cont (l2n.make_polygon_layer (poly_cont, "poly_cont"));
std::auto_ptr<db::Region> rmetal1 (l2n.make_polygon_layer (metal1, "metal1"));
std::auto_ptr<db::Region> rmetal1_lbl (l2n.make_text_layer (metal1_lbl, "metal1_lbl"));
std::auto_ptr<db::Region> rvia1 (l2n.make_polygon_layer (via1, "via1"));
std::auto_ptr<db::Region> rmetal2 (l2n.make_polygon_layer (metal2, "metal2"));
std::auto_ptr<db::Region> rmetal2_lbl (l2n.make_text_layer (metal2_lbl, "metal2_lbl"));
// derived regions
@ -1362,6 +1423,11 @@ TEST(5_DeviceExtractionWithDeviceCombination)
// net extraction
l2n.register_layer (rpsd, "psd");
l2n.register_layer (rnsd, "nsd");
l2n.register_layer (rptie, "ptie");
l2n.register_layer (rntie, "ntie");
// Intra-layer
l2n.connect (rpsd);
l2n.connect (rnsd);

View File

@ -90,16 +90,16 @@ TEST(1_WriterBasic)
db::Region rpactive = *ractive & *rnwell;
db::Region rpgate = rpactive & *rpoly;
db::Region rpsd = rpactive - rpgate;
l2n.name (rpactive, "pactive");
l2n.name (rpgate, "pgate");
l2n.name (rpsd, "psd");
l2n.register_layer (rpactive, "pactive");
l2n.register_layer (rpgate, "pgate");
l2n.register_layer (rpsd, "psd");
db::Region rnactive = *ractive - *rnwell;
db::Region rngate = rnactive & *rpoly;
db::Region rnsd = rnactive - rngate;
l2n.name (rnactive, "nactive");
l2n.name (rngate, "ngate");
l2n.name (rnsd, "nsd");
l2n.register_layer (rnactive, "nactive");
l2n.register_layer (rngate, "ngate");
l2n.register_layer (rnsd, "nsd");
db::NetlistDeviceExtractorMOS3Transistor pmos_ex ("PMOS");
db::NetlistDeviceExtractorMOS3Transistor nmos_ex ("NMOS");
@ -296,20 +296,20 @@ TEST(2_WriterWithGlobalNets)
db::Region rntie = ractive_in_nwell & *rnplus;
db::Region rpgate = rpactive & *rpoly;
db::Region rpsd = rpactive - rpgate;
l2n.name (rpactive, "pactive");
l2n.name (rntie, "ntie");
l2n.name (rpgate, "pgate");
l2n.name (rpsd, "psd");
l2n.register_layer (rpactive, "pactive");
l2n.register_layer (rntie, "ntie");
l2n.register_layer (rpgate, "pgate");
l2n.register_layer (rpsd, "psd");
db::Region ractive_outside_nwell = *ractive - *rnwell;
db::Region rnactive = ractive_outside_nwell & *rnplus;
db::Region rptie = ractive_outside_nwell & *rpplus;
db::Region rngate = rnactive & *rpoly;
db::Region rnsd = rnactive - rngate;
l2n.name (rnactive, "nactive");
l2n.name (rptie, "ptie");
l2n.name (rngate, "ngate");
l2n.name (rnsd, "nsd");
l2n.register_layer (rnactive, "nactive");
l2n.register_layer (rptie, "ptie");
l2n.register_layer (rngate, "ngate");
l2n.register_layer (rnsd, "nsd");
// return the computed layers into the original layout and write it for debugging purposes

BIN
testdata/algo/hierarchy_builder_au2f.gds vendored Normal file

Binary file not shown.

View File

@ -61,7 +61,7 @@ class DBLayoutToNetlist_TestClass < TestBase
assert_equal(l2n.internal_layout.cell(ci).name, ly2.cell(cm.cell_mapping(ci)).name)
end
rmetal1 = l2n.make_polygon_layer( ly.layer(6, 0) )
rmetal1 = l2n.make_polygon_layer( ly.layer(6, 0), "metal1" )
bulk_id = l2n.connect_global(rmetal1, "BULK")
assert_equal(l2n.global_net_name(bulk_id), "BULK")
@ -76,11 +76,11 @@ class DBLayoutToNetlist_TestClass < TestBase
# only plain backend connectivity
rmetal1 = l2n.make_polygon_layer( ly.layer(6, 0) )
rmetal1_lbl = l2n.make_text_layer( ly.layer(6, 1) )
rvia1 = l2n.make_polygon_layer( ly.layer(7, 0) )
rmetal2 = l2n.make_polygon_layer( ly.layer(8, 0) )
rmetal2_lbl = l2n.make_text_layer( ly.layer(8, 1) )
rmetal1 = l2n.make_polygon_layer( ly.layer(6, 0), "metal1" )
rmetal1_lbl = l2n.make_text_layer( ly.layer(6, 1), "metal1_lbl" )
rvia1 = l2n.make_polygon_layer( ly.layer(7, 0), "via1" )
rmetal2 = l2n.make_polygon_layer( ly.layer(8, 0), "metal2" )
rmetal2_lbl = l2n.make_text_layer( ly.layer(8, 1), "metal2_lbl" )
# Intra-layer
l2n.connect(rmetal1)
@ -141,19 +141,21 @@ END
# only plain connectivity
ractive = l2n.make_layer( ly.layer(2, 0) )
rpoly = l2n.make_polygon_layer( ly.layer(3, 0) )
rpoly_lbl = l2n.make_text_layer( ly.layer(3, 1) )
rdiff_cont = l2n.make_polygon_layer( ly.layer(4, 0) )
rpoly_cont = l2n.make_polygon_layer( ly.layer(5, 0) )
rmetal1 = l2n.make_polygon_layer( ly.layer(6, 0) )
rmetal1_lbl = l2n.make_text_layer( ly.layer(6, 1) )
rvia1 = l2n.make_polygon_layer( ly.layer(7, 0) )
rmetal2 = l2n.make_polygon_layer( ly.layer(8, 0) )
rmetal2_lbl = l2n.make_text_layer( ly.layer(8, 1) )
ractive = l2n.make_layer( ly.layer(2, 0), "active" )
rpoly = l2n.make_polygon_layer( ly.layer(3, 0), "poly" )
rpoly_lbl = l2n.make_text_layer( ly.layer(3, 1), "poly_lbl" )
rdiff_cont = l2n.make_polygon_layer( ly.layer(4, 0), "diff_cont" )
rpoly_cont = l2n.make_polygon_layer( ly.layer(5, 0), "poly_cont" )
rmetal1 = l2n.make_polygon_layer( ly.layer(6, 0), "metal1" )
rmetal1_lbl = l2n.make_text_layer( ly.layer(6, 1), "metal1_lbl" )
rvia1 = l2n.make_polygon_layer( ly.layer(7, 0), "via1" )
rmetal2 = l2n.make_polygon_layer( ly.layer(8, 0), "metal2" )
rmetal2_lbl = l2n.make_text_layer( ly.layer(8, 1), "metal2_lbl" )
rsd = ractive - rpoly
l2n.register(rsd, "sd")
# Intra-layer
l2n.connect(rsd)
l2n.connect(rpoly)
@ -206,17 +208,17 @@ END
l2n = RBA::LayoutToNetlist::new(RBA::RecursiveShapeIterator::new(ly, ly.top_cell, []))
rnwell = l2n.make_layer( ly.layer(1, 0) )
ractive = l2n.make_layer( ly.layer(2, 0) )
rpoly = l2n.make_polygon_layer( ly.layer(3, 0) )
rpoly_lbl = l2n.make_text_layer( ly.layer(3, 1) )
rdiff_cont = l2n.make_polygon_layer( ly.layer(4, 0) )
rpoly_cont = l2n.make_polygon_layer( ly.layer(5, 0) )
rmetal1 = l2n.make_polygon_layer( ly.layer(6, 0) )
rmetal1_lbl = l2n.make_text_layer( ly.layer(6, 1) )
rvia1 = l2n.make_polygon_layer( ly.layer(7, 0) )
rmetal2 = l2n.make_polygon_layer( ly.layer(8, 0) )
rmetal2_lbl = l2n.make_text_layer( ly.layer(8, 1) )
rnwell = l2n.make_layer( ly.layer(1, 0), "nwell" )
ractive = l2n.make_layer( ly.layer(2, 0), "active" )
rpoly = l2n.make_polygon_layer( ly.layer(3, 0), "poly" )
rpoly_lbl = l2n.make_text_layer( ly.layer(3, 1), "poly_lbl" )
rdiff_cont = l2n.make_polygon_layer( ly.layer(4, 0), "diff_cont" )
rpoly_cont = l2n.make_polygon_layer( ly.layer(5, 0), "poly_cont" )
rmetal1 = l2n.make_polygon_layer( ly.layer(6, 0), "metal1" )
rmetal1_lbl = l2n.make_text_layer( ly.layer(6, 1), "metal1_lbl" )
rvia1 = l2n.make_polygon_layer( ly.layer(7, 0), "via1" )
rmetal2 = l2n.make_polygon_layer( ly.layer(8, 0), "metal2" )
rmetal2_lbl = l2n.make_text_layer( ly.layer(8, 1), "metal2_lbl" )
rpactive = ractive & rnwell
rpgate = rpactive & rpoly
@ -236,6 +238,9 @@ END
# Define connectivity for netlist extraction
l2n.register(rpsd, "psd")
l2n.register(rnsd, "nsd")
# Intra-layer
l2n.connect(rpsd)
l2n.connect(rnsd)
@ -297,20 +302,20 @@ END
l2n = RBA::LayoutToNetlist::new(RBA::RecursiveShapeIterator::new(ly, ly.top_cell, []))
rbulk = l2n.make_polygon_layer( ly.layer )
rnwell = l2n.make_polygon_layer( ly.layer(1, 0) )
ractive = l2n.make_polygon_layer( ly.layer(2, 0) )
rpoly = l2n.make_polygon_layer( ly.layer(3, 0) )
rpoly_lbl = l2n.make_text_layer( ly.layer(3, 1) )
rdiff_cont = l2n.make_polygon_layer( ly.layer(4, 0) )
rpoly_cont = l2n.make_polygon_layer( ly.layer(5, 0) )
rmetal1 = l2n.make_polygon_layer( ly.layer(6, 0) )
rmetal1_lbl = l2n.make_text_layer( ly.layer(6, 1) )
rvia1 = l2n.make_polygon_layer( ly.layer(7, 0) )
rmetal2 = l2n.make_polygon_layer( ly.layer(8, 0) )
rmetal2_lbl = l2n.make_text_layer( ly.layer(8, 1) )
rpplus = l2n.make_polygon_layer( ly.layer(10, 0) )
rnplus = l2n.make_polygon_layer( ly.layer(11, 0) )
rbulk = l2n.make_layer( "bulk" )
rnwell = l2n.make_polygon_layer( ly.layer(1, 0) , "nwell" )
ractive = l2n.make_polygon_layer( ly.layer(2, 0) , "active" )
rpoly = l2n.make_polygon_layer( ly.layer(3, 0) , "poly" )
rpoly_lbl = l2n.make_text_layer( ly.layer(3, 1) , "poly_lbl" )
rdiff_cont = l2n.make_polygon_layer( ly.layer(4, 0) , "diff_cont" )
rpoly_cont = l2n.make_polygon_layer( ly.layer(5, 0) , "poly_cont" )
rmetal1 = l2n.make_polygon_layer( ly.layer(6, 0) , "metal1" )
rmetal1_lbl = l2n.make_text_layer( ly.layer(6, 1) , "metal1_lbl" )
rvia1 = l2n.make_polygon_layer( ly.layer(7, 0) , "via1" )
rmetal2 = l2n.make_polygon_layer( ly.layer(8, 0) , "metal2" )
rmetal2_lbl = l2n.make_text_layer( ly.layer(8, 1) , "metal2_lbl" )
rpplus = l2n.make_polygon_layer( ly.layer(10, 0) , "pplus" )
rnplus = l2n.make_polygon_layer( ly.layer(11, 0) , "nplus" )
ractive_in_nwell = ractive & rnwell
rpactive = ractive_in_nwell & rpplus
@ -334,6 +339,11 @@ END
# Define connectivity for netlist extraction
l2n.register(rpsd, "psd")
l2n.register(rnsd, "nsd")
l2n.register(rptie, "ptie")
l2n.register(rntie, "ntie")
# Intra-layer
l2n.connect(rpsd)
l2n.connect(rnsd)
@ -417,6 +427,24 @@ END
end
def test_13_ReadAndWrite
l2n = RBA::LayoutToNetlist::new
input = File.join($ut_testsrc, "testdata", "algo", "l2n_writer_au.txt")
l2n.read(input)
tmp = File::join($ut_testtmp, "tmp.txt")
l2n.write(tmp)
assert_equal(File.open(tmp, "r").read, File.open(input, "r").read)
assert_equal(l2n.layer_names.join(","), "poly,poly_lbl,diff_cont,poly_cont,metal1,metal1_lbl,via1,metal2,metal2_lbl,psd,nsd")
assert_equal(l2n.name(l2n.layer_by_name("metal1")), "metal1")
assert_equal(l2n.name(l2n.layer_by_index(l2n.layer_of(l2n.layer_by_name("metal1")))), "metal1")
end
end
load("test_epilogue.rb")