|
|
@ -50,6 +50,10 @@ SOURCES = \
|
||||||
dbManager.cc \
|
dbManager.cc \
|
||||||
dbMatrix.cc \
|
dbMatrix.cc \
|
||||||
dbMemStatistics.cc \
|
dbMemStatistics.cc \
|
||||||
|
dbMutableEdgePairs.cc \
|
||||||
|
dbMutableEdges.cc \
|
||||||
|
dbMutableRegion.cc \
|
||||||
|
dbMutableTexts.cc \
|
||||||
dbObject.cc \
|
dbObject.cc \
|
||||||
dbPath.cc \
|
dbPath.cc \
|
||||||
dbPCellDeclaration.cc \
|
dbPCellDeclaration.cc \
|
||||||
|
|
@ -258,6 +262,10 @@ HEADERS = \
|
||||||
dbMatrix.h \
|
dbMatrix.h \
|
||||||
dbMemStatistics.h \
|
dbMemStatistics.h \
|
||||||
dbMetaInfo.h \
|
dbMetaInfo.h \
|
||||||
|
dbMutableEdgePairs.h \
|
||||||
|
dbMutableEdges.h \
|
||||||
|
dbMutableRegion.h \
|
||||||
|
dbMutableTexts.h \
|
||||||
dbObject.h \
|
dbObject.h \
|
||||||
dbObjectTag.h \
|
dbObjectTag.h \
|
||||||
dbObjectWithProperties.h \
|
dbObjectWithProperties.h \
|
||||||
|
|
|
||||||
|
|
@ -186,8 +186,10 @@ void Circuit::rename_pin (size_t id, const std::string &name)
|
||||||
|
|
||||||
const Pin *Circuit::pin_by_name (const std::string &name) const
|
const Pin *Circuit::pin_by_name (const std::string &name) const
|
||||||
{
|
{
|
||||||
|
std::string nn = mp_netlist ? mp_netlist->normalize_name (name) : name;
|
||||||
|
|
||||||
for (Circuit::const_pin_iterator p = begin_pins (); p != end_pins (); ++p) {
|
for (Circuit::const_pin_iterator p = begin_pins (); p != end_pins (); ++p) {
|
||||||
if (p->name () == name) {
|
if (p->name () == nn) {
|
||||||
return p.operator-> ();
|
return p.operator-> ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -331,6 +333,11 @@ void Circuit::remove_pin (size_t id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Net *Circuit::net_by_name (const std::string &name)
|
||||||
|
{
|
||||||
|
return m_net_by_name.object_by (mp_netlist ? mp_netlist->normalize_name (name) : name);
|
||||||
|
}
|
||||||
|
|
||||||
void Circuit::add_net (Net *net)
|
void Circuit::add_net (Net *net)
|
||||||
{
|
{
|
||||||
if (! net) {
|
if (! net) {
|
||||||
|
|
@ -423,6 +430,11 @@ void Circuit::remove_device (Device *device)
|
||||||
m_devices.erase (device);
|
m_devices.erase (device);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Device *Circuit::device_by_name (const std::string &name)
|
||||||
|
{
|
||||||
|
return m_device_by_name.object_by (mp_netlist ? mp_netlist->normalize_name (name) : name);
|
||||||
|
}
|
||||||
|
|
||||||
void Circuit::add_subcircuit (SubCircuit *subcircuit)
|
void Circuit::add_subcircuit (SubCircuit *subcircuit)
|
||||||
{
|
{
|
||||||
if (! subcircuit) {
|
if (! subcircuit) {
|
||||||
|
|
@ -456,6 +468,11 @@ void Circuit::remove_subcircuit (SubCircuit *subcircuit)
|
||||||
m_subcircuits.erase (subcircuit);
|
m_subcircuits.erase (subcircuit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SubCircuit *Circuit::subcircuit_by_name (const std::string &name)
|
||||||
|
{
|
||||||
|
return m_subcircuit_by_name.object_by (mp_netlist ? mp_netlist->normalize_name (name) : name);
|
||||||
|
}
|
||||||
|
|
||||||
void Circuit::register_ref (SubCircuit *r)
|
void Circuit::register_ref (SubCircuit *r)
|
||||||
{
|
{
|
||||||
m_refs.push_back (r);
|
m_refs.push_back (r);
|
||||||
|
|
|
||||||
|
|
@ -496,10 +496,7 @@ public:
|
||||||
*
|
*
|
||||||
* If the name is not valid, null is returned.
|
* If the name is not valid, null is returned.
|
||||||
*/
|
*/
|
||||||
Net *net_by_name (const std::string &name)
|
Net *net_by_name (const std::string &name);
|
||||||
{
|
|
||||||
return m_net_by_name.object_by (name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Adds a device to this circuit
|
* @brief Adds a device to this circuit
|
||||||
|
|
@ -556,10 +553,7 @@ public:
|
||||||
*
|
*
|
||||||
* If the name is not valid, null is returned.
|
* If the name is not valid, null is returned.
|
||||||
*/
|
*/
|
||||||
Device *device_by_name (const std::string &name)
|
Device *device_by_name (const std::string &name);
|
||||||
{
|
|
||||||
return m_device_by_name.object_by (name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Begin iterator for the devices of the circuit (non-const version)
|
* @brief Begin iterator for the devices of the circuit (non-const version)
|
||||||
|
|
@ -648,10 +642,7 @@ public:
|
||||||
*
|
*
|
||||||
* If the name is not valid, null is returned.
|
* If the name is not valid, null is returned.
|
||||||
*/
|
*/
|
||||||
SubCircuit *subcircuit_by_name (const std::string &name)
|
SubCircuit *subcircuit_by_name (const std::string &name);
|
||||||
{
|
|
||||||
return m_subcircuit_by_name.object_by (name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Begin iterator for the subcircuits of the circuit (non-const version)
|
* @brief Begin iterator for the subcircuits of the circuit (non-const version)
|
||||||
|
|
|
||||||
|
|
@ -112,31 +112,31 @@ private:
|
||||||
|
|
||||||
|
|
||||||
DeepEdgePairs::DeepEdgePairs ()
|
DeepEdgePairs::DeepEdgePairs ()
|
||||||
: AsIfFlatEdgePairs ()
|
: MutableEdgePairs ()
|
||||||
{
|
{
|
||||||
// .. nothing yet ..
|
// .. nothing yet ..
|
||||||
}
|
}
|
||||||
|
|
||||||
DeepEdgePairs::DeepEdgePairs (const RecursiveShapeIterator &si, DeepShapeStore &dss)
|
DeepEdgePairs::DeepEdgePairs (const RecursiveShapeIterator &si, DeepShapeStore &dss)
|
||||||
: AsIfFlatEdgePairs ()
|
: MutableEdgePairs ()
|
||||||
{
|
{
|
||||||
set_deep_layer (dss.create_edge_pair_layer (si));
|
set_deep_layer (dss.create_edge_pair_layer (si));
|
||||||
}
|
}
|
||||||
|
|
||||||
DeepEdgePairs::DeepEdgePairs (const RecursiveShapeIterator &si, DeepShapeStore &dss, const db::ICplxTrans &trans)
|
DeepEdgePairs::DeepEdgePairs (const RecursiveShapeIterator &si, DeepShapeStore &dss, const db::ICplxTrans &trans)
|
||||||
: AsIfFlatEdgePairs ()
|
: MutableEdgePairs ()
|
||||||
{
|
{
|
||||||
set_deep_layer (dss.create_edge_pair_layer (si, trans));
|
set_deep_layer (dss.create_edge_pair_layer (si, trans));
|
||||||
}
|
}
|
||||||
|
|
||||||
DeepEdgePairs::DeepEdgePairs (const DeepEdgePairs &other)
|
DeepEdgePairs::DeepEdgePairs (const DeepEdgePairs &other)
|
||||||
: AsIfFlatEdgePairs (other), db::DeepShapeCollectionDelegateBase (other)
|
: MutableEdgePairs (other), db::DeepShapeCollectionDelegateBase (other)
|
||||||
{
|
{
|
||||||
// .. nothing yet ..
|
// .. nothing yet ..
|
||||||
}
|
}
|
||||||
|
|
||||||
DeepEdgePairs::DeepEdgePairs (const DeepLayer &dl)
|
DeepEdgePairs::DeepEdgePairs (const DeepLayer &dl)
|
||||||
: AsIfFlatEdgePairs ()
|
: MutableEdgePairs ()
|
||||||
{
|
{
|
||||||
set_deep_layer (dl);
|
set_deep_layer (dl);
|
||||||
}
|
}
|
||||||
|
|
@ -151,6 +151,86 @@ EdgePairsDelegate *DeepEdgePairs::clone () const
|
||||||
return new DeepEdgePairs (*this);
|
return new DeepEdgePairs (*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DeepEdgePairs::do_insert (const db::EdgePair &edge_pair)
|
||||||
|
{
|
||||||
|
db::Layout &layout = deep_layer ().layout ();
|
||||||
|
if (layout.begin_top_down () != layout.end_top_down ()) {
|
||||||
|
db::Cell &top_cell = layout.cell (*layout.begin_top_down ());
|
||||||
|
top_cell.shapes (deep_layer ().layer ()).insert (edge_pair);
|
||||||
|
}
|
||||||
|
|
||||||
|
invalidate_bbox ();
|
||||||
|
set_is_merged (false);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Trans>
|
||||||
|
static void transform_deep_layer (db::DeepLayer &deep_layer, const Trans &t)
|
||||||
|
{
|
||||||
|
// TODO: this is a pretty cheap implementation. At least a plain move can be done with orientation variants.
|
||||||
|
|
||||||
|
db::Layout &layout = deep_layer.layout ();
|
||||||
|
if (layout.begin_top_down () != layout.end_top_down ()) {
|
||||||
|
|
||||||
|
db::Cell &top_cell = layout.cell (*layout.begin_top_down ());
|
||||||
|
|
||||||
|
db::Shapes flat_shapes (layout.is_editable ());
|
||||||
|
for (db::RecursiveShapeIterator iter (layout, top_cell, deep_layer.layer ()); !iter.at_end (); ++iter) {
|
||||||
|
flat_shapes.insert (iter->edge_pair ().transformed (iter.trans ()).transformed (t));
|
||||||
|
}
|
||||||
|
|
||||||
|
layout.clear_layer (deep_layer.layer ());
|
||||||
|
top_cell.shapes (deep_layer.layer ()).swap (flat_shapes);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeepEdgePairs::do_transform (const db::Trans &t)
|
||||||
|
{
|
||||||
|
transform_deep_layer (deep_layer (), t);
|
||||||
|
invalidate_bbox ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeepEdgePairs::do_transform (const db::ICplxTrans &t)
|
||||||
|
{
|
||||||
|
transform_deep_layer (deep_layer (), t);
|
||||||
|
invalidate_bbox ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeepEdgePairs::do_transform (const db::IMatrix2d &t)
|
||||||
|
{
|
||||||
|
transform_deep_layer (deep_layer (), t);
|
||||||
|
invalidate_bbox ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeepEdgePairs::do_transform (const db::IMatrix3d &t)
|
||||||
|
{
|
||||||
|
transform_deep_layer (deep_layer (), t);
|
||||||
|
invalidate_bbox ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeepEdgePairs::reserve (size_t)
|
||||||
|
{
|
||||||
|
// Not implemented for deep regions
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeepEdgePairs::flatten ()
|
||||||
|
{
|
||||||
|
db::Layout &layout = deep_layer ().layout ();
|
||||||
|
if (layout.begin_top_down () != layout.end_top_down ()) {
|
||||||
|
|
||||||
|
db::Cell &top_cell = layout.cell (*layout.begin_top_down ());
|
||||||
|
|
||||||
|
db::Shapes flat_shapes (layout.is_editable ());
|
||||||
|
for (db::RecursiveShapeIterator iter (layout, top_cell, deep_layer ().layer ()); !iter.at_end (); ++iter) {
|
||||||
|
flat_shapes.insert (iter->edge_pair ().transformed (iter.trans ()));
|
||||||
|
}
|
||||||
|
|
||||||
|
layout.clear_layer (deep_layer ().layer ());
|
||||||
|
top_cell.shapes (deep_layer ().layer ()).swap (flat_shapes);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
EdgePairsIteratorDelegate *DeepEdgePairs::begin () const
|
EdgePairsIteratorDelegate *DeepEdgePairs::begin () const
|
||||||
{
|
{
|
||||||
return new DeepEdgePairsIterator (begin_iter ().first);
|
return new DeepEdgePairsIterator (begin_iter ().first);
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@
|
||||||
|
|
||||||
#include "dbCommon.h"
|
#include "dbCommon.h"
|
||||||
|
|
||||||
#include "dbAsIfFlatEdgePairs.h"
|
#include "dbMutableEdgePairs.h"
|
||||||
#include "dbDeepShapeStore.h"
|
#include "dbDeepShapeStore.h"
|
||||||
#include "dbEdgePairs.h"
|
#include "dbEdgePairs.h"
|
||||||
|
|
||||||
|
|
@ -36,7 +36,7 @@ namespace db {
|
||||||
* @brief Provides hierarchical edges implementation
|
* @brief Provides hierarchical edges implementation
|
||||||
*/
|
*/
|
||||||
class DB_PUBLIC DeepEdgePairs
|
class DB_PUBLIC DeepEdgePairs
|
||||||
: public db::AsIfFlatEdgePairs, public db::DeepShapeCollectionDelegateBase
|
: public db::MutableEdgePairs, public db::DeepShapeCollectionDelegateBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DeepEdgePairs ();
|
DeepEdgePairs ();
|
||||||
|
|
@ -50,6 +50,17 @@ public:
|
||||||
|
|
||||||
EdgePairsDelegate *clone () const;
|
EdgePairsDelegate *clone () const;
|
||||||
|
|
||||||
|
virtual void do_insert (const db::EdgePair &edge_pair);
|
||||||
|
|
||||||
|
virtual void do_transform (const db::Trans &t);
|
||||||
|
virtual void do_transform (const db::ICplxTrans &t);
|
||||||
|
virtual void do_transform (const db::IMatrix2d &t);
|
||||||
|
virtual void do_transform (const db::IMatrix3d &t);
|
||||||
|
|
||||||
|
virtual void flatten ();
|
||||||
|
|
||||||
|
virtual void reserve (size_t n);
|
||||||
|
|
||||||
virtual EdgePairsIteratorDelegate *begin () const;
|
virtual EdgePairsIteratorDelegate *begin () const;
|
||||||
virtual std::pair<db::RecursiveShapeIterator, db::ICplxTrans> begin_iter () const;
|
virtual std::pair<db::RecursiveShapeIterator, db::ICplxTrans> begin_iter () const;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -123,14 +123,14 @@ private:
|
||||||
// DeepEdges implementation
|
// DeepEdges implementation
|
||||||
|
|
||||||
DeepEdges::DeepEdges (const RecursiveShapeIterator &si, DeepShapeStore &dss, bool as_edges)
|
DeepEdges::DeepEdges (const RecursiveShapeIterator &si, DeepShapeStore &dss, bool as_edges)
|
||||||
: AsIfFlatEdges (), m_merged_edges ()
|
: MutableEdges (), m_merged_edges ()
|
||||||
{
|
{
|
||||||
set_deep_layer (dss.create_edge_layer (si, as_edges));
|
set_deep_layer (dss.create_edge_layer (si, as_edges));
|
||||||
init ();
|
init ();
|
||||||
}
|
}
|
||||||
|
|
||||||
DeepEdges::DeepEdges (const RecursiveShapeIterator &si, DeepShapeStore &dss, const db::ICplxTrans &trans, bool as_edges, bool merged_semantics)
|
DeepEdges::DeepEdges (const RecursiveShapeIterator &si, DeepShapeStore &dss, const db::ICplxTrans &trans, bool as_edges, bool merged_semantics)
|
||||||
: AsIfFlatEdges (), m_merged_edges ()
|
: MutableEdges (), m_merged_edges ()
|
||||||
{
|
{
|
||||||
set_deep_layer (dss.create_edge_layer (si, as_edges, trans));
|
set_deep_layer (dss.create_edge_layer (si, as_edges, trans));
|
||||||
init ();
|
init ();
|
||||||
|
|
@ -138,7 +138,7 @@ DeepEdges::DeepEdges (const RecursiveShapeIterator &si, DeepShapeStore &dss, con
|
||||||
}
|
}
|
||||||
|
|
||||||
DeepEdges::DeepEdges (const db::Edges &other, DeepShapeStore &dss)
|
DeepEdges::DeepEdges (const db::Edges &other, DeepShapeStore &dss)
|
||||||
: AsIfFlatEdges (), m_merged_edges ()
|
: MutableEdges (), m_merged_edges ()
|
||||||
{
|
{
|
||||||
set_deep_layer (dss.create_from_flat (other));
|
set_deep_layer (dss.create_from_flat (other));
|
||||||
|
|
||||||
|
|
@ -147,13 +147,13 @@ DeepEdges::DeepEdges (const db::Edges &other, DeepShapeStore &dss)
|
||||||
}
|
}
|
||||||
|
|
||||||
DeepEdges::DeepEdges ()
|
DeepEdges::DeepEdges ()
|
||||||
: AsIfFlatEdges ()
|
: MutableEdges ()
|
||||||
{
|
{
|
||||||
init ();
|
init ();
|
||||||
}
|
}
|
||||||
|
|
||||||
DeepEdges::DeepEdges (const DeepLayer &dl)
|
DeepEdges::DeepEdges (const DeepLayer &dl)
|
||||||
: AsIfFlatEdges ()
|
: MutableEdges ()
|
||||||
{
|
{
|
||||||
set_deep_layer (dl);
|
set_deep_layer (dl);
|
||||||
init ();
|
init ();
|
||||||
|
|
@ -165,7 +165,7 @@ DeepEdges::~DeepEdges ()
|
||||||
}
|
}
|
||||||
|
|
||||||
DeepEdges::DeepEdges (const DeepEdges &other)
|
DeepEdges::DeepEdges (const DeepEdges &other)
|
||||||
: AsIfFlatEdges (other), DeepShapeCollectionDelegateBase (other),
|
: MutableEdges (other), DeepShapeCollectionDelegateBase (other),
|
||||||
m_merged_edges_valid (other.m_merged_edges_valid),
|
m_merged_edges_valid (other.m_merged_edges_valid),
|
||||||
m_is_merged (other.m_is_merged)
|
m_is_merged (other.m_is_merged)
|
||||||
{
|
{
|
||||||
|
|
@ -211,6 +211,86 @@ void DeepEdges::merged_semantics_changed ()
|
||||||
// .. nothing yet ..
|
// .. nothing yet ..
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DeepEdges::do_insert (const db::Edge &edge)
|
||||||
|
{
|
||||||
|
db::Layout &layout = deep_layer ().layout ();
|
||||||
|
if (layout.begin_top_down () != layout.end_top_down ()) {
|
||||||
|
db::Cell &top_cell = layout.cell (*layout.begin_top_down ());
|
||||||
|
top_cell.shapes (deep_layer ().layer ()).insert (edge);
|
||||||
|
}
|
||||||
|
|
||||||
|
invalidate_bbox ();
|
||||||
|
set_is_merged (false);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Trans>
|
||||||
|
static void transform_deep_layer (db::DeepLayer &deep_layer, const Trans &t)
|
||||||
|
{
|
||||||
|
// TODO: this is a pretty cheap implementation. At least a plain move can be done with orientation variants.
|
||||||
|
|
||||||
|
db::Layout &layout = deep_layer.layout ();
|
||||||
|
if (layout.begin_top_down () != layout.end_top_down ()) {
|
||||||
|
|
||||||
|
db::Cell &top_cell = layout.cell (*layout.begin_top_down ());
|
||||||
|
|
||||||
|
db::Shapes flat_shapes (layout.is_editable ());
|
||||||
|
for (db::RecursiveShapeIterator iter (layout, top_cell, deep_layer.layer ()); !iter.at_end (); ++iter) {
|
||||||
|
flat_shapes.insert (iter->edge ().transformed (iter.trans ()).transformed (t));
|
||||||
|
}
|
||||||
|
|
||||||
|
layout.clear_layer (deep_layer.layer ());
|
||||||
|
top_cell.shapes (deep_layer.layer ()).swap (flat_shapes);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeepEdges::do_transform (const db::Trans &t)
|
||||||
|
{
|
||||||
|
transform_deep_layer (deep_layer (), t);
|
||||||
|
invalidate_bbox ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeepEdges::do_transform (const db::ICplxTrans &t)
|
||||||
|
{
|
||||||
|
transform_deep_layer (deep_layer (), t);
|
||||||
|
invalidate_bbox ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeepEdges::do_transform (const db::IMatrix2d &t)
|
||||||
|
{
|
||||||
|
transform_deep_layer (deep_layer (), t);
|
||||||
|
invalidate_bbox ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeepEdges::do_transform (const db::IMatrix3d &t)
|
||||||
|
{
|
||||||
|
transform_deep_layer (deep_layer (), t);
|
||||||
|
invalidate_bbox ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeepEdges::reserve (size_t)
|
||||||
|
{
|
||||||
|
// Not implemented for deep regions
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeepEdges::flatten ()
|
||||||
|
{
|
||||||
|
db::Layout &layout = deep_layer ().layout ();
|
||||||
|
if (layout.begin_top_down () != layout.end_top_down ()) {
|
||||||
|
|
||||||
|
db::Cell &top_cell = layout.cell (*layout.begin_top_down ());
|
||||||
|
|
||||||
|
db::Shapes flat_shapes (layout.is_editable ());
|
||||||
|
for (db::RecursiveShapeIterator iter (layout, top_cell, deep_layer ().layer ()); !iter.at_end (); ++iter) {
|
||||||
|
flat_shapes.insert (iter->edge ().transformed (iter.trans ()));
|
||||||
|
}
|
||||||
|
|
||||||
|
layout.clear_layer (deep_layer ().layer ());
|
||||||
|
top_cell.shapes (deep_layer ().layer ()).swap (flat_shapes);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
EdgesIteratorDelegate *
|
EdgesIteratorDelegate *
|
||||||
DeepEdges::begin () const
|
DeepEdges::begin () const
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@
|
||||||
|
|
||||||
#include "dbCommon.h"
|
#include "dbCommon.h"
|
||||||
|
|
||||||
#include "dbAsIfFlatEdges.h"
|
#include "dbMutableEdges.h"
|
||||||
#include "dbDeepShapeStore.h"
|
#include "dbDeepShapeStore.h"
|
||||||
#include "dbEdgeBoolean.h"
|
#include "dbEdgeBoolean.h"
|
||||||
#include "dbEdgePairs.h"
|
#include "dbEdgePairs.h"
|
||||||
|
|
@ -40,7 +40,7 @@ class DeepRegion;
|
||||||
* @brief Provides hierarchical edges implementation
|
* @brief Provides hierarchical edges implementation
|
||||||
*/
|
*/
|
||||||
class DB_PUBLIC DeepEdges
|
class DB_PUBLIC DeepEdges
|
||||||
: public db::AsIfFlatEdges, public db::DeepShapeCollectionDelegateBase
|
: public db::MutableEdges, public db::DeepShapeCollectionDelegateBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DeepEdges ();
|
DeepEdges ();
|
||||||
|
|
@ -53,6 +53,17 @@ public:
|
||||||
|
|
||||||
virtual ~DeepEdges ();
|
virtual ~DeepEdges ();
|
||||||
|
|
||||||
|
virtual void do_transform (const db::Trans &t);
|
||||||
|
virtual void do_transform (const db::ICplxTrans &t);
|
||||||
|
virtual void do_transform (const db::IMatrix2d &t);
|
||||||
|
virtual void do_transform (const db::IMatrix3d &t);
|
||||||
|
|
||||||
|
virtual void flatten ();
|
||||||
|
|
||||||
|
virtual void reserve (size_t n);
|
||||||
|
|
||||||
|
virtual void do_insert (const db::Edge &edge);
|
||||||
|
|
||||||
EdgesDelegate *clone () const;
|
EdgesDelegate *clone () const;
|
||||||
|
|
||||||
virtual EdgesIteratorDelegate *begin () const;
|
virtual EdgesIteratorDelegate *begin () const;
|
||||||
|
|
|
||||||
|
|
@ -127,14 +127,14 @@ private:
|
||||||
// DeepRegion implementation
|
// DeepRegion implementation
|
||||||
|
|
||||||
DeepRegion::DeepRegion (const RecursiveShapeIterator &si, DeepShapeStore &dss, double area_ratio, size_t max_vertex_count)
|
DeepRegion::DeepRegion (const RecursiveShapeIterator &si, DeepShapeStore &dss, double area_ratio, size_t max_vertex_count)
|
||||||
: AsIfFlatRegion (), m_merged_polygons ()
|
: MutableRegion (), m_merged_polygons ()
|
||||||
{
|
{
|
||||||
set_deep_layer (dss.create_polygon_layer (si, area_ratio, max_vertex_count));
|
set_deep_layer (dss.create_polygon_layer (si, area_ratio, max_vertex_count));
|
||||||
init ();
|
init ();
|
||||||
}
|
}
|
||||||
|
|
||||||
DeepRegion::DeepRegion (const RecursiveShapeIterator &si, DeepShapeStore &dss, const db::ICplxTrans &trans, bool merged_semantics, double area_ratio, size_t max_vertex_count)
|
DeepRegion::DeepRegion (const RecursiveShapeIterator &si, DeepShapeStore &dss, const db::ICplxTrans &trans, bool merged_semantics, double area_ratio, size_t max_vertex_count)
|
||||||
: AsIfFlatRegion (), m_merged_polygons ()
|
: MutableRegion (), m_merged_polygons ()
|
||||||
{
|
{
|
||||||
set_deep_layer (dss.create_polygon_layer (si, area_ratio, max_vertex_count, trans));
|
set_deep_layer (dss.create_polygon_layer (si, area_ratio, max_vertex_count, trans));
|
||||||
init ();
|
init ();
|
||||||
|
|
@ -142,7 +142,7 @@ DeepRegion::DeepRegion (const RecursiveShapeIterator &si, DeepShapeStore &dss, c
|
||||||
}
|
}
|
||||||
|
|
||||||
DeepRegion::DeepRegion (const db::Region &other, DeepShapeStore &dss)
|
DeepRegion::DeepRegion (const db::Region &other, DeepShapeStore &dss)
|
||||||
: AsIfFlatRegion (), m_merged_polygons ()
|
: MutableRegion (), m_merged_polygons ()
|
||||||
{
|
{
|
||||||
set_deep_layer (dss.create_from_flat (other, false));
|
set_deep_layer (dss.create_from_flat (other, false));
|
||||||
|
|
||||||
|
|
@ -151,13 +151,13 @@ DeepRegion::DeepRegion (const db::Region &other, DeepShapeStore &dss)
|
||||||
}
|
}
|
||||||
|
|
||||||
DeepRegion::DeepRegion ()
|
DeepRegion::DeepRegion ()
|
||||||
: AsIfFlatRegion ()
|
: MutableRegion ()
|
||||||
{
|
{
|
||||||
init ();
|
init ();
|
||||||
}
|
}
|
||||||
|
|
||||||
DeepRegion::DeepRegion (const DeepLayer &dl)
|
DeepRegion::DeepRegion (const DeepLayer &dl)
|
||||||
: AsIfFlatRegion ()
|
: MutableRegion ()
|
||||||
{
|
{
|
||||||
set_deep_layer (dl);
|
set_deep_layer (dl);
|
||||||
init ();
|
init ();
|
||||||
|
|
@ -169,7 +169,7 @@ DeepRegion::~DeepRegion ()
|
||||||
}
|
}
|
||||||
|
|
||||||
DeepRegion::DeepRegion (const DeepRegion &other)
|
DeepRegion::DeepRegion (const DeepRegion &other)
|
||||||
: AsIfFlatRegion (other), DeepShapeCollectionDelegateBase (other),
|
: MutableRegion (other), DeepShapeCollectionDelegateBase (other),
|
||||||
m_merged_polygons_valid (other.m_merged_polygons_valid),
|
m_merged_polygons_valid (other.m_merged_polygons_valid),
|
||||||
m_is_merged (other.m_is_merged)
|
m_is_merged (other.m_is_merged)
|
||||||
{
|
{
|
||||||
|
|
@ -220,6 +220,90 @@ void DeepRegion::min_coherence_changed ()
|
||||||
set_is_merged (false);
|
set_is_merged (false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DeepRegion::do_insert (const db::Polygon &polygon)
|
||||||
|
{
|
||||||
|
db::Layout &layout = deep_layer ().layout ();
|
||||||
|
if (layout.begin_top_down () != layout.end_top_down ()) {
|
||||||
|
db::Cell &top_cell = layout.cell (*layout.begin_top_down ());
|
||||||
|
top_cell.shapes (deep_layer ().layer ()).insert (db::PolygonRef (polygon, layout.shape_repository ()));
|
||||||
|
}
|
||||||
|
|
||||||
|
invalidate_bbox ();
|
||||||
|
set_is_merged (false);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Trans>
|
||||||
|
static void transform_deep_layer (db::DeepLayer &deep_layer, const Trans &t)
|
||||||
|
{
|
||||||
|
// TODO: this is a pretty cheap implementation. At least a plain move can be done with orientation variants.
|
||||||
|
|
||||||
|
db::Layout &layout = deep_layer.layout ();
|
||||||
|
if (layout.begin_top_down () != layout.end_top_down ()) {
|
||||||
|
|
||||||
|
db::Cell &top_cell = layout.cell (*layout.begin_top_down ());
|
||||||
|
|
||||||
|
db::Shapes flat_shapes (layout.is_editable ());
|
||||||
|
for (db::RecursiveShapeIterator iter (layout, top_cell, deep_layer.layer ()); !iter.at_end (); ++iter) {
|
||||||
|
db::Polygon poly;
|
||||||
|
iter->polygon (poly);
|
||||||
|
flat_shapes.insert (poly.transformed (iter.trans ()).transformed (t));
|
||||||
|
}
|
||||||
|
|
||||||
|
layout.clear_layer (deep_layer.layer ());
|
||||||
|
top_cell.shapes (deep_layer.layer ()).swap (flat_shapes);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeepRegion::do_transform (const db::Trans &t)
|
||||||
|
{
|
||||||
|
transform_deep_layer (deep_layer (), t);
|
||||||
|
invalidate_bbox ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeepRegion::do_transform (const db::ICplxTrans &t)
|
||||||
|
{
|
||||||
|
transform_deep_layer (deep_layer (), t);
|
||||||
|
invalidate_bbox ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeepRegion::do_transform (const db::IMatrix2d &t)
|
||||||
|
{
|
||||||
|
transform_deep_layer (deep_layer (), t);
|
||||||
|
invalidate_bbox ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeepRegion::do_transform (const db::IMatrix3d &t)
|
||||||
|
{
|
||||||
|
transform_deep_layer (deep_layer (), t);
|
||||||
|
invalidate_bbox ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeepRegion::reserve (size_t)
|
||||||
|
{
|
||||||
|
// Not implemented for deep regions
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeepRegion::flatten ()
|
||||||
|
{
|
||||||
|
db::Layout &layout = deep_layer ().layout ();
|
||||||
|
if (layout.begin_top_down () != layout.end_top_down ()) {
|
||||||
|
|
||||||
|
db::Cell &top_cell = layout.cell (*layout.begin_top_down ());
|
||||||
|
|
||||||
|
db::Shapes flat_shapes (layout.is_editable ());
|
||||||
|
for (db::RecursiveShapeIterator iter (layout, top_cell, deep_layer ().layer ()); !iter.at_end (); ++iter) {
|
||||||
|
db::Polygon poly;
|
||||||
|
iter->polygon (poly);
|
||||||
|
flat_shapes.insert (poly.transformed (iter.trans ()));
|
||||||
|
}
|
||||||
|
|
||||||
|
layout.clear_layer (deep_layer ().layer ());
|
||||||
|
top_cell.shapes (deep_layer ().layer ()).swap (flat_shapes);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
RegionIteratorDelegate *
|
RegionIteratorDelegate *
|
||||||
DeepRegion::begin () const
|
DeepRegion::begin () const
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@
|
||||||
|
|
||||||
#include "dbCommon.h"
|
#include "dbCommon.h"
|
||||||
|
|
||||||
#include "dbAsIfFlatRegion.h"
|
#include "dbMutableRegion.h"
|
||||||
#include "dbDeepShapeStore.h"
|
#include "dbDeepShapeStore.h"
|
||||||
|
|
||||||
namespace db {
|
namespace db {
|
||||||
|
|
@ -35,7 +35,7 @@ namespace db {
|
||||||
* @brief A deep, polygon-set delegate
|
* @brief A deep, polygon-set delegate
|
||||||
*/
|
*/
|
||||||
class DB_PUBLIC DeepRegion
|
class DB_PUBLIC DeepRegion
|
||||||
: public AsIfFlatRegion, public DeepShapeCollectionDelegateBase
|
: public MutableRegion, public DeepShapeCollectionDelegateBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef db::layer<db::Polygon, db::unstable_layer_tag> polygon_layer_type;
|
typedef db::layer<db::Polygon, db::unstable_layer_tag> polygon_layer_type;
|
||||||
|
|
@ -53,6 +53,17 @@ public:
|
||||||
|
|
||||||
RegionDelegate *clone () const;
|
RegionDelegate *clone () const;
|
||||||
|
|
||||||
|
virtual void do_insert (const db::Polygon &polygon);
|
||||||
|
|
||||||
|
virtual void do_transform (const db::Trans &t);
|
||||||
|
virtual void do_transform (const db::ICplxTrans &t);
|
||||||
|
virtual void do_transform (const db::IMatrix2d &t);
|
||||||
|
virtual void do_transform (const db::IMatrix3d &t);
|
||||||
|
|
||||||
|
virtual void flatten ();
|
||||||
|
|
||||||
|
virtual void reserve (size_t);
|
||||||
|
|
||||||
virtual RegionIteratorDelegate *begin () const;
|
virtual RegionIteratorDelegate *begin () const;
|
||||||
virtual RegionIteratorDelegate *begin_merged () const;
|
virtual RegionIteratorDelegate *begin_merged () const;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -399,6 +399,18 @@ DeepShapeStoreState::max_vertex_count () const
|
||||||
|
|
||||||
static size_t s_instance_count = 0;
|
static size_t s_instance_count = 0;
|
||||||
|
|
||||||
|
static unsigned int init_layer (db::Layout &layout, const db::RecursiveShapeIterator &si)
|
||||||
|
{
|
||||||
|
unsigned int layer_index = layout.insert_layer ();
|
||||||
|
|
||||||
|
if (si.layout () && si.layer () < si.layout ()->layers ()) {
|
||||||
|
// try to preserve the layer properties
|
||||||
|
layout.set_properties (layer_index, si.layout ()->get_properties (si.layer ()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return layer_index;
|
||||||
|
}
|
||||||
|
|
||||||
DeepShapeStore::DeepShapeStore ()
|
DeepShapeStore::DeepShapeStore ()
|
||||||
{
|
{
|
||||||
++s_instance_count;
|
++s_instance_count;
|
||||||
|
|
@ -433,7 +445,9 @@ DeepLayer DeepShapeStore::create_from_flat (const db::Region ®ion, bool for_n
|
||||||
|
|
||||||
require_singular ();
|
require_singular ();
|
||||||
|
|
||||||
unsigned int layer = layout ().insert_layer ();
|
unsigned int layer = init_layer (layout (), region.iter ());
|
||||||
|
|
||||||
|
// attempt to initialize the layer properties
|
||||||
|
|
||||||
if (max_area_ratio == 0.0) {
|
if (max_area_ratio == 0.0) {
|
||||||
max_area_ratio = m_state.max_area_ratio ();
|
max_area_ratio = m_state.max_area_ratio ();
|
||||||
|
|
@ -480,7 +494,7 @@ DeepLayer DeepShapeStore::create_from_flat (const db::Edges &edges, const db::IC
|
||||||
|
|
||||||
require_singular ();
|
require_singular ();
|
||||||
|
|
||||||
unsigned int layer = layout ().insert_layer ();
|
unsigned int layer = init_layer (layout (), edges.iter ());
|
||||||
|
|
||||||
db::Shapes *shapes = &initial_cell ().shapes (layer);
|
db::Shapes *shapes = &initial_cell ().shapes (layer);
|
||||||
db::Box world = db::Box::world ();
|
db::Box world = db::Box::world ();
|
||||||
|
|
@ -510,7 +524,7 @@ DeepLayer DeepShapeStore::create_from_flat (const db::Texts &texts, const db::IC
|
||||||
|
|
||||||
require_singular ();
|
require_singular ();
|
||||||
|
|
||||||
unsigned int layer = layout ().insert_layer ();
|
unsigned int layer = init_layer (layout (), texts.iter ());
|
||||||
|
|
||||||
db::Shapes *shapes = &initial_cell ().shapes (layer);
|
db::Shapes *shapes = &initial_cell ().shapes (layer);
|
||||||
db::Box world = db::Box::world ();
|
db::Box world = db::Box::world ();
|
||||||
|
|
@ -780,18 +794,6 @@ void DeepShapeStore::make_layout (unsigned int layout_index, const db::Recursive
|
||||||
m_layout_map[std::make_pair (si, trans)] = layout_index;
|
m_layout_map[std::make_pair (si, trans)] = layout_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int init_layer (db::Layout &layout, const db::RecursiveShapeIterator &si)
|
|
||||||
{
|
|
||||||
unsigned int layer_index = layout.insert_layer ();
|
|
||||||
|
|
||||||
if (si.layout () && si.layer () < si.layout ()->layers ()) {
|
|
||||||
// try to preserve the layer properties
|
|
||||||
layout.set_properties (layer_index, si.layout ()->get_properties (si.layer ()));
|
|
||||||
}
|
|
||||||
|
|
||||||
return layer_index;
|
|
||||||
}
|
|
||||||
|
|
||||||
DeepLayer DeepShapeStore::create_polygon_layer (const db::RecursiveShapeIterator &si, double max_area_ratio, size_t max_vertex_count, const db::ICplxTrans &trans)
|
DeepLayer DeepShapeStore::create_polygon_layer (const db::RecursiveShapeIterator &si, double max_area_ratio, size_t max_vertex_count, const db::ICplxTrans &trans)
|
||||||
{
|
{
|
||||||
if (max_area_ratio == 0.0) {
|
if (max_area_ratio == 0.0) {
|
||||||
|
|
|
||||||
|
|
@ -116,31 +116,31 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
DeepTexts::DeepTexts ()
|
DeepTexts::DeepTexts ()
|
||||||
: AsIfFlatTexts ()
|
: MutableTexts ()
|
||||||
{
|
{
|
||||||
// .. nothing yet ..
|
// .. nothing yet ..
|
||||||
}
|
}
|
||||||
|
|
||||||
DeepTexts::DeepTexts (const db::Texts &other, DeepShapeStore &dss)
|
DeepTexts::DeepTexts (const db::Texts &other, DeepShapeStore &dss)
|
||||||
: AsIfFlatTexts ()
|
: MutableTexts ()
|
||||||
{
|
{
|
||||||
set_deep_layer (dss.create_from_flat (other));
|
set_deep_layer (dss.create_from_flat (other));
|
||||||
}
|
}
|
||||||
|
|
||||||
DeepTexts::DeepTexts (const RecursiveShapeIterator &si, DeepShapeStore &dss)
|
DeepTexts::DeepTexts (const RecursiveShapeIterator &si, DeepShapeStore &dss)
|
||||||
: AsIfFlatTexts ()
|
: MutableTexts ()
|
||||||
{
|
{
|
||||||
set_deep_layer (dss.create_text_layer (si));
|
set_deep_layer (dss.create_text_layer (si));
|
||||||
}
|
}
|
||||||
|
|
||||||
DeepTexts::DeepTexts (const RecursiveShapeIterator &si, DeepShapeStore &dss, const db::ICplxTrans &trans)
|
DeepTexts::DeepTexts (const RecursiveShapeIterator &si, DeepShapeStore &dss, const db::ICplxTrans &trans)
|
||||||
: AsIfFlatTexts ()
|
: MutableTexts ()
|
||||||
{
|
{
|
||||||
set_deep_layer (dss.create_text_layer (si, trans));
|
set_deep_layer (dss.create_text_layer (si, trans));
|
||||||
}
|
}
|
||||||
|
|
||||||
DeepTexts::DeepTexts (const DeepTexts &other)
|
DeepTexts::DeepTexts (const DeepTexts &other)
|
||||||
: AsIfFlatTexts (other), DeepShapeCollectionDelegateBase (other)
|
: MutableTexts (other), DeepShapeCollectionDelegateBase (other)
|
||||||
{
|
{
|
||||||
// .. nothing yet ..
|
// .. nothing yet ..
|
||||||
}
|
}
|
||||||
|
|
@ -156,7 +156,7 @@ DeepTexts::operator= (const DeepTexts &other)
|
||||||
}
|
}
|
||||||
|
|
||||||
DeepTexts::DeepTexts (const DeepLayer &dl)
|
DeepTexts::DeepTexts (const DeepLayer &dl)
|
||||||
: AsIfFlatTexts ()
|
: MutableTexts ()
|
||||||
{
|
{
|
||||||
set_deep_layer (dl);
|
set_deep_layer (dl);
|
||||||
}
|
}
|
||||||
|
|
@ -171,6 +171,90 @@ TextsDelegate *DeepTexts::clone () const
|
||||||
return new DeepTexts (*this);
|
return new DeepTexts (*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DeepTexts::do_insert (const db::Text &text)
|
||||||
|
{
|
||||||
|
db::Layout &layout = deep_layer ().layout ();
|
||||||
|
if (layout.begin_top_down () != layout.end_top_down ()) {
|
||||||
|
db::Cell &top_cell = layout.cell (*layout.begin_top_down ());
|
||||||
|
top_cell.shapes (deep_layer ().layer ()).insert (db::TextRef (text, layout.shape_repository ()));
|
||||||
|
}
|
||||||
|
|
||||||
|
invalidate_bbox ();
|
||||||
|
set_is_merged (false);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Trans>
|
||||||
|
static void transform_deep_layer (db::DeepLayer &deep_layer, const Trans &t)
|
||||||
|
{
|
||||||
|
// TODO: this is a pretty cheap implementation. At least a plain move can be done with orientation variants.
|
||||||
|
|
||||||
|
db::Layout &layout = deep_layer.layout ();
|
||||||
|
if (layout.begin_top_down () != layout.end_top_down ()) {
|
||||||
|
|
||||||
|
db::Cell &top_cell = layout.cell (*layout.begin_top_down ());
|
||||||
|
|
||||||
|
db::Shapes flat_shapes (layout.is_editable ());
|
||||||
|
for (db::RecursiveShapeIterator iter (layout, top_cell, deep_layer.layer ()); !iter.at_end (); ++iter) {
|
||||||
|
db::Text text;
|
||||||
|
iter->text (text);
|
||||||
|
flat_shapes.insert (text.transformed (iter.trans ()).transformed (t));
|
||||||
|
}
|
||||||
|
|
||||||
|
layout.clear_layer (deep_layer.layer ());
|
||||||
|
top_cell.shapes (deep_layer.layer ()).swap (flat_shapes);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeepTexts::do_transform (const db::Trans &t)
|
||||||
|
{
|
||||||
|
transform_deep_layer (deep_layer (), t);
|
||||||
|
invalidate_bbox ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeepTexts::do_transform (const db::ICplxTrans &t)
|
||||||
|
{
|
||||||
|
transform_deep_layer (deep_layer (), t);
|
||||||
|
invalidate_bbox ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeepTexts::do_transform (const db::IMatrix2d &t)
|
||||||
|
{
|
||||||
|
transform_deep_layer (deep_layer (), t);
|
||||||
|
invalidate_bbox ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeepTexts::do_transform (const db::IMatrix3d &t)
|
||||||
|
{
|
||||||
|
transform_deep_layer (deep_layer (), t);
|
||||||
|
invalidate_bbox ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeepTexts::reserve (size_t)
|
||||||
|
{
|
||||||
|
// Not implemented for deep regions
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeepTexts::flatten ()
|
||||||
|
{
|
||||||
|
db::Layout &layout = deep_layer ().layout ();
|
||||||
|
if (layout.begin_top_down () != layout.end_top_down ()) {
|
||||||
|
|
||||||
|
db::Cell &top_cell = layout.cell (*layout.begin_top_down ());
|
||||||
|
|
||||||
|
db::Shapes flat_shapes (layout.is_editable ());
|
||||||
|
for (db::RecursiveShapeIterator iter (layout, top_cell, deep_layer ().layer ()); !iter.at_end (); ++iter) {
|
||||||
|
db::Text text;
|
||||||
|
iter->text (text);
|
||||||
|
flat_shapes.insert (db::TextRef (text.transformed (iter.trans ()), layout.shape_repository ()));
|
||||||
|
}
|
||||||
|
|
||||||
|
layout.clear_layer (deep_layer ().layer ());
|
||||||
|
top_cell.shapes (deep_layer ().layer ()).swap (flat_shapes);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TextsIteratorDelegate *DeepTexts::begin () const
|
TextsIteratorDelegate *DeepTexts::begin () const
|
||||||
{
|
{
|
||||||
return new DeepTextsIterator (begin_iter ().first);
|
return new DeepTextsIterator (begin_iter ().first);
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@
|
||||||
|
|
||||||
#include "dbCommon.h"
|
#include "dbCommon.h"
|
||||||
|
|
||||||
#include "dbAsIfFlatTexts.h"
|
#include "dbMutableTexts.h"
|
||||||
#include "dbDeepShapeStore.h"
|
#include "dbDeepShapeStore.h"
|
||||||
#include "dbTexts.h"
|
#include "dbTexts.h"
|
||||||
|
|
||||||
|
|
@ -36,7 +36,7 @@ namespace db {
|
||||||
* @brief Provides hierarchical edges implementation
|
* @brief Provides hierarchical edges implementation
|
||||||
*/
|
*/
|
||||||
class DB_PUBLIC DeepTexts
|
class DB_PUBLIC DeepTexts
|
||||||
: public db::AsIfFlatTexts, public db::DeepShapeCollectionDelegateBase
|
: public db::MutableTexts, public db::DeepShapeCollectionDelegateBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DeepTexts ();
|
DeepTexts ();
|
||||||
|
|
@ -51,6 +51,17 @@ public:
|
||||||
|
|
||||||
TextsDelegate *clone () const;
|
TextsDelegate *clone () const;
|
||||||
|
|
||||||
|
virtual void do_insert (const db::Text &text);
|
||||||
|
|
||||||
|
virtual void do_transform (const db::Trans &t);
|
||||||
|
virtual void do_transform (const db::ICplxTrans &t);
|
||||||
|
virtual void do_transform (const db::IMatrix2d &t);
|
||||||
|
virtual void do_transform (const db::IMatrix3d &t);
|
||||||
|
|
||||||
|
virtual void flatten ();
|
||||||
|
|
||||||
|
virtual void reserve (size_t n);
|
||||||
|
|
||||||
virtual TextsIteratorDelegate *begin () const;
|
virtual TextsIteratorDelegate *begin () const;
|
||||||
virtual std::pair<db::RecursiveShapeIterator, db::ICplxTrans> begin_iter () const;
|
virtual std::pair<db::RecursiveShapeIterator, db::ICplxTrans> begin_iter () const;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -93,20 +93,20 @@ EdgePairs::EdgePairs (const RecursiveShapeIterator &si, DeepShapeStore &dss, con
|
||||||
template <class Sh>
|
template <class Sh>
|
||||||
void EdgePairs::insert (const Sh &shape)
|
void EdgePairs::insert (const Sh &shape)
|
||||||
{
|
{
|
||||||
flat_edge_pairs ()->insert (shape);
|
mutable_edge_pairs ()->insert (shape);
|
||||||
}
|
}
|
||||||
|
|
||||||
template DB_PUBLIC void EdgePairs::insert (const db::EdgePair &);
|
template DB_PUBLIC void EdgePairs::insert (const db::EdgePair &);
|
||||||
|
|
||||||
void EdgePairs::insert (const db::Shape &shape)
|
void EdgePairs::insert (const db::Shape &shape)
|
||||||
{
|
{
|
||||||
flat_edge_pairs ()->insert (shape);
|
mutable_edge_pairs ()->insert (shape);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
void EdgePairs::insert (const db::Shape &shape, const T &trans)
|
void EdgePairs::insert (const db::Shape &shape, const T &trans)
|
||||||
{
|
{
|
||||||
flat_edge_pairs ()->insert (shape, trans);
|
mutable_edge_pairs ()->insert (shape, trans);
|
||||||
}
|
}
|
||||||
|
|
||||||
template DB_PUBLIC void EdgePairs::insert (const db::Shape &, const db::ICplxTrans &);
|
template DB_PUBLIC void EdgePairs::insert (const db::Shape &, const db::ICplxTrans &);
|
||||||
|
|
@ -120,13 +120,18 @@ void EdgePairs::clear ()
|
||||||
|
|
||||||
void EdgePairs::reserve (size_t n)
|
void EdgePairs::reserve (size_t n)
|
||||||
{
|
{
|
||||||
flat_edge_pairs ()->reserve (n);
|
mutable_edge_pairs ()->reserve (n);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EdgePairs::flatten ()
|
||||||
|
{
|
||||||
|
mutable_edge_pairs ()->flatten ();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
EdgePairs &EdgePairs::transform (const T &trans)
|
EdgePairs &EdgePairs::transform (const T &trans)
|
||||||
{
|
{
|
||||||
flat_edge_pairs ()->transform (trans);
|
mutable_edge_pairs ()->transform (trans);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -183,9 +188,9 @@ void EdgePairs::set_delegate (EdgePairsDelegate *delegate)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FlatEdgePairs *EdgePairs::flat_edge_pairs ()
|
MutableEdgePairs *EdgePairs::mutable_edge_pairs ()
|
||||||
{
|
{
|
||||||
FlatEdgePairs *edge_pairs = dynamic_cast<FlatEdgePairs *> (mp_delegate);
|
MutableEdgePairs *edge_pairs = dynamic_cast<MutableEdgePairs *> (mp_delegate);
|
||||||
if (! edge_pairs) {
|
if (! edge_pairs) {
|
||||||
edge_pairs = new FlatEdgePairs ();
|
edge_pairs = new FlatEdgePairs ();
|
||||||
if (mp_delegate) {
|
if (mp_delegate) {
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ namespace db
|
||||||
{
|
{
|
||||||
|
|
||||||
class EdgePairFilterBase;
|
class EdgePairFilterBase;
|
||||||
class FlatEdgePairs;
|
class MutableEdgePairs;
|
||||||
class EmptyEdgePairs;
|
class EmptyEdgePairs;
|
||||||
class Edges;
|
class Edges;
|
||||||
class Region;
|
class Region;
|
||||||
|
|
@ -469,10 +469,7 @@ public:
|
||||||
*
|
*
|
||||||
* This method will turn any edge pair collection into a flat one.
|
* This method will turn any edge pair collection into a flat one.
|
||||||
*/
|
*/
|
||||||
void flatten ()
|
void flatten ();
|
||||||
{
|
|
||||||
flat_edge_pairs ();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns true, if the edge pair set has valid edges stored within itself
|
* @brief Returns true, if the edge pair set has valid edges stored within itself
|
||||||
|
|
@ -615,7 +612,7 @@ private:
|
||||||
EdgePairsDelegate *mp_delegate;
|
EdgePairsDelegate *mp_delegate;
|
||||||
|
|
||||||
void set_delegate (EdgePairsDelegate *delegate);
|
void set_delegate (EdgePairsDelegate *delegate);
|
||||||
FlatEdgePairs *flat_edge_pairs ();
|
MutableEdgePairs *mutable_edge_pairs ();
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@
|
||||||
#include "dbDeepEdges.h"
|
#include "dbDeepEdges.h"
|
||||||
#include "dbOriginalLayerEdges.h"
|
#include "dbOriginalLayerEdges.h"
|
||||||
#include "dbEmptyEdges.h"
|
#include "dbEmptyEdges.h"
|
||||||
|
#include "dbMutableEdges.h"
|
||||||
#include "dbFlatEdges.h"
|
#include "dbFlatEdges.h"
|
||||||
#include "dbEdgesUtils.h"
|
#include "dbEdgesUtils.h"
|
||||||
#include "dbRegion.h"
|
#include "dbRegion.h"
|
||||||
|
|
@ -133,7 +134,7 @@ Edges::clear ()
|
||||||
void
|
void
|
||||||
Edges::reserve (size_t n)
|
Edges::reserve (size_t n)
|
||||||
{
|
{
|
||||||
flat_edges ()->reserve (n);
|
mutable_edges ()->reserve (n);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Edges::processed (Region &output, const EdgeToPolygonProcessorBase &filter) const
|
void Edges::processed (Region &output, const EdgeToPolygonProcessorBase &filter) const
|
||||||
|
|
@ -166,10 +167,16 @@ Edges Edges::centers (length_type length, double fraction) const
|
||||||
return Edges (mp_delegate->processed (EdgeSegmentSelector (0, length, fraction)));
|
return Edges (mp_delegate->processed (EdgeSegmentSelector (0, length, fraction)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Edges::flatten ()
|
||||||
|
{
|
||||||
|
mutable_edges ()->flatten ();
|
||||||
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
Edges &Edges::transform (const T &trans)
|
Edges &Edges::transform (const T &trans)
|
||||||
{
|
{
|
||||||
flat_edges ()->transform (trans);
|
mutable_edges ()->transform (trans);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -183,7 +190,7 @@ template DB_PUBLIC Edges &Edges::transform (const db::IMatrix3d &);
|
||||||
template <class Sh>
|
template <class Sh>
|
||||||
void Edges::insert (const Sh &shape)
|
void Edges::insert (const Sh &shape)
|
||||||
{
|
{
|
||||||
flat_edges ()->insert (shape);
|
mutable_edges ()->insert (shape);
|
||||||
}
|
}
|
||||||
|
|
||||||
template DB_PUBLIC void Edges::insert (const db::Box &);
|
template DB_PUBLIC void Edges::insert (const db::Box &);
|
||||||
|
|
@ -194,24 +201,25 @@ template DB_PUBLIC void Edges::insert (const db::Edge &);
|
||||||
|
|
||||||
void Edges::insert (const db::Shape &shape)
|
void Edges::insert (const db::Shape &shape)
|
||||||
{
|
{
|
||||||
flat_edges ()->insert (shape);
|
mutable_edges ()->insert (shape);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
void Edges::insert (const db::Shape &shape, const T &trans)
|
void Edges::insert (const db::Shape &shape, const T &trans)
|
||||||
{
|
{
|
||||||
flat_edges ()->insert (shape, trans);
|
mutable_edges ()->insert (shape, trans);
|
||||||
}
|
}
|
||||||
|
|
||||||
template DB_PUBLIC void Edges::insert (const db::Shape &, const db::ICplxTrans &);
|
template DB_PUBLIC void Edges::insert (const db::Shape &, const db::ICplxTrans &);
|
||||||
template DB_PUBLIC void Edges::insert (const db::Shape &, const db::Trans &);
|
template DB_PUBLIC void Edges::insert (const db::Shape &, const db::Trans &);
|
||||||
template DB_PUBLIC void Edges::insert (const db::Shape &, const db::Disp &);
|
template DB_PUBLIC void Edges::insert (const db::Shape &, const db::Disp &);
|
||||||
|
|
||||||
FlatEdges *
|
MutableEdges *
|
||||||
Edges::flat_edges ()
|
Edges::mutable_edges ()
|
||||||
{
|
{
|
||||||
FlatEdges *edges = dynamic_cast<FlatEdges *> (mp_delegate);
|
MutableEdges *edges = dynamic_cast<MutableEdges *> (mp_delegate);
|
||||||
if (! edges) {
|
if (! edges) {
|
||||||
|
|
||||||
edges = new FlatEdges ();
|
edges = new FlatEdges ();
|
||||||
if (mp_delegate) {
|
if (mp_delegate) {
|
||||||
edges->EdgesDelegate::operator= (*mp_delegate);
|
edges->EdgesDelegate::operator= (*mp_delegate);
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@
|
||||||
namespace db {
|
namespace db {
|
||||||
|
|
||||||
class EdgeFilterBase;
|
class EdgeFilterBase;
|
||||||
class FlatEdges;
|
class MutableEdges;
|
||||||
class EmptyEdges;
|
class EmptyEdges;
|
||||||
class DeepShapeStore;
|
class DeepShapeStore;
|
||||||
|
|
||||||
|
|
@ -1112,10 +1112,7 @@ public:
|
||||||
*
|
*
|
||||||
* This method will turn any edge collection into a flat one.
|
* This method will turn any edge collection into a flat one.
|
||||||
*/
|
*/
|
||||||
void flatten ()
|
void flatten ();
|
||||||
{
|
|
||||||
flat_edges ();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns true, if the edge set has valid edges stored within itself
|
* @brief Returns true, if the edge set has valid edges stored within itself
|
||||||
|
|
@ -1208,7 +1205,7 @@ private:
|
||||||
EdgesDelegate *mp_delegate;
|
EdgesDelegate *mp_delegate;
|
||||||
|
|
||||||
void set_delegate (EdgesDelegate *delegate, bool keep_attributes = true);
|
void set_delegate (EdgesDelegate *delegate, bool keep_attributes = true);
|
||||||
FlatEdges *flat_edges ();
|
MutableEdges *mutable_edges();
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace db
|
} // namespace db
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ namespace db
|
||||||
// FlatEdgePairs implementation
|
// FlatEdgePairs implementation
|
||||||
|
|
||||||
FlatEdgePairs::FlatEdgePairs ()
|
FlatEdgePairs::FlatEdgePairs ()
|
||||||
: AsIfFlatEdgePairs (), mp_edge_pairs (new db::Shapes (false))
|
: MutableEdgePairs (), mp_edge_pairs (new db::Shapes (false))
|
||||||
{
|
{
|
||||||
// .. nothing yet ..
|
// .. nothing yet ..
|
||||||
}
|
}
|
||||||
|
|
@ -43,13 +43,13 @@ FlatEdgePairs::~FlatEdgePairs ()
|
||||||
}
|
}
|
||||||
|
|
||||||
FlatEdgePairs::FlatEdgePairs (const FlatEdgePairs &other)
|
FlatEdgePairs::FlatEdgePairs (const FlatEdgePairs &other)
|
||||||
: AsIfFlatEdgePairs (other), mp_edge_pairs (other.mp_edge_pairs)
|
: MutableEdgePairs (other), mp_edge_pairs (other.mp_edge_pairs)
|
||||||
{
|
{
|
||||||
// .. nothing yet ..
|
// .. nothing yet ..
|
||||||
}
|
}
|
||||||
|
|
||||||
FlatEdgePairs::FlatEdgePairs (const db::Shapes &edge_pairs)
|
FlatEdgePairs::FlatEdgePairs (const db::Shapes &edge_pairs)
|
||||||
: AsIfFlatEdgePairs (), mp_edge_pairs (new db::Shapes (edge_pairs))
|
: MutableEdgePairs (), mp_edge_pairs (new db::Shapes (edge_pairs))
|
||||||
{
|
{
|
||||||
// .. nothing yet ..
|
// .. nothing yet ..
|
||||||
}
|
}
|
||||||
|
|
@ -205,23 +205,11 @@ FlatEdgePairs::insert_into (Layout *layout, db::cell_index_type into_cell, unsig
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
FlatEdgePairs::insert (const db::EdgePair &ep)
|
FlatEdgePairs::do_insert (const db::EdgePair &ep)
|
||||||
{
|
{
|
||||||
mp_edge_pairs->insert (ep);
|
mp_edge_pairs->insert (ep);
|
||||||
invalidate_cache ();
|
invalidate_cache ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
FlatEdgePairs::insert (const db::Shape &shape)
|
|
||||||
{
|
|
||||||
if (shape.is_edge_pair ()) {
|
|
||||||
|
|
||||||
db::EdgePair ep;
|
|
||||||
shape.edge_pair (ep);
|
|
||||||
insert (ep);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@
|
||||||
|
|
||||||
#include "dbCommon.h"
|
#include "dbCommon.h"
|
||||||
|
|
||||||
#include "dbAsIfFlatEdgePairs.h"
|
#include "dbMutableEdgePairs.h"
|
||||||
#include "dbShapes.h"
|
#include "dbShapes.h"
|
||||||
#include "dbGenericShapeIterator.h"
|
#include "dbGenericShapeIterator.h"
|
||||||
#include "tlCopyOnWrite.h"
|
#include "tlCopyOnWrite.h"
|
||||||
|
|
@ -42,7 +42,7 @@ typedef generic_shapes_iterator_delegate<db::EdgePair> FlatEdgePairsIterator;
|
||||||
* @brief The delegate for the actual edge pair set implementation
|
* @brief The delegate for the actual edge pair set implementation
|
||||||
*/
|
*/
|
||||||
class DB_PUBLIC FlatEdgePairs
|
class DB_PUBLIC FlatEdgePairs
|
||||||
: public AsIfFlatEdgePairs
|
: public MutableEdgePairs
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef db::layer<db::EdgePair, db::unstable_layer_tag> edge_pair_layer_type;
|
typedef db::layer<db::EdgePair, db::unstable_layer_tag> edge_pair_layer_type;
|
||||||
|
|
@ -82,42 +82,30 @@ public:
|
||||||
virtual void insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const;
|
virtual void insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const;
|
||||||
virtual void insert_into_as_polygons (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer, db::Coord enl) const;
|
virtual void insert_into_as_polygons (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer, db::Coord enl) const;
|
||||||
|
|
||||||
void insert (const db::EdgePair &edge_pair);
|
virtual void do_insert (const db::EdgePair &edge_pair);
|
||||||
void insert (const db::Shape &shape);
|
|
||||||
|
|
||||||
template <class T>
|
virtual void do_transform (const db::Trans &t)
|
||||||
void insert (const db::Shape &shape, const T &trans)
|
|
||||||
{
|
{
|
||||||
if (shape.is_edge_pair ()) {
|
transform_generic (t);
|
||||||
|
|
||||||
db::EdgePair ep;
|
|
||||||
shape.edge_pair (ep);
|
|
||||||
ep.transform (trans);
|
|
||||||
insert (ep);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Iter>
|
virtual void do_transform (const db::ICplxTrans &t)
|
||||||
void insert_seq (const Iter &seq)
|
|
||||||
{
|
{
|
||||||
for (Iter i = seq; ! i.at_end (); ++i) {
|
transform_generic (t);
|
||||||
insert (*i);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Trans>
|
virtual void do_transform (const db::IMatrix2d &t)
|
||||||
void transform (const Trans &trans)
|
|
||||||
{
|
{
|
||||||
if (! trans.is_unity ()) {
|
transform_generic (t);
|
||||||
db::Shapes &ep = *mp_edge_pairs;
|
|
||||||
for (edge_pair_iterator_type p = ep.template get_layer<db::EdgePair, db::unstable_layer_tag> ().begin (); p != ep.template get_layer<db::EdgePair, db::unstable_layer_tag> ().end (); ++p) {
|
|
||||||
ep.get_layer<db::EdgePair, db::unstable_layer_tag> ().replace (p, p->transformed (trans));
|
|
||||||
}
|
|
||||||
invalidate_cache ();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void do_transform (const db::IMatrix3d &t)
|
||||||
|
{
|
||||||
|
transform_generic (t);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void flatten () { }
|
||||||
|
|
||||||
db::Shapes &raw_edge_pairs () { return *mp_edge_pairs; }
|
db::Shapes &raw_edge_pairs () { return *mp_edge_pairs; }
|
||||||
const db::Shapes &raw_edge_pairs () const { return *mp_edge_pairs; }
|
const db::Shapes &raw_edge_pairs () const { return *mp_edge_pairs; }
|
||||||
|
|
||||||
|
|
@ -131,6 +119,18 @@ private:
|
||||||
FlatEdgePairs &operator= (const FlatEdgePairs &other);
|
FlatEdgePairs &operator= (const FlatEdgePairs &other);
|
||||||
|
|
||||||
mutable tl::copy_on_write_ptr<db::Shapes> mp_edge_pairs;
|
mutable tl::copy_on_write_ptr<db::Shapes> mp_edge_pairs;
|
||||||
|
|
||||||
|
template <class Trans>
|
||||||
|
void transform_generic (const Trans &trans)
|
||||||
|
{
|
||||||
|
if (! trans.is_unity ()) {
|
||||||
|
db::Shapes &ep = *mp_edge_pairs;
|
||||||
|
for (edge_pair_iterator_type p = ep.template get_layer<db::EdgePair, db::unstable_layer_tag> ().begin (); p != ep.template get_layer<db::EdgePair, db::unstable_layer_tag> ().end (); ++p) {
|
||||||
|
ep.get_layer<db::EdgePair, db::unstable_layer_tag> ().replace (p, p->transformed (trans));
|
||||||
|
}
|
||||||
|
invalidate_cache ();
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ namespace db
|
||||||
// FlatEdges implementation
|
// FlatEdges implementation
|
||||||
|
|
||||||
FlatEdges::FlatEdges ()
|
FlatEdges::FlatEdges ()
|
||||||
: AsIfFlatEdges (), mp_edges (new db::Shapes (false)), mp_merged_edges (new db::Shapes (false))
|
: MutableEdges (), mp_edges (new db::Shapes (false)), mp_merged_edges (new db::Shapes (false))
|
||||||
{
|
{
|
||||||
init ();
|
init ();
|
||||||
}
|
}
|
||||||
|
|
@ -44,7 +44,7 @@ FlatEdges::~FlatEdges ()
|
||||||
}
|
}
|
||||||
|
|
||||||
FlatEdges::FlatEdges (const FlatEdges &other)
|
FlatEdges::FlatEdges (const FlatEdges &other)
|
||||||
: AsIfFlatEdges (other), mp_edges (other.mp_edges), mp_merged_edges (other.mp_merged_edges)
|
: MutableEdges (other), mp_edges (other.mp_edges), mp_merged_edges (other.mp_merged_edges)
|
||||||
{
|
{
|
||||||
init ();
|
init ();
|
||||||
|
|
||||||
|
|
@ -53,7 +53,7 @@ FlatEdges::FlatEdges (const FlatEdges &other)
|
||||||
}
|
}
|
||||||
|
|
||||||
FlatEdges::FlatEdges (const db::Shapes &edges, bool is_merged)
|
FlatEdges::FlatEdges (const db::Shapes &edges, bool is_merged)
|
||||||
: AsIfFlatEdges (), mp_edges (new db::Shapes (edges)), mp_merged_edges (new db::Shapes (false))
|
: MutableEdges (), mp_edges (new db::Shapes (edges)), mp_merged_edges (new db::Shapes (false))
|
||||||
{
|
{
|
||||||
init ();
|
init ();
|
||||||
|
|
||||||
|
|
@ -61,7 +61,7 @@ FlatEdges::FlatEdges (const db::Shapes &edges, bool is_merged)
|
||||||
}
|
}
|
||||||
|
|
||||||
FlatEdges::FlatEdges (bool is_merged)
|
FlatEdges::FlatEdges (bool is_merged)
|
||||||
: AsIfFlatEdges (), mp_edges (new db::Shapes (false)), mp_merged_edges (new db::Shapes (false))
|
: MutableEdges (), mp_edges (new db::Shapes (false)), mp_merged_edges (new db::Shapes (false))
|
||||||
{
|
{
|
||||||
init ();
|
init ();
|
||||||
|
|
||||||
|
|
@ -320,69 +320,7 @@ const db::RecursiveShapeIterator *FlatEdges::iter () const
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
FlatEdges::insert (const db::Box &box)
|
FlatEdges::do_insert (const db::Edge &edge)
|
||||||
{
|
|
||||||
if (! box.empty () && box.width () > 0 && box.height () > 0) {
|
|
||||||
|
|
||||||
bool was_empty = empty ();
|
|
||||||
|
|
||||||
db::Shapes &e = *mp_edges;
|
|
||||||
e.insert (db::Edge (box.lower_left (), box.upper_left ()));
|
|
||||||
e.insert (db::Edge (box.upper_left (), box.upper_right ()));
|
|
||||||
e.insert (db::Edge (box.upper_right (), box.lower_right ()));
|
|
||||||
e.insert (db::Edge (box.lower_right (), box.lower_left ()));
|
|
||||||
|
|
||||||
if (was_empty) {
|
|
||||||
|
|
||||||
m_is_merged = true;
|
|
||||||
update_bbox (box);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
m_is_merged = false;
|
|
||||||
invalidate_cache ();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
FlatEdges::insert (const db::Path &path)
|
|
||||||
{
|
|
||||||
if (path.points () > 0) {
|
|
||||||
insert (path.polygon ());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
FlatEdges::insert (const db::Polygon &polygon)
|
|
||||||
{
|
|
||||||
if (polygon.holes () > 0 || polygon.vertices () > 0) {
|
|
||||||
db::Shapes &edges = *mp_edges;
|
|
||||||
for (db::Polygon::polygon_edge_iterator e = polygon.begin_edge (); ! e.at_end (); ++e) {
|
|
||||||
edges.insert (*e);
|
|
||||||
}
|
|
||||||
m_is_merged = false;
|
|
||||||
invalidate_cache ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
FlatEdges::insert (const db::SimplePolygon &polygon)
|
|
||||||
{
|
|
||||||
if (polygon.vertices () > 0) {
|
|
||||||
db::Shapes &edges = *mp_edges;
|
|
||||||
for (db::SimplePolygon::polygon_edge_iterator e = polygon.begin_edge (); ! e.at_end (); ++e) {
|
|
||||||
edges.insert (*e);
|
|
||||||
}
|
|
||||||
m_is_merged = false;
|
|
||||||
invalidate_cache ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
FlatEdges::insert (const db::Edge &edge)
|
|
||||||
{
|
{
|
||||||
if (! empty ()) {
|
if (! empty ()) {
|
||||||
m_is_merged = false;
|
m_is_merged = false;
|
||||||
|
|
@ -392,23 +330,5 @@ FlatEdges::insert (const db::Edge &edge)
|
||||||
invalidate_cache ();
|
invalidate_cache ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
FlatEdges::insert (const db::Shape &shape)
|
|
||||||
{
|
|
||||||
if (shape.is_polygon () || shape.is_path () || shape.is_box ()) {
|
|
||||||
|
|
||||||
db::Polygon poly;
|
|
||||||
shape.polygon (poly);
|
|
||||||
insert (poly);
|
|
||||||
|
|
||||||
} else if (shape.is_edge ()) {
|
|
||||||
|
|
||||||
db::Edge edge;
|
|
||||||
shape.edge (edge);
|
|
||||||
insert (edge);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@
|
||||||
|
|
||||||
#include "dbCommon.h"
|
#include "dbCommon.h"
|
||||||
|
|
||||||
#include "dbAsIfFlatEdges.h"
|
#include "dbMutableEdges.h"
|
||||||
#include "dbShapes.h"
|
#include "dbShapes.h"
|
||||||
#include "dbShapes2.h"
|
#include "dbShapes2.h"
|
||||||
#include "dbGenericShapeIterator.h"
|
#include "dbGenericShapeIterator.h"
|
||||||
|
|
@ -43,7 +43,7 @@ typedef generic_shapes_iterator_delegate<db::Edge> FlatEdgesIterator;
|
||||||
* @brief A flat, edge-set delegate
|
* @brief A flat, edge-set delegate
|
||||||
*/
|
*/
|
||||||
class DB_PUBLIC FlatEdges
|
class DB_PUBLIC FlatEdges
|
||||||
: public AsIfFlatEdges
|
: public MutableEdges
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef db::Edge value_type;
|
typedef db::Edge value_type;
|
||||||
|
|
@ -65,6 +65,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
void reserve (size_t);
|
void reserve (size_t);
|
||||||
|
void flatten () { }
|
||||||
|
|
||||||
virtual EdgesIteratorDelegate *begin () const;
|
virtual EdgesIteratorDelegate *begin () const;
|
||||||
virtual EdgesIteratorDelegate *begin_merged () const;
|
virtual EdgesIteratorDelegate *begin_merged () const;
|
||||||
|
|
@ -91,60 +92,26 @@ public:
|
||||||
|
|
||||||
virtual const db::RecursiveShapeIterator *iter () const;
|
virtual const db::RecursiveShapeIterator *iter () const;
|
||||||
|
|
||||||
void insert (const db::Box &box);
|
void do_insert (const db::Edge &edge);
|
||||||
void insert (const db::Path &path);
|
|
||||||
void insert (const db::SimplePolygon &polygon);
|
|
||||||
void insert (const db::Polygon &polygon);
|
|
||||||
void insert (const db::Edge &edge);
|
|
||||||
void insert (const db::Shape &shape);
|
|
||||||
|
|
||||||
template <class T>
|
void do_transform (const db::Trans &t)
|
||||||
void insert (const db::Shape &shape, const T &trans)
|
|
||||||
{
|
{
|
||||||
if (shape.is_polygon () || shape.is_path () || shape.is_box ()) {
|
transform_generic (t);
|
||||||
|
|
||||||
db::Polygon poly;
|
|
||||||
shape.polygon (poly);
|
|
||||||
poly.transform (trans);
|
|
||||||
insert (poly);
|
|
||||||
|
|
||||||
} else if (shape.is_edge ()) {
|
|
||||||
|
|
||||||
db::Edge edge;
|
|
||||||
shape.edge (edge);
|
|
||||||
edge.transform (trans);
|
|
||||||
insert (edge);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Iter>
|
void do_transform (const db::ICplxTrans &t)
|
||||||
void insert (const Iter &b, const Iter &e)
|
|
||||||
{
|
{
|
||||||
reserve (count () + (e - b));
|
transform_generic (t);
|
||||||
for (Iter i = b; i != e; ++i) {
|
|
||||||
insert (*i);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Iter>
|
void do_transform (const db::IMatrix2d &t)
|
||||||
void insert_seq (const Iter &seq)
|
|
||||||
{
|
{
|
||||||
for (Iter i = seq; ! i.at_end (); ++i) {
|
transform_generic (t);
|
||||||
insert (*i);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Trans>
|
void do_transform (const db::IMatrix3d &t)
|
||||||
void transform (const Trans &trans)
|
|
||||||
{
|
{
|
||||||
if (! trans.is_unity ()) {
|
transform_generic (t);
|
||||||
db::Shapes &e = *mp_edges;
|
|
||||||
for (edge_iterator_type p = e.template get_layer<db::Edge, db::unstable_layer_tag> ().begin (); p != e.get_layer<db::Edge, db::unstable_layer_tag> ().end (); ++p) {
|
|
||||||
e.get_layer<db::Edge, db::unstable_layer_tag> ().replace (p, p->transformed (trans));
|
|
||||||
}
|
|
||||||
invalidate_cache ();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
db::Shapes &raw_edges () { return *mp_edges; }
|
db::Shapes &raw_edges () { return *mp_edges; }
|
||||||
|
|
@ -168,6 +135,18 @@ private:
|
||||||
|
|
||||||
void init ();
|
void init ();
|
||||||
void ensure_merged_edges_valid () const;
|
void ensure_merged_edges_valid () const;
|
||||||
|
|
||||||
|
template <class Trans>
|
||||||
|
void transform_generic (const Trans &trans)
|
||||||
|
{
|
||||||
|
if (! trans.is_unity ()) {
|
||||||
|
db::Shapes &e = *mp_edges;
|
||||||
|
for (edge_iterator_type p = e.template get_layer<db::Edge, db::unstable_layer_tag> ().begin (); p != e.get_layer<db::Edge, db::unstable_layer_tag> ().end (); ++p) {
|
||||||
|
e.get_layer<db::Edge, db::unstable_layer_tag> ().replace (p, p->transformed (trans));
|
||||||
|
}
|
||||||
|
invalidate_cache ();
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ namespace db
|
||||||
// FlatRegion implementation
|
// FlatRegion implementation
|
||||||
|
|
||||||
FlatRegion::FlatRegion ()
|
FlatRegion::FlatRegion ()
|
||||||
: AsIfFlatRegion (), mp_polygons (new db::Shapes (false)), mp_merged_polygons (new db::Shapes (false))
|
: MutableRegion (), mp_polygons (new db::Shapes (false)), mp_merged_polygons (new db::Shapes (false))
|
||||||
{
|
{
|
||||||
init ();
|
init ();
|
||||||
}
|
}
|
||||||
|
|
@ -44,7 +44,7 @@ FlatRegion::~FlatRegion ()
|
||||||
}
|
}
|
||||||
|
|
||||||
FlatRegion::FlatRegion (const FlatRegion &other)
|
FlatRegion::FlatRegion (const FlatRegion &other)
|
||||||
: AsIfFlatRegion (other), mp_polygons (other.mp_polygons), mp_merged_polygons (other.mp_merged_polygons)
|
: MutableRegion (other), mp_polygons (other.mp_polygons), mp_merged_polygons (other.mp_merged_polygons)
|
||||||
{
|
{
|
||||||
init ();
|
init ();
|
||||||
|
|
||||||
|
|
@ -53,7 +53,7 @@ FlatRegion::FlatRegion (const FlatRegion &other)
|
||||||
}
|
}
|
||||||
|
|
||||||
FlatRegion::FlatRegion (const db::Shapes &polygons, bool is_merged)
|
FlatRegion::FlatRegion (const db::Shapes &polygons, bool is_merged)
|
||||||
: AsIfFlatRegion (), mp_polygons (new db::Shapes (polygons)), mp_merged_polygons (new db::Shapes (false))
|
: MutableRegion (), mp_polygons (new db::Shapes (polygons)), mp_merged_polygons (new db::Shapes (false))
|
||||||
{
|
{
|
||||||
init ();
|
init ();
|
||||||
|
|
||||||
|
|
@ -61,7 +61,7 @@ FlatRegion::FlatRegion (const db::Shapes &polygons, bool is_merged)
|
||||||
}
|
}
|
||||||
|
|
||||||
FlatRegion::FlatRegion (bool is_merged)
|
FlatRegion::FlatRegion (bool is_merged)
|
||||||
: AsIfFlatRegion (), mp_polygons (new db::Shapes (false)), mp_merged_polygons (new db::Shapes (false))
|
: MutableRegion (), mp_polygons (new db::Shapes (false)), mp_merged_polygons (new db::Shapes (false))
|
||||||
{
|
{
|
||||||
init ();
|
init ();
|
||||||
|
|
||||||
|
|
@ -410,68 +410,17 @@ void FlatRegion::insert_into (Layout *layout, db::cell_index_type into_cell, uns
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
FlatRegion::insert (const db::Box &box)
|
FlatRegion::do_insert (const db::Polygon &polygon)
|
||||||
{
|
|
||||||
if (! box.empty () && box.width () > 0 && box.height () > 0) {
|
|
||||||
|
|
||||||
if (empty ()) {
|
|
||||||
|
|
||||||
mp_polygons->insert (db::Polygon (box));
|
|
||||||
m_is_merged = true;
|
|
||||||
update_bbox (box);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
mp_polygons->insert (db::Polygon (box));
|
|
||||||
m_is_merged = false;
|
|
||||||
invalidate_cache ();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
FlatRegion::insert (const db::Path &path)
|
|
||||||
{
|
|
||||||
if (path.points () > 0) {
|
|
||||||
mp_polygons->insert (path.polygon ());
|
|
||||||
m_is_merged = false;
|
|
||||||
invalidate_cache ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
FlatRegion::insert (const db::Polygon &polygon)
|
|
||||||
{
|
{
|
||||||
if (polygon.holes () > 0 || polygon.vertices () > 0) {
|
if (polygon.holes () > 0 || polygon.vertices () > 0) {
|
||||||
|
|
||||||
|
bool is_box = (empty () && polygon.is_box ());
|
||||||
|
|
||||||
mp_polygons->insert (polygon);
|
mp_polygons->insert (polygon);
|
||||||
m_is_merged = false;
|
set_is_merged (is_box);
|
||||||
invalidate_cache ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
FlatRegion::insert (const db::SimplePolygon &polygon)
|
|
||||||
{
|
|
||||||
if (polygon.vertices () > 0) {
|
|
||||||
db::Polygon poly;
|
|
||||||
poly.assign_hull (polygon.begin_hull (), polygon.end_hull ());
|
|
||||||
mp_polygons->insert (poly);
|
|
||||||
m_is_merged = false;
|
|
||||||
invalidate_cache ();
|
invalidate_cache ();
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
FlatRegion::insert (const db::Shape &shape)
|
|
||||||
{
|
|
||||||
if (shape.is_polygon () || shape.is_path () || shape.is_box ()) {
|
|
||||||
db::Polygon poly;
|
|
||||||
shape.polygon (poly);
|
|
||||||
mp_polygons->insert (poly);
|
|
||||||
m_is_merged = false;
|
|
||||||
invalidate_cache ();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@
|
||||||
|
|
||||||
#include "dbCommon.h"
|
#include "dbCommon.h"
|
||||||
|
|
||||||
#include "dbAsIfFlatRegion.h"
|
#include "dbMutableRegion.h"
|
||||||
#include "dbShapes.h"
|
#include "dbShapes.h"
|
||||||
#include "dbShapes2.h"
|
#include "dbShapes2.h"
|
||||||
#include "tlCopyOnWrite.h"
|
#include "tlCopyOnWrite.h"
|
||||||
|
|
@ -42,7 +42,7 @@ typedef generic_shapes_iterator_delegate<db::Polygon> FlatRegionIterator;
|
||||||
* @brief A flat, polygon-set delegate
|
* @brief A flat, polygon-set delegate
|
||||||
*/
|
*/
|
||||||
class DB_PUBLIC FlatRegion
|
class DB_PUBLIC FlatRegion
|
||||||
: public AsIfFlatRegion
|
: public MutableRegion
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef db::Polygon value_type;
|
typedef db::Polygon value_type;
|
||||||
|
|
@ -62,7 +62,7 @@ public:
|
||||||
return new FlatRegion (*this);
|
return new FlatRegion (*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void reserve (size_t);
|
virtual void reserve (size_t);
|
||||||
|
|
||||||
virtual RegionIteratorDelegate *begin () const;
|
virtual RegionIteratorDelegate *begin () const;
|
||||||
virtual RegionIteratorDelegate *begin_merged () const;
|
virtual RegionIteratorDelegate *begin_merged () const;
|
||||||
|
|
@ -97,52 +97,30 @@ public:
|
||||||
|
|
||||||
virtual const db::RecursiveShapeIterator *iter () const;
|
virtual const db::RecursiveShapeIterator *iter () const;
|
||||||
|
|
||||||
void insert (const db::Box &box);
|
void do_insert (const db::Polygon &polygon);
|
||||||
void insert (const db::Path &path);
|
|
||||||
void insert (const db::SimplePolygon &polygon);
|
|
||||||
void insert (const db::Polygon &polygon);
|
|
||||||
void insert (const db::Shape &shape);
|
|
||||||
|
|
||||||
template <class T>
|
void do_transform (const db::Trans &t)
|
||||||
void insert (const db::Shape &shape, const T &trans)
|
|
||||||
{
|
{
|
||||||
if (shape.is_polygon () || shape.is_path () || shape.is_box ()) {
|
transform_generic (t);
|
||||||
db::Polygon poly;
|
|
||||||
shape.polygon (poly);
|
|
||||||
poly.transform (trans);
|
|
||||||
insert (poly);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Iter>
|
void do_transform (const db::ICplxTrans &t)
|
||||||
void insert (const Iter &b, const Iter &e)
|
|
||||||
{
|
{
|
||||||
reserve (count () + (e - b));
|
transform_generic (t);
|
||||||
for (Iter i = b; i != e; ++i) {
|
|
||||||
insert (*i);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Iter>
|
virtual void do_transform (const db::IMatrix2d &t)
|
||||||
void insert_seq (const Iter &seq)
|
|
||||||
{
|
{
|
||||||
for (Iter i = seq; ! i.at_end (); ++i) {
|
transform_generic (t);
|
||||||
insert (*i);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Trans>
|
virtual void do_transform (const db::IMatrix3d &t)
|
||||||
void transform (const Trans &trans)
|
|
||||||
{
|
{
|
||||||
if (! trans.is_unity ()) {
|
transform_generic (t);
|
||||||
db::Shapes &polygons = *mp_polygons;
|
|
||||||
for (polygon_iterator_type p = polygons.get_layer<db::Polygon, db::unstable_layer_tag> ().begin (); p != polygons.get_layer<db::Polygon, db::unstable_layer_tag> ().end (); ++p) {
|
|
||||||
polygons.get_layer<db::Polygon, db::unstable_layer_tag> ().replace (p, p->transformed (trans));
|
|
||||||
}
|
|
||||||
invalidate_cache ();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void flatten () { }
|
||||||
|
|
||||||
db::Shapes &raw_polygons () { return *mp_polygons; }
|
db::Shapes &raw_polygons () { return *mp_polygons; }
|
||||||
const db::Shapes &raw_polygons () const { return *mp_polygons; }
|
const db::Shapes &raw_polygons () const { return *mp_polygons; }
|
||||||
|
|
||||||
|
|
@ -166,6 +144,18 @@ private:
|
||||||
|
|
||||||
void init ();
|
void init ();
|
||||||
void ensure_merged_polygons_valid () const;
|
void ensure_merged_polygons_valid () const;
|
||||||
|
|
||||||
|
template <class Trans>
|
||||||
|
void transform_generic (const Trans &trans)
|
||||||
|
{
|
||||||
|
if (! trans.is_unity ()) {
|
||||||
|
db::Shapes &polygons = *mp_polygons;
|
||||||
|
for (polygon_iterator_type p = polygons.get_layer<db::Polygon, db::unstable_layer_tag> ().begin (); p != polygons.get_layer<db::Polygon, db::unstable_layer_tag> ().end (); ++p) {
|
||||||
|
polygons.get_layer<db::Polygon, db::unstable_layer_tag> ().replace (p, p->transformed (trans));
|
||||||
|
}
|
||||||
|
invalidate_cache ();
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ namespace db
|
||||||
// FlatTexts implementation
|
// FlatTexts implementation
|
||||||
|
|
||||||
FlatTexts::FlatTexts ()
|
FlatTexts::FlatTexts ()
|
||||||
: AsIfFlatTexts (), mp_texts (new db::Shapes (false))
|
: MutableTexts (), mp_texts (new db::Shapes (false))
|
||||||
{
|
{
|
||||||
// .. nothing yet ..
|
// .. nothing yet ..
|
||||||
}
|
}
|
||||||
|
|
@ -43,13 +43,13 @@ FlatTexts::~FlatTexts ()
|
||||||
}
|
}
|
||||||
|
|
||||||
FlatTexts::FlatTexts (const FlatTexts &other)
|
FlatTexts::FlatTexts (const FlatTexts &other)
|
||||||
: AsIfFlatTexts (other), mp_texts (other.mp_texts)
|
: MutableTexts (other), mp_texts (other.mp_texts)
|
||||||
{
|
{
|
||||||
// .. nothing yet ..
|
// .. nothing yet ..
|
||||||
}
|
}
|
||||||
|
|
||||||
FlatTexts::FlatTexts (const db::Shapes &texts)
|
FlatTexts::FlatTexts (const db::Shapes &texts)
|
||||||
: AsIfFlatTexts (), mp_texts (new db::Shapes (texts))
|
: MutableTexts (), mp_texts (new db::Shapes (texts))
|
||||||
{
|
{
|
||||||
// .. nothing yet ..
|
// .. nothing yet ..
|
||||||
}
|
}
|
||||||
|
|
@ -207,23 +207,11 @@ FlatTexts::insert_into (Layout *layout, db::cell_index_type into_cell, unsigned
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
FlatTexts::insert (const db::Text &t)
|
FlatTexts::do_insert (const db::Text &t)
|
||||||
{
|
{
|
||||||
mp_texts->insert (t);
|
mp_texts->insert (t);
|
||||||
invalidate_cache ();
|
invalidate_cache ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
FlatTexts::insert (const db::Shape &shape)
|
|
||||||
{
|
|
||||||
if (shape.is_text ()) {
|
|
||||||
|
|
||||||
db::Text t;
|
|
||||||
shape.text (t);
|
|
||||||
insert (t);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@
|
||||||
|
|
||||||
#include "dbCommon.h"
|
#include "dbCommon.h"
|
||||||
|
|
||||||
#include "dbAsIfFlatTexts.h"
|
#include "dbMutableTexts.h"
|
||||||
#include "dbShapes.h"
|
#include "dbShapes.h"
|
||||||
#include "tlCopyOnWrite.h"
|
#include "tlCopyOnWrite.h"
|
||||||
|
|
||||||
|
|
@ -41,7 +41,7 @@ typedef generic_shapes_iterator_delegate<db::Text> FlatTextsIterator;
|
||||||
* @brief The delegate for the actual text set implementation
|
* @brief The delegate for the actual text set implementation
|
||||||
*/
|
*/
|
||||||
class DB_PUBLIC FlatTexts
|
class DB_PUBLIC FlatTexts
|
||||||
: public AsIfFlatTexts
|
: public MutableTexts
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef db::Text value_type;
|
typedef db::Text value_type;
|
||||||
|
|
@ -83,40 +83,28 @@ public:
|
||||||
virtual void insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const;
|
virtual void insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const;
|
||||||
virtual void insert_into_as_polygons (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer, db::Coord enl) const;
|
virtual void insert_into_as_polygons (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer, db::Coord enl) const;
|
||||||
|
|
||||||
void insert (const db::Text &text);
|
virtual void flatten () { }
|
||||||
void insert (const db::Shape &shape);
|
|
||||||
|
|
||||||
template <class T>
|
void do_insert (const db::Text &text);
|
||||||
void insert (const db::Shape &shape, const T &trans)
|
|
||||||
|
virtual void do_transform (const db::Trans &t)
|
||||||
{
|
{
|
||||||
if (shape.is_edge_pair ()) {
|
transform_generic (t);
|
||||||
|
|
||||||
db::Text t;
|
|
||||||
shape.text (t);
|
|
||||||
t.transform (trans);
|
|
||||||
insert (t);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Iter>
|
virtual void do_transform (const db::ICplxTrans &t)
|
||||||
void insert_seq (const Iter &seq)
|
|
||||||
{
|
{
|
||||||
for (Iter i = seq; ! i.at_end (); ++i) {
|
transform_generic (t);
|
||||||
insert (*i);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Trans>
|
virtual void do_transform (const db::IMatrix2d &t)
|
||||||
void transform (const Trans &trans)
|
|
||||||
{
|
{
|
||||||
if (! trans.is_unity ()) {
|
transform_generic (t);
|
||||||
db::Shapes &texts = *mp_texts;
|
}
|
||||||
for (text_iterator_type p = texts.template get_layer<db::Text, db::unstable_layer_tag> ().begin (); p != texts.template get_layer<db::Text, db::unstable_layer_tag> ().end (); ++p) {
|
|
||||||
texts.get_layer<db::Text, db::unstable_layer_tag> ().replace (p, p->transformed (trans));
|
virtual void do_transform (const db::IMatrix3d &t)
|
||||||
}
|
{
|
||||||
invalidate_cache ();
|
transform_generic (t);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
db::Shapes &raw_texts () { return *mp_texts; }
|
db::Shapes &raw_texts () { return *mp_texts; }
|
||||||
|
|
@ -132,6 +120,18 @@ private:
|
||||||
FlatTexts &operator= (const FlatTexts &other);
|
FlatTexts &operator= (const FlatTexts &other);
|
||||||
|
|
||||||
mutable tl::copy_on_write_ptr<db::Shapes> mp_texts;
|
mutable tl::copy_on_write_ptr<db::Shapes> mp_texts;
|
||||||
|
|
||||||
|
template <class Trans>
|
||||||
|
void transform_generic (const Trans &trans)
|
||||||
|
{
|
||||||
|
if (! trans.is_unity ()) {
|
||||||
|
db::Shapes &texts = *mp_texts;
|
||||||
|
for (text_iterator_type p = texts.template get_layer<db::Text, db::unstable_layer_tag> ().begin (); p != texts.template get_layer<db::Text, db::unstable_layer_tag> ().end (); ++p) {
|
||||||
|
texts.get_layer<db::Text, db::unstable_layer_tag> ().replace (p, p->transformed (trans));
|
||||||
|
}
|
||||||
|
invalidate_cache ();
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -121,13 +121,13 @@ public:
|
||||||
* @param char_spacing Additional spacing between the lines in µm
|
* @param char_spacing Additional spacing between the lines in µm
|
||||||
* @param The resulting polygons will be put here (the vector will be cleared before)
|
* @param The resulting polygons will be put here (the vector will be cleared before)
|
||||||
*/
|
*/
|
||||||
void text (const std::string &t, double target_dbu, double mag, bool inv, double bias, double char_spacing, double line_spacing, std::vector<db::Polygon> &polygons) const;
|
void text (const std::string &t, double target_dbu, double mag2, bool inv, double bias, double char_spacing, double line_spacing, std::vector<db::Polygon> &polygons) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Creates the given text as a region
|
* @brief Creates the given text as a region
|
||||||
* For the parameters see "text"
|
* For the parameters see "text"
|
||||||
*/
|
*/
|
||||||
db::Region text_as_region (const std::string &t, double target_dbu, double mag, bool inv, double bias, double char_spacing, double line_spacing) const;
|
db::Region text_as_region (const std::string &t, double target_dbu, double mag2, bool inv, double bias, double char_spacing, double line_spacing) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Gets the glyph for a given character
|
* @brief Gets the glyph for a given character
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ namespace db
|
||||||
// the iterator provides the hierarchical selection (enabling/disabling cells etc.)
|
// the iterator provides the hierarchical selection (enabling/disabling cells etc.)
|
||||||
|
|
||||||
LayoutToNetlist::LayoutToNetlist (const db::RecursiveShapeIterator &iter)
|
LayoutToNetlist::LayoutToNetlist (const db::RecursiveShapeIterator &iter)
|
||||||
: m_iter (iter), m_layout_index (0), m_netlist_extracted (false), m_is_flat (false), m_device_scaling (1.0)
|
: m_iter (iter), m_layout_index (0), m_netlist_extracted (false), m_is_flat (false), m_device_scaling (1.0), m_include_floating_subcircuits (false)
|
||||||
{
|
{
|
||||||
// check the iterator
|
// check the iterator
|
||||||
if (iter.has_complex_region () || iter.region () != db::Box::world ()) {
|
if (iter.has_complex_region () || iter.region () != db::Box::world ()) {
|
||||||
|
|
@ -60,7 +60,7 @@ LayoutToNetlist::LayoutToNetlist (const db::RecursiveShapeIterator &iter)
|
||||||
}
|
}
|
||||||
|
|
||||||
LayoutToNetlist::LayoutToNetlist (db::DeepShapeStore *dss, unsigned int layout_index)
|
LayoutToNetlist::LayoutToNetlist (db::DeepShapeStore *dss, unsigned int layout_index)
|
||||||
: mp_dss (dss), m_layout_index (layout_index), m_netlist_extracted (false), m_is_flat (false), m_device_scaling (1.0)
|
: mp_dss (dss), m_layout_index (layout_index), m_netlist_extracted (false), m_is_flat (false), m_device_scaling (1.0), m_include_floating_subcircuits (false)
|
||||||
{
|
{
|
||||||
if (dss->is_valid_layout_index (m_layout_index)) {
|
if (dss->is_valid_layout_index (m_layout_index)) {
|
||||||
m_iter = db::RecursiveShapeIterator (dss->layout (m_layout_index), dss->initial_cell (m_layout_index), std::set<unsigned int> ());
|
m_iter = db::RecursiveShapeIterator (dss->layout (m_layout_index), dss->initial_cell (m_layout_index), std::set<unsigned int> ());
|
||||||
|
|
@ -68,7 +68,7 @@ LayoutToNetlist::LayoutToNetlist (db::DeepShapeStore *dss, unsigned int layout_i
|
||||||
}
|
}
|
||||||
|
|
||||||
LayoutToNetlist::LayoutToNetlist (const std::string &topcell_name, double dbu)
|
LayoutToNetlist::LayoutToNetlist (const std::string &topcell_name, double dbu)
|
||||||
: m_iter (), m_netlist_extracted (false), m_is_flat (true), m_device_scaling (1.0)
|
: m_iter (), m_netlist_extracted (false), m_is_flat (true), m_device_scaling (1.0), m_include_floating_subcircuits (false)
|
||||||
{
|
{
|
||||||
mp_internal_dss.reset (new db::DeepShapeStore (topcell_name, dbu));
|
mp_internal_dss.reset (new db::DeepShapeStore (topcell_name, dbu));
|
||||||
mp_dss.reset (mp_internal_dss.get ());
|
mp_dss.reset (mp_internal_dss.get ());
|
||||||
|
|
@ -79,7 +79,7 @@ LayoutToNetlist::LayoutToNetlist (const std::string &topcell_name, double dbu)
|
||||||
|
|
||||||
LayoutToNetlist::LayoutToNetlist ()
|
LayoutToNetlist::LayoutToNetlist ()
|
||||||
: m_iter (), mp_internal_dss (new db::DeepShapeStore ()), mp_dss (mp_internal_dss.get ()), m_layout_index (0),
|
: m_iter (), mp_internal_dss (new db::DeepShapeStore ()), mp_dss (mp_internal_dss.get ()), m_layout_index (0),
|
||||||
m_netlist_extracted (false), m_is_flat (false), m_device_scaling (1.0)
|
m_netlist_extracted (false), m_is_flat (false), m_device_scaling (1.0), m_include_floating_subcircuits (false)
|
||||||
{
|
{
|
||||||
init ();
|
init ();
|
||||||
}
|
}
|
||||||
|
|
@ -310,37 +310,91 @@ size_t LayoutToNetlist::global_net_id (const std::string &name)
|
||||||
return m_conn.global_net_id (name);
|
return m_conn.global_net_id (name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LayoutToNetlist::extract_netlist (const std::string &joined_net_names, bool include_floating_subcircuits)
|
void LayoutToNetlist::set_include_floating_subcircuits (bool f)
|
||||||
{
|
{
|
||||||
extract_netlist (joined_net_names, std::map<std::string, std::string> (), include_floating_subcircuits);
|
m_include_floating_subcircuits = f;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LayoutToNetlist::extract_netlist (const std::string &joined_net_names, const std::map<std::string, std::string> &joined_net_names_per_cell, bool include_floating_subcircuits)
|
void LayoutToNetlist::clear_join_net_names ()
|
||||||
|
{
|
||||||
|
m_joined_net_names.clear ();
|
||||||
|
m_joined_net_names_per_cell.clear ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LayoutToNetlist::join_net_names (const tl::GlobPattern &gp)
|
||||||
|
{
|
||||||
|
m_joined_net_names.push_back (gp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LayoutToNetlist::join_net_names (const tl::GlobPattern &cell, const tl::GlobPattern &gp)
|
||||||
|
{
|
||||||
|
m_joined_net_names_per_cell.push_back (std::make_pair (cell, gp));
|
||||||
|
}
|
||||||
|
|
||||||
|
void LayoutToNetlist::clear_join_nets ()
|
||||||
|
{
|
||||||
|
m_joined_nets.clear ();
|
||||||
|
m_joined_nets_per_cell.clear ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LayoutToNetlist::join_nets (const std::set<std::string> &jn)
|
||||||
|
{
|
||||||
|
m_joined_nets.push_back (jn);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LayoutToNetlist::join_nets (const tl::GlobPattern &cell, const std::set<std::string> &gp)
|
||||||
|
{
|
||||||
|
m_joined_nets_per_cell.push_back (std::make_pair (cell, gp));
|
||||||
|
}
|
||||||
|
|
||||||
|
void LayoutToNetlist::extract_netlist ()
|
||||||
{
|
{
|
||||||
if (m_netlist_extracted) {
|
if (m_netlist_extracted) {
|
||||||
throw tl::Exception (tl::to_string (tr ("The netlist has already been extracted")));
|
throw tl::Exception (tl::to_string (tr ("The netlist has already been extracted")));
|
||||||
}
|
}
|
||||||
ensure_netlist ();
|
ensure_netlist ();
|
||||||
|
|
||||||
|
const db::Layout &layout = dss ().layout (m_layout_index);
|
||||||
|
|
||||||
db::NetlistExtractor netex;
|
db::NetlistExtractor netex;
|
||||||
|
|
||||||
netex.set_joined_net_names (joined_net_names);
|
netex.set_joined_net_names (m_joined_net_names);
|
||||||
|
|
||||||
const db::Layout &layout = dss ().layout (m_layout_index);
|
std::map<std::string, std::list<tl::GlobPattern> > jp_per_cell;
|
||||||
for (std::map<std::string, std::string>::const_iterator j = joined_net_names_per_cell.begin (); j != joined_net_names_per_cell.end (); ++j) {
|
for (std::list<std::pair<tl::GlobPattern, tl::GlobPattern> >::const_iterator j = m_joined_net_names_per_cell.begin (); j != m_joined_net_names_per_cell.end (); ++j) {
|
||||||
tl::GlobPattern pat (j->first);
|
if (j->first.is_const ()) {
|
||||||
if (pat.is_const ()) {
|
jp_per_cell [j->first.pattern ()].push_back (j->second);
|
||||||
netex.set_joined_net_names (j->first, j->second);
|
|
||||||
} else {
|
} else {
|
||||||
for (db::Layout::const_iterator c = layout.begin (); c != layout.end (); ++c) {
|
for (db::Layout::const_iterator c = layout.begin (); c != layout.end (); ++c) {
|
||||||
if (pat.match (layout.cell_name (c->cell_index ()))) {
|
if (j->first.match (layout.cell_name (c->cell_index ()))) {
|
||||||
netex.set_joined_net_names (layout.cell_name (c->cell_index ()), j->second);
|
jp_per_cell [layout.cell_name (c->cell_index ())].push_back (j->second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (std::map<std::string, std::list<tl::GlobPattern> >::const_iterator i = jp_per_cell.begin (); i != jp_per_cell.end (); ++i) {
|
||||||
|
netex.set_joined_net_names (i->first, i->second);
|
||||||
|
}
|
||||||
|
|
||||||
netex.set_include_floating_subcircuits (include_floating_subcircuits);
|
netex.set_joined_nets (m_joined_nets);
|
||||||
|
|
||||||
|
std::map<std::string, std::list<std::set<std::string> > > jn_per_cell;
|
||||||
|
for (std::list<std::pair<tl::GlobPattern, std::set<std::string> > >::const_iterator j = m_joined_nets_per_cell.begin (); j != m_joined_nets_per_cell.end (); ++j) {
|
||||||
|
if (j->first.is_const ()) {
|
||||||
|
jn_per_cell [j->first.pattern ()].push_back (j->second);
|
||||||
|
} else {
|
||||||
|
for (db::Layout::const_iterator c = layout.begin (); c != layout.end (); ++c) {
|
||||||
|
if (j->first.match (layout.cell_name (c->cell_index ()))) {
|
||||||
|
jn_per_cell [layout.cell_name (c->cell_index ())].push_back (j->second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (std::map<std::string, std::list<std::set<std::string> > >::const_iterator i = jn_per_cell.begin (); i != jn_per_cell.end (); ++i) {
|
||||||
|
netex.set_joined_nets (i->first, i->second);
|
||||||
|
}
|
||||||
|
|
||||||
|
netex.set_include_floating_subcircuits (m_include_floating_subcircuits);
|
||||||
netex.extract_nets (dss (), m_layout_index, m_conn, *mp_netlist, m_net_clusters);
|
netex.extract_nets (dss (), m_layout_index, m_conn, *mp_netlist, m_net_clusters);
|
||||||
|
|
||||||
m_netlist_extracted = true;
|
m_netlist_extracted = true;
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@
|
||||||
#include "dbCellMapping.h"
|
#include "dbCellMapping.h"
|
||||||
#include "dbNetlistExtractor.h"
|
#include "dbNetlistExtractor.h"
|
||||||
#include "dbNetlistDeviceExtractor.h"
|
#include "dbNetlistDeviceExtractor.h"
|
||||||
|
#include "tlGlobPattern.h"
|
||||||
|
|
||||||
namespace db
|
namespace db
|
||||||
{
|
{
|
||||||
|
|
@ -423,20 +424,106 @@ public:
|
||||||
size_t global_net_id (const std::string &name);
|
size_t global_net_id (const std::string &name);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Runs the netlist extraction
|
* @brief Sets a flag indicating whether to include floating subcircuits
|
||||||
* See the class description for more details.
|
|
||||||
*/
|
*/
|
||||||
void extract_netlist (const std::string &joined_net_names = std::string (), bool include_floating_subcircuits = false);
|
void set_include_floating_subcircuits (bool f);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets a flag indicating whether to include floating subcircuits
|
||||||
|
*/
|
||||||
|
bool include_floating_subcircuits () const
|
||||||
|
{
|
||||||
|
return m_include_floating_subcircuits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Clears the "join net names" settings
|
||||||
|
*/
|
||||||
|
void clear_join_net_names ();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Joins net names matching the given expression
|
||||||
|
*
|
||||||
|
* Using this function will *add* one more rule. To clear all registered rules, use "clear_join_net_names".
|
||||||
|
* These pattern will only act on top level cells.
|
||||||
|
*/
|
||||||
|
void join_net_names (const tl::GlobPattern &gp);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Joins net names matching the given expression
|
||||||
|
*
|
||||||
|
* Using this function will *add* one more rule specific to cells matching the first glob pattern. To clear all registered rules, use "clear_join_net_names".
|
||||||
|
* Pattern registered with this function will act on the given cells, regardless of whether it's top level or not.
|
||||||
|
*/
|
||||||
|
void join_net_names (const tl::GlobPattern &cell, const tl::GlobPattern &gp);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the joined net names for top level
|
||||||
|
*
|
||||||
|
* This method is mainly provided to test purposes.
|
||||||
|
*/
|
||||||
|
const std::list<tl::GlobPattern> &joined_net_names () const
|
||||||
|
{
|
||||||
|
return m_joined_net_names;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the joined net names per cell
|
||||||
|
*
|
||||||
|
* This method is mainly provided to test purposes.
|
||||||
|
*/
|
||||||
|
const std::list<std::pair<tl::GlobPattern, tl::GlobPattern> > &joined_net_names_per_cell () const
|
||||||
|
{
|
||||||
|
return m_joined_net_names_per_cell;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Clears the "join nets" settings
|
||||||
|
*/
|
||||||
|
void clear_join_nets ();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Joins the given nets for the top level cell
|
||||||
|
*
|
||||||
|
* This method will make an explicit connection between the nets given in the name set.
|
||||||
|
* This applies implicit joining of different nets with the same label (intra-net joining)
|
||||||
|
* and of nets with different names (inter-net joining). Intra-net joining is implied always.
|
||||||
|
*/
|
||||||
|
void join_nets (const std::set<std::string> &jn);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Joins the given nets for cells matching the given pattern
|
||||||
|
*
|
||||||
|
* Using this function will *add* one more rule specific to cells matching the first glob pattern. To clear all registered rules, use "clear_join_nets".
|
||||||
|
* Pattern registered with this function will act on the given cells, regardless of whether it's top level or not.
|
||||||
|
*/
|
||||||
|
void join_nets (const tl::GlobPattern &cell, const std::set<std::string> &gp);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the joined nets for top level
|
||||||
|
*
|
||||||
|
* This method is mainly provided to test purposes.
|
||||||
|
*/
|
||||||
|
const std::list<std::set<std::string> > &joined_nets () const
|
||||||
|
{
|
||||||
|
return m_joined_nets;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the joined nets per cell
|
||||||
|
*
|
||||||
|
* This method is mainly provided to test purposes.
|
||||||
|
*/
|
||||||
|
const std::list<std::pair<tl::GlobPattern, std::set<std::string> > > &joined_nets_per_cell () const
|
||||||
|
{
|
||||||
|
return m_joined_nets_per_cell;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Runs the netlist extraction
|
* @brief Runs the netlist extraction
|
||||||
* In addition to the previous version, this extraction method allows specification of a per-cell list of
|
* See the class description for more details.
|
||||||
* joined (labelled) net names.
|
|
||||||
* The key of the "joined_net_names_per_cell" is a cell name or a glob expression for cells. On all matching cells,
|
|
||||||
* the value is applied as a label selector for labels that are joined together. The "joined_net_names" expressions
|
|
||||||
* is only applied to the top cell.
|
|
||||||
*/
|
*/
|
||||||
void extract_netlist (const std::string &joined_net_names, const std::map<std::string, std::string> &joined_net_names_per_cell, bool include_floating_subcircuits = false);
|
void extract_netlist ();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Marks the netlist as extracted
|
* @brief Marks the netlist as extracted
|
||||||
|
|
@ -830,6 +917,11 @@ private:
|
||||||
double m_device_scaling;
|
double m_device_scaling;
|
||||||
db::DeepLayer m_dummy_layer;
|
db::DeepLayer m_dummy_layer;
|
||||||
std::string m_generator;
|
std::string m_generator;
|
||||||
|
bool m_include_floating_subcircuits;
|
||||||
|
std::list<tl::GlobPattern> m_joined_net_names;
|
||||||
|
std::list<std::pair<tl::GlobPattern, tl::GlobPattern> > m_joined_net_names_per_cell;
|
||||||
|
std::list<std::set<std::string> > m_joined_nets;
|
||||||
|
std::list<std::pair<tl::GlobPattern, std::set<std::string> > > m_joined_nets_per_cell;
|
||||||
|
|
||||||
struct CellReuseTableKey
|
struct CellReuseTableKey
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ matrix_2d<C>::to_string () const
|
||||||
|
|
||||||
template <class C>
|
template <class C>
|
||||||
std::pair<double, double>
|
std::pair<double, double>
|
||||||
matrix_2d<C>::mag () const
|
matrix_2d<C>::mag2 () const
|
||||||
{
|
{
|
||||||
double s1 = sqrt (m_m11 * m_m11 + m_m21 * m_m21);
|
double s1 = sqrt (m_m11 * m_m11 + m_m21 * m_m21);
|
||||||
double s2 = sqrt (m_m12 * m_m12 + m_m22 * m_m22);
|
double s2 = sqrt (m_m12 * m_m12 + m_m22 * m_m22);
|
||||||
|
|
@ -65,7 +65,7 @@ template <class C>
|
||||||
double
|
double
|
||||||
matrix_2d<C>::angle () const
|
matrix_2d<C>::angle () const
|
||||||
{
|
{
|
||||||
std::pair <double, double> m = mag ();
|
std::pair <double, double> m = mag2 ();
|
||||||
double u1 = m.first;
|
double u1 = m.first;
|
||||||
double u2 = is_mirror () ? -m.second : m.second;
|
double u2 = is_mirror () ? -m.second : m.second;
|
||||||
double n11 = m_m11 / u1;
|
double n11 = m_m11 / u1;
|
||||||
|
|
@ -98,7 +98,7 @@ template <class C>
|
||||||
bool
|
bool
|
||||||
matrix_2d<C>::has_shear () const
|
matrix_2d<C>::has_shear () const
|
||||||
{
|
{
|
||||||
std::pair <double, double> m = mag ();
|
std::pair <double, double> m = mag2 ();
|
||||||
double u1 = m.first;
|
double u1 = m.first;
|
||||||
double u2 = is_mirror () ? -m.second : m.second;
|
double u2 = is_mirror () ? -m.second : m.second;
|
||||||
double n11 = m_m11 / u1;
|
double n11 = m_m11 / u1;
|
||||||
|
|
@ -114,7 +114,7 @@ template <class C>
|
||||||
double
|
double
|
||||||
matrix_2d<C>::shear_angle () const
|
matrix_2d<C>::shear_angle () const
|
||||||
{
|
{
|
||||||
std::pair <double, double> m = mag ();
|
std::pair <double, double> m = mag2 ();
|
||||||
double u1 = m.first;
|
double u1 = m.first;
|
||||||
double u2 = is_mirror () ? -m.second : m.second;
|
double u2 = is_mirror () ? -m.second : m.second;
|
||||||
double n11 = m_m11 / u1;
|
double n11 = m_m11 / u1;
|
||||||
|
|
|
||||||
|
|
@ -309,7 +309,15 @@ public:
|
||||||
* into the geometrical base transformations. This member returns the x and y magnification
|
* into the geometrical base transformations. This member returns the x and y magnification
|
||||||
* components. The order of the execution is mirror, magnification, shear and rotation.
|
* components. The order of the execution is mirror, magnification, shear and rotation.
|
||||||
*/
|
*/
|
||||||
std::pair<double, double> mag () const;
|
std::pair<double, double> mag2 () const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief For compatibility with other transformations
|
||||||
|
*/
|
||||||
|
double mag () const
|
||||||
|
{
|
||||||
|
return mag2 ().first;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Return the x magnification component of the matrix
|
* @brief Return the x magnification component of the matrix
|
||||||
|
|
@ -320,7 +328,7 @@ public:
|
||||||
*/
|
*/
|
||||||
double mag_x () const
|
double mag_x () const
|
||||||
{
|
{
|
||||||
return mag ().first;
|
return mag2 ().first;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -332,7 +340,7 @@ public:
|
||||||
*/
|
*/
|
||||||
double mag_y () const
|
double mag_y () const
|
||||||
{
|
{
|
||||||
return mag ().second;
|
return mag2 ().second;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -356,6 +364,22 @@ public:
|
||||||
return matrix_2d<C> (m, 0.0, 0.0, m);
|
return matrix_2d<C> (m, 0.0, 0.0, m);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A dummy displacement accessor (matrix2d does not have a displacement)
|
||||||
|
*/
|
||||||
|
db::vector<coord_type> disp () const
|
||||||
|
{
|
||||||
|
return db::vector<coord_type> ();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief For compatibility with other transformations
|
||||||
|
*/
|
||||||
|
coord_type ctrans (coord_type c) const
|
||||||
|
{
|
||||||
|
return db::coord_traits<coord_type>::rounded (mag2 ().first * c);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Return the mirror component of the matrix
|
* @brief Return the mirror component of the matrix
|
||||||
*
|
*
|
||||||
|
|
@ -759,9 +783,25 @@ public:
|
||||||
* into the geometrical base transformations. This member returns the magnification
|
* into the geometrical base transformations. This member returns the magnification
|
||||||
* component for both x and y direction (anisotropic magnification). The order of the execution is mirror, magnification, shear, rotation, perspective and displacement.
|
* component for both x and y direction (anisotropic magnification). The order of the execution is mirror, magnification, shear, rotation, perspective and displacement.
|
||||||
*/
|
*/
|
||||||
std::pair<double, double> mag () const
|
std::pair<double, double> mag2 () const
|
||||||
{
|
{
|
||||||
return m2d ().mag ();
|
return m2d ().mag2 ();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief For compatibility with other transformations
|
||||||
|
*/
|
||||||
|
double mag () const
|
||||||
|
{
|
||||||
|
return mag2 ().first;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief For compatibility with other transformations
|
||||||
|
*/
|
||||||
|
coord_type ctrans (coord_type c) const
|
||||||
|
{
|
||||||
|
return db::coord_traits<coord_type>::rounded (mag2 ().first * c);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -769,7 +809,7 @@ public:
|
||||||
*/
|
*/
|
||||||
double mag_x () const
|
double mag_x () const
|
||||||
{
|
{
|
||||||
return mag ().first;
|
return mag2 ().first;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -777,7 +817,7 @@ public:
|
||||||
*/
|
*/
|
||||||
double mag_y () const
|
double mag_y () const
|
||||||
{
|
{
|
||||||
return mag ().second;
|
return mag2 ().second;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,58 @@
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
KLayout Layout Viewer
|
||||||
|
Copyright (C) 2006-2021 Matthias Koefferlein
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "dbMutableEdgePairs.h"
|
||||||
|
|
||||||
|
namespace db
|
||||||
|
{
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------------------------------
|
||||||
|
// MutableEdgePairs implementation
|
||||||
|
|
||||||
|
MutableEdgePairs::MutableEdgePairs ()
|
||||||
|
: AsIfFlatEdgePairs ()
|
||||||
|
{
|
||||||
|
// .. nothing yet ..
|
||||||
|
}
|
||||||
|
|
||||||
|
MutableEdgePairs::MutableEdgePairs (const MutableEdgePairs &other)
|
||||||
|
: AsIfFlatEdgePairs (other)
|
||||||
|
{
|
||||||
|
// .. nothing yet ..
|
||||||
|
}
|
||||||
|
|
||||||
|
MutableEdgePairs::~MutableEdgePairs ()
|
||||||
|
{
|
||||||
|
// .. nothing yet ..
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MutableEdgePairs::insert (const db::Shape &shape)
|
||||||
|
{
|
||||||
|
if (shape.is_edge_pair ()) {
|
||||||
|
insert (shape.edge_pair ());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,100 @@
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
KLayout Layout Viewer
|
||||||
|
Copyright (C) 2006-2021 Matthias Koefferlein
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef HDR_dbMutableEdgePairs
|
||||||
|
#define HDR_dbMutableEdgePairs
|
||||||
|
|
||||||
|
#include "dbCommon.h"
|
||||||
|
|
||||||
|
#include "dbAsIfFlatEdgePairs.h"
|
||||||
|
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
namespace db {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief An interface representing mutable edge pair collections
|
||||||
|
*
|
||||||
|
* Mutable edge pair collections offer insert, transform, flatten and other manipulation functions.
|
||||||
|
*/
|
||||||
|
class DB_PUBLIC MutableEdgePairs
|
||||||
|
: public AsIfFlatEdgePairs
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MutableEdgePairs ();
|
||||||
|
MutableEdgePairs (const MutableEdgePairs &other);
|
||||||
|
virtual ~MutableEdgePairs ();
|
||||||
|
|
||||||
|
virtual void do_insert (const db::EdgePair &edge_pair) = 0;
|
||||||
|
|
||||||
|
virtual void do_transform (const db::Trans &t) = 0;
|
||||||
|
virtual void do_transform (const db::ICplxTrans &t) = 0;
|
||||||
|
virtual void do_transform (const db::IMatrix2d &t) = 0;
|
||||||
|
virtual void do_transform (const db::IMatrix3d &t) = 0;
|
||||||
|
|
||||||
|
virtual void flatten () = 0;
|
||||||
|
|
||||||
|
virtual void reserve (size_t n) = 0;
|
||||||
|
|
||||||
|
void transform (const db::UnitTrans &) { }
|
||||||
|
void transform (const db::Disp &t) { do_transform (db::Trans (t)); }
|
||||||
|
void transform (const db::Trans &t) { do_transform (t); }
|
||||||
|
void transform (const db::ICplxTrans &t) { do_transform (t); }
|
||||||
|
void transform (const db::IMatrix2d &t) { do_transform (t); }
|
||||||
|
void transform (const db::IMatrix3d &t) { do_transform (t); }
|
||||||
|
|
||||||
|
void insert (const db::EdgePair &edge_pair) { do_insert (edge_pair); }
|
||||||
|
void insert (const db::Shape &shape);
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void insert (const db::Shape &shape, const T &trans)
|
||||||
|
{
|
||||||
|
if (shape.is_edge_pair ()) {
|
||||||
|
db::EdgePair ep = shape.edge_pair ();
|
||||||
|
ep.transform (trans);
|
||||||
|
insert (ep);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Iter>
|
||||||
|
void insert (const Iter &b, const Iter &e)
|
||||||
|
{
|
||||||
|
reserve (count () + (e - b));
|
||||||
|
for (Iter i = b; i != e; ++i) {
|
||||||
|
insert (*i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Iter>
|
||||||
|
void insert_seq (const Iter &seq)
|
||||||
|
{
|
||||||
|
for (Iter i = seq; ! i.at_end (); ++i) {
|
||||||
|
insert (*i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
@ -0,0 +1,107 @@
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
KLayout Layout Viewer
|
||||||
|
Copyright (C) 2006-2021 Matthias Koefferlein
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "dbMutableEdges.h"
|
||||||
|
|
||||||
|
namespace db
|
||||||
|
{
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------------------------------
|
||||||
|
// MutableEdges implementation
|
||||||
|
|
||||||
|
MutableEdges::MutableEdges ()
|
||||||
|
: AsIfFlatEdges ()
|
||||||
|
{
|
||||||
|
// .. nothing yet ..
|
||||||
|
}
|
||||||
|
|
||||||
|
MutableEdges::MutableEdges (const MutableEdges &other)
|
||||||
|
: AsIfFlatEdges (other)
|
||||||
|
{
|
||||||
|
// .. nothing yet ..
|
||||||
|
}
|
||||||
|
|
||||||
|
MutableEdges::~MutableEdges ()
|
||||||
|
{
|
||||||
|
// .. nothing yet ..
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MutableEdges::insert (const db::Box &box)
|
||||||
|
{
|
||||||
|
if (! box.empty () && box.width () > 0 && box.height () > 0) {
|
||||||
|
do_insert (db::Edge (box.lower_left (), box.upper_left ()));
|
||||||
|
do_insert (db::Edge (box.upper_left (), box.upper_right ()));
|
||||||
|
do_insert (db::Edge (box.upper_right (), box.lower_right ()));
|
||||||
|
do_insert (db::Edge (box.lower_right (), box.lower_left ()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MutableEdges::insert (const db::Path &path)
|
||||||
|
{
|
||||||
|
if (path.points () > 0) {
|
||||||
|
insert (path.polygon ());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MutableEdges::insert (const db::Polygon &polygon)
|
||||||
|
{
|
||||||
|
if (polygon.holes () > 0 || polygon.vertices () > 0) {
|
||||||
|
for (db::Polygon::polygon_edge_iterator e = polygon.begin_edge (); ! e.at_end (); ++e) {
|
||||||
|
do_insert (*e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MutableEdges::insert (const db::SimplePolygon &polygon)
|
||||||
|
{
|
||||||
|
if (polygon.vertices () > 0) {
|
||||||
|
for (db::SimplePolygon::polygon_edge_iterator e = polygon.begin_edge (); ! e.at_end (); ++e) {
|
||||||
|
do_insert (*e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MutableEdges::insert (const db::Shape &shape)
|
||||||
|
{
|
||||||
|
if (shape.is_polygon () || shape.is_path () || shape.is_box ()) {
|
||||||
|
|
||||||
|
db::Polygon poly;
|
||||||
|
shape.polygon (poly);
|
||||||
|
insert (poly);
|
||||||
|
|
||||||
|
} else if (shape.is_edge ()) {
|
||||||
|
|
||||||
|
db::Edge edge;
|
||||||
|
shape.edge (edge);
|
||||||
|
do_insert (edge);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,114 @@
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
KLayout Layout Viewer
|
||||||
|
Copyright (C) 2006-2021 Matthias Koefferlein
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef HDR_dbMutableEdges
|
||||||
|
#define HDR_dbMutableEdges
|
||||||
|
|
||||||
|
#include "dbCommon.h"
|
||||||
|
|
||||||
|
#include "dbAsIfFlatEdges.h"
|
||||||
|
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
namespace db {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief An interface representing mutable edge collections
|
||||||
|
*
|
||||||
|
* Mutable edge collections offer insert, transform, flatten and other manipulation functions.
|
||||||
|
*/
|
||||||
|
class DB_PUBLIC MutableEdges
|
||||||
|
: public AsIfFlatEdges
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MutableEdges ();
|
||||||
|
MutableEdges (const MutableEdges &other);
|
||||||
|
virtual ~MutableEdges ();
|
||||||
|
|
||||||
|
virtual void do_transform (const db::Trans &t) = 0;
|
||||||
|
virtual void do_transform (const db::ICplxTrans &t) = 0;
|
||||||
|
virtual void do_transform (const db::IMatrix2d &t) = 0;
|
||||||
|
virtual void do_transform (const db::IMatrix3d &t) = 0;
|
||||||
|
|
||||||
|
virtual void flatten () = 0;
|
||||||
|
|
||||||
|
virtual void reserve (size_t n) = 0;
|
||||||
|
|
||||||
|
virtual void do_insert (const db::Edge &edge) = 0;
|
||||||
|
|
||||||
|
void transform (const db::UnitTrans &) { }
|
||||||
|
void transform (const db::Disp &t) { do_transform (db::Trans (t)); }
|
||||||
|
void transform (const db::Trans &t) { do_transform (t); }
|
||||||
|
void transform (const db::ICplxTrans &t) { do_transform (t); }
|
||||||
|
void transform (const db::IMatrix2d &t) { do_transform (t); }
|
||||||
|
void transform (const db::IMatrix3d &t) { do_transform (t); }
|
||||||
|
|
||||||
|
void insert (const db::Edge &edge) { do_insert (edge); }
|
||||||
|
void insert (const db::Box &box);
|
||||||
|
void insert (const db::Path &path);
|
||||||
|
void insert (const db::SimplePolygon &polygon);
|
||||||
|
void insert (const db::Polygon &polygon);
|
||||||
|
void insert (const db::Shape &shape);
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void insert (const db::Shape &shape, const T &trans)
|
||||||
|
{
|
||||||
|
if (shape.is_polygon () || shape.is_path () || shape.is_box ()) {
|
||||||
|
|
||||||
|
db::Polygon poly;
|
||||||
|
shape.polygon (poly);
|
||||||
|
poly.transform (trans);
|
||||||
|
insert (poly);
|
||||||
|
|
||||||
|
} else if (shape.is_edge ()) {
|
||||||
|
|
||||||
|
db::Edge edge;
|
||||||
|
shape.edge (edge);
|
||||||
|
edge.transform (trans);
|
||||||
|
insert (edge);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Iter>
|
||||||
|
void insert (const Iter &b, const Iter &e)
|
||||||
|
{
|
||||||
|
reserve (count () + (e - b));
|
||||||
|
for (Iter i = b; i != e; ++i) {
|
||||||
|
insert (*i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Iter>
|
||||||
|
void insert_seq (const Iter &seq)
|
||||||
|
{
|
||||||
|
for (Iter i = seq; ! i.at_end (); ++i) {
|
||||||
|
insert (*i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
@ -0,0 +1,90 @@
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
KLayout Layout Viewer
|
||||||
|
Copyright (C) 2006-2021 Matthias Koefferlein
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "dbMutableRegion.h"
|
||||||
|
|
||||||
|
namespace db
|
||||||
|
{
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------------------------------
|
||||||
|
// FlatRegion implementation
|
||||||
|
|
||||||
|
MutableRegion::MutableRegion ()
|
||||||
|
: AsIfFlatRegion ()
|
||||||
|
{
|
||||||
|
// .. nothing yet ..
|
||||||
|
}
|
||||||
|
|
||||||
|
MutableRegion::MutableRegion (const MutableRegion &other)
|
||||||
|
: AsIfFlatRegion (other)
|
||||||
|
{
|
||||||
|
// .. nothing yet ..
|
||||||
|
}
|
||||||
|
|
||||||
|
MutableRegion::~MutableRegion ()
|
||||||
|
{
|
||||||
|
// .. nothing yet ..
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MutableRegion::insert (const db::Box &box)
|
||||||
|
{
|
||||||
|
if (! box.empty () && box.width () > 0 && box.height () > 0) {
|
||||||
|
do_insert (db::Polygon (box));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MutableRegion::insert (const db::Path &path)
|
||||||
|
{
|
||||||
|
if (path.points () > 0) {
|
||||||
|
do_insert (path.polygon ());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MutableRegion::insert (const db::SimplePolygon &polygon)
|
||||||
|
{
|
||||||
|
if (polygon.vertices () > 0) {
|
||||||
|
db::Polygon poly;
|
||||||
|
poly.assign_hull (polygon.begin_hull (), polygon.end_hull ());
|
||||||
|
do_insert (poly);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MutableRegion::insert (const db::Shape &shape)
|
||||||
|
{
|
||||||
|
if (shape.is_polygon () || shape.is_path () || shape.is_box ()) {
|
||||||
|
db::Polygon poly;
|
||||||
|
shape.polygon (poly);
|
||||||
|
insert (poly);
|
||||||
|
} else if (shape.is_path ()) {
|
||||||
|
insert (shape.path ());
|
||||||
|
} else if (shape.is_box ()) {
|
||||||
|
insert (shape.box ());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,105 @@
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
KLayout Layout Viewer
|
||||||
|
Copyright (C) 2006-2021 Matthias Koefferlein
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef HDR_dbMutableRegion
|
||||||
|
#define HDR_dbMutableRegion
|
||||||
|
|
||||||
|
#include "dbCommon.h"
|
||||||
|
|
||||||
|
#include "dbAsIfFlatRegion.h"
|
||||||
|
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
namespace db {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief An interface representing mutable regions
|
||||||
|
*
|
||||||
|
* Mutable regions offer insert, transform, flatten and other manipulation functions.
|
||||||
|
*/
|
||||||
|
class DB_PUBLIC MutableRegion
|
||||||
|
: public AsIfFlatRegion
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MutableRegion ();
|
||||||
|
MutableRegion (const MutableRegion &other);
|
||||||
|
virtual ~MutableRegion ();
|
||||||
|
|
||||||
|
virtual void do_insert (const db::Polygon &polygon) = 0;
|
||||||
|
|
||||||
|
void transform (const db::UnitTrans &) { }
|
||||||
|
void transform (const db::Disp &t) { do_transform (db::Trans (t)); }
|
||||||
|
void transform (const db::Trans &t) { do_transform (t); }
|
||||||
|
void transform (const db::ICplxTrans &t) { do_transform (t); }
|
||||||
|
void transform (const db::IMatrix2d &t) { do_transform (t); }
|
||||||
|
void transform (const db::IMatrix3d &t) { do_transform (t); }
|
||||||
|
|
||||||
|
virtual void do_transform (const db::Trans &t) = 0;
|
||||||
|
virtual void do_transform (const db::ICplxTrans &t) = 0;
|
||||||
|
virtual void do_transform (const db::IMatrix2d &t) = 0;
|
||||||
|
virtual void do_transform (const db::IMatrix3d &t) = 0;
|
||||||
|
|
||||||
|
virtual void flatten () = 0;
|
||||||
|
|
||||||
|
virtual void reserve (size_t n) = 0;
|
||||||
|
|
||||||
|
void insert (const db::Polygon &polygon) { do_insert (polygon); }
|
||||||
|
void insert (const db::Box &box);
|
||||||
|
void insert (const db::Path &path);
|
||||||
|
void insert (const db::SimplePolygon &polygon);
|
||||||
|
|
||||||
|
void insert (const db::Shape &shape);
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void insert (const db::Shape &shape, const T &trans)
|
||||||
|
{
|
||||||
|
if (shape.is_polygon () || shape.is_path () || shape.is_box ()) {
|
||||||
|
db::Polygon poly;
|
||||||
|
shape.polygon (poly);
|
||||||
|
poly.transform (trans);
|
||||||
|
insert (poly);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Iter>
|
||||||
|
void insert (const Iter &b, const Iter &e)
|
||||||
|
{
|
||||||
|
reserve (count () + (e - b));
|
||||||
|
for (Iter i = b; i != e; ++i) {
|
||||||
|
insert (*i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Iter>
|
||||||
|
void insert_seq (const Iter &seq)
|
||||||
|
{
|
||||||
|
for (Iter i = seq; ! i.at_end (); ++i) {
|
||||||
|
insert (*i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
KLayout Layout Viewer
|
||||||
|
Copyright (C) 2006-2021 Matthias Koefferlein
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "dbMutableTexts.h"
|
||||||
|
|
||||||
|
namespace db
|
||||||
|
{
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------------------------------
|
||||||
|
// MutableTexts implementation
|
||||||
|
|
||||||
|
MutableTexts::MutableTexts ()
|
||||||
|
: AsIfFlatTexts ()
|
||||||
|
{
|
||||||
|
// .. nothing yet ..
|
||||||
|
}
|
||||||
|
|
||||||
|
MutableTexts::MutableTexts (const MutableTexts &other)
|
||||||
|
: AsIfFlatTexts (other)
|
||||||
|
{
|
||||||
|
// .. nothing yet ..
|
||||||
|
}
|
||||||
|
|
||||||
|
MutableTexts::~MutableTexts ()
|
||||||
|
{
|
||||||
|
// .. nothing yet ..
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MutableTexts::insert (const db::Shape &shape)
|
||||||
|
{
|
||||||
|
if (shape.is_text ()) {
|
||||||
|
db::Text text;
|
||||||
|
shape.text (text);
|
||||||
|
insert (text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,100 @@
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
KLayout Layout Viewer
|
||||||
|
Copyright (C) 2006-2021 Matthias Koefferlein
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef HDR_dbMutableTexts
|
||||||
|
#define HDR_dbMutableTexts
|
||||||
|
|
||||||
|
#include "dbCommon.h"
|
||||||
|
|
||||||
|
#include "dbAsIfFlatTexts.h"
|
||||||
|
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
namespace db {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief An interface representing mutable text collections
|
||||||
|
*
|
||||||
|
* Mutable text collections offer insert, transform, flatten and other manipulation functions.
|
||||||
|
*/
|
||||||
|
class DB_PUBLIC MutableTexts
|
||||||
|
: public AsIfFlatTexts
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MutableTexts ();
|
||||||
|
MutableTexts (const MutableTexts &other);
|
||||||
|
virtual ~MutableTexts ();
|
||||||
|
|
||||||
|
virtual void do_insert (const db::Text &text) = 0;
|
||||||
|
|
||||||
|
virtual void do_transform (const db::Trans &t) = 0;
|
||||||
|
virtual void do_transform (const db::ICplxTrans &t) = 0;
|
||||||
|
virtual void do_transform (const db::IMatrix3d &t) = 0;
|
||||||
|
virtual void do_transform (const db::IMatrix2d &t) = 0;
|
||||||
|
|
||||||
|
virtual void flatten () = 0;
|
||||||
|
|
||||||
|
virtual void reserve (size_t n) = 0;
|
||||||
|
|
||||||
|
void transform (const db::UnitTrans &) { }
|
||||||
|
void transform (const db::Disp &t) { do_transform (db::Trans (t)); }
|
||||||
|
void transform (const db::Trans &t) { do_transform (t); }
|
||||||
|
void transform (const db::ICplxTrans &t) { do_transform (t); }
|
||||||
|
void transform (const db::IMatrix3d &t) { do_transform (t); }
|
||||||
|
void transform (const db::IMatrix2d &t) { do_transform (t); }
|
||||||
|
|
||||||
|
void insert (const db::Text &text) { do_insert (text); }
|
||||||
|
void insert (const db::Shape &shape);
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void insert (const db::Shape &shape, const T &trans)
|
||||||
|
{
|
||||||
|
if (shape.is_text ()) {
|
||||||
|
db::Text text = shape.text ();
|
||||||
|
text.transform (trans);
|
||||||
|
insert (text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Iter>
|
||||||
|
void insert (const Iter &b, const Iter &e)
|
||||||
|
{
|
||||||
|
reserve (count () + (e - b));
|
||||||
|
for (Iter i = b; i != e; ++i) {
|
||||||
|
insert (*i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Iter>
|
||||||
|
void insert_seq (const Iter &seq)
|
||||||
|
{
|
||||||
|
for (Iter i = seq; ! i.at_end (); ++i) {
|
||||||
|
insert (*i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
@ -204,6 +204,16 @@ Net::~Net ()
|
||||||
clear ();
|
clear ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Netlist *Net::netlist ()
|
||||||
|
{
|
||||||
|
return mp_circuit ? mp_circuit->netlist () : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Netlist *Net::netlist () const
|
||||||
|
{
|
||||||
|
return mp_circuit ? mp_circuit->netlist () : 0;
|
||||||
|
}
|
||||||
|
|
||||||
void Net::clear ()
|
void Net::clear ()
|
||||||
{
|
{
|
||||||
m_name.clear ();
|
m_name.clear ();
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,7 @@ class Circuit;
|
||||||
class DeviceTerminalDefinition;
|
class DeviceTerminalDefinition;
|
||||||
class DeviceClass;
|
class DeviceClass;
|
||||||
class Pin;
|
class Pin;
|
||||||
|
class Netlist;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief A reference to a terminal of a device
|
* @brief A reference to a terminal of a device
|
||||||
|
|
@ -418,6 +419,18 @@ public:
|
||||||
return mp_circuit;
|
return mp_circuit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the netlist the net lives in
|
||||||
|
* This pointer is 0 if the net is not part of a netlist.
|
||||||
|
*/
|
||||||
|
Netlist *netlist ();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the netlist the net lives in (const version)
|
||||||
|
* This pointer is 0 if the net is not part of a netlist.
|
||||||
|
*/
|
||||||
|
const Netlist *netlist () const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Clears the circuit
|
* @brief Clears the circuit
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ namespace db
|
||||||
// Netlist class implementation
|
// Netlist class implementation
|
||||||
|
|
||||||
Netlist::Netlist (NetlistManipulationCallbacks *callbacks)
|
Netlist::Netlist (NetlistManipulationCallbacks *callbacks)
|
||||||
: mp_callbacks (callbacks),
|
: m_case_sensitive (true), mp_callbacks (callbacks),
|
||||||
m_valid_topology (false), m_lock_count (0),
|
m_valid_topology (false), m_lock_count (0),
|
||||||
m_circuit_by_name (this, &Netlist::begin_circuits, &Netlist::end_circuits),
|
m_circuit_by_name (this, &Netlist::begin_circuits, &Netlist::end_circuits),
|
||||||
m_circuit_by_cell_index (this, &Netlist::begin_circuits, &Netlist::end_circuits),
|
m_circuit_by_cell_index (this, &Netlist::begin_circuits, &Netlist::end_circuits),
|
||||||
|
|
@ -44,7 +44,8 @@ Netlist::Netlist (NetlistManipulationCallbacks *callbacks)
|
||||||
}
|
}
|
||||||
|
|
||||||
Netlist::Netlist (const Netlist &other)
|
Netlist::Netlist (const Netlist &other)
|
||||||
: gsi::ObjectBase (other), tl::Object (other), m_valid_topology (false), m_lock_count (0),
|
: gsi::ObjectBase (other), tl::Object (other), m_case_sensitive (true),
|
||||||
|
m_valid_topology (false), m_lock_count (0),
|
||||||
m_circuit_by_name (this, &Netlist::begin_circuits, &Netlist::end_circuits),
|
m_circuit_by_name (this, &Netlist::begin_circuits, &Netlist::end_circuits),
|
||||||
m_circuit_by_cell_index (this, &Netlist::begin_circuits, &Netlist::end_circuits),
|
m_circuit_by_cell_index (this, &Netlist::begin_circuits, &Netlist::end_circuits),
|
||||||
m_device_abstract_by_name (this, &Netlist::begin_device_abstracts, &Netlist::end_device_abstracts),
|
m_device_abstract_by_name (this, &Netlist::begin_device_abstracts, &Netlist::end_device_abstracts),
|
||||||
|
|
@ -69,6 +70,8 @@ Netlist &Netlist::operator= (const Netlist &other)
|
||||||
|
|
||||||
clear ();
|
clear ();
|
||||||
|
|
||||||
|
set_case_sensitive (other.is_case_sensitive ());
|
||||||
|
|
||||||
std::map<const DeviceClass *, DeviceClass *> dct;
|
std::map<const DeviceClass *, DeviceClass *> dct;
|
||||||
for (const_device_class_iterator dc = other.begin_device_classes (); dc != other.end_device_classes (); ++dc) {
|
for (const_device_class_iterator dc = other.begin_device_classes (); dc != other.end_device_classes (); ++dc) {
|
||||||
DeviceClass *dc_new = dc->clone ();
|
DeviceClass *dc_new = dc->clone ();
|
||||||
|
|
@ -100,6 +103,34 @@ Netlist &Netlist::operator= (const Netlist &other)
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Netlist::set_case_sensitive (bool f)
|
||||||
|
{
|
||||||
|
m_case_sensitive = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Netlist::name_compare (bool case_sensitive, const std::string &n1, const std::string &n2)
|
||||||
|
{
|
||||||
|
// TODO: unicode support?
|
||||||
|
if (case_sensitive) {
|
||||||
|
return strcmp (n1.c_str (), n2.c_str ());
|
||||||
|
} else {
|
||||||
|
#if defined(_WIN32)
|
||||||
|
return _stricmp (n1.c_str (), n2.c_str ());
|
||||||
|
#else
|
||||||
|
return strcasecmp (n1.c_str (), n2.c_str ());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Netlist::normalize_name (bool case_sensitive, const std::string &n)
|
||||||
|
{
|
||||||
|
if (case_sensitive) {
|
||||||
|
return n;
|
||||||
|
} else {
|
||||||
|
return tl::to_upper_case (n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Netlist::circuits_changed ()
|
void Netlist::circuits_changed ()
|
||||||
{
|
{
|
||||||
m_circuit_by_cell_index.invalidate ();
|
m_circuit_by_cell_index.invalidate ();
|
||||||
|
|
@ -472,8 +503,10 @@ void Netlist::flatten ()
|
||||||
|
|
||||||
DeviceClass *Netlist::device_class_by_name (const std::string &name)
|
DeviceClass *Netlist::device_class_by_name (const std::string &name)
|
||||||
{
|
{
|
||||||
|
std::string nn = m_case_sensitive ? name : normalize_name (name);
|
||||||
|
|
||||||
for (device_class_iterator d = begin_device_classes (); d != end_device_classes (); ++d) {
|
for (device_class_iterator d = begin_device_classes (); d != end_device_classes (); ++d) {
|
||||||
if (d->name () == name) {
|
if (d->name () == nn) {
|
||||||
return d.operator-> ();
|
return d.operator-> ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -102,6 +102,19 @@ public:
|
||||||
*/
|
*/
|
||||||
void clear ();
|
void clear ();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns a value indicating whether the netlist names are case sensitive
|
||||||
|
*/
|
||||||
|
bool is_case_sensitive () const
|
||||||
|
{
|
||||||
|
return m_case_sensitive;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets a value indicating whether the netlist names are case sensitive
|
||||||
|
*/
|
||||||
|
void set_case_sensitive (bool f);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns a parsable string representation of the netlist
|
* @brief Returns a parsable string representation of the netlist
|
||||||
*
|
*
|
||||||
|
|
@ -225,7 +238,7 @@ public:
|
||||||
*/
|
*/
|
||||||
Circuit *circuit_by_name (const std::string &name)
|
Circuit *circuit_by_name (const std::string &name)
|
||||||
{
|
{
|
||||||
return m_circuit_by_name.object_by (name);
|
return m_circuit_by_name.object_by (normalize_name (name));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -235,7 +248,7 @@ public:
|
||||||
*/
|
*/
|
||||||
const Circuit *circuit_by_name (const std::string &name) const
|
const Circuit *circuit_by_name (const std::string &name) const
|
||||||
{
|
{
|
||||||
return m_circuit_by_name.object_by (name);
|
return m_circuit_by_name.object_by (normalize_name (name));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -429,7 +442,7 @@ public:
|
||||||
*/
|
*/
|
||||||
DeviceAbstract *device_abstract_by_name (const std::string &name)
|
DeviceAbstract *device_abstract_by_name (const std::string &name)
|
||||||
{
|
{
|
||||||
return m_device_abstract_by_name.object_by (name);
|
return m_device_abstract_by_name.object_by (normalize_name (name));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -439,7 +452,7 @@ public:
|
||||||
*/
|
*/
|
||||||
const DeviceAbstract *device_abstract_by_name (const std::string &name) const
|
const DeviceAbstract *device_abstract_by_name (const std::string &name) const
|
||||||
{
|
{
|
||||||
return m_device_abstract_by_name.object_by (name);
|
return m_device_abstract_by_name.object_by (normalize_name (name));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -502,10 +515,29 @@ public:
|
||||||
*/
|
*/
|
||||||
void combine_devices ();
|
void combine_devices ();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Compares two names with the given case sensitivity
|
||||||
|
*/
|
||||||
|
static int name_compare (bool case_sensitive, const std::string &n1, const std::string &n2);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Normalizes a name with the given case sensitivity
|
||||||
|
*/
|
||||||
|
static std::string normalize_name (bool case_sensitive, const std::string &n);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Normalizes a name with the given case sensitivity of the netlist
|
||||||
|
*/
|
||||||
|
std::string normalize_name (const std::string &n) const
|
||||||
|
{
|
||||||
|
return normalize_name (is_case_sensitive (), n);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class Circuit;
|
friend class Circuit;
|
||||||
friend class DeviceAbstract;
|
friend class DeviceAbstract;
|
||||||
|
|
||||||
|
bool m_case_sensitive;
|
||||||
tl::weak_ptr<db::NetlistManipulationCallbacks> mp_callbacks;
|
tl::weak_ptr<db::NetlistManipulationCallbacks> mp_callbacks;
|
||||||
circuit_list m_circuits;
|
circuit_list m_circuits;
|
||||||
device_class_list m_device_classes;
|
device_class_list m_device_classes;
|
||||||
|
|
|
||||||
|
|
@ -48,15 +48,12 @@ struct GlobalCompareOptions
|
||||||
debug_netcompare = tl::app_flag ("netlist-compare-debug-netcompare");
|
debug_netcompare = tl::app_flag ("netlist-compare-debug-netcompare");
|
||||||
// $KLAYOUT_NETLIST_COMPARE_DEBUG_NETGRAPH
|
// $KLAYOUT_NETLIST_COMPARE_DEBUG_NETGRAPH
|
||||||
debug_netgraph = tl::app_flag ("netlist-compare-debug-netgraph");
|
debug_netgraph = tl::app_flag ("netlist-compare-debug-netgraph");
|
||||||
// $KLAYOUT_NETLIST_COMPARE_CASE_SENSITIVE
|
|
||||||
compare_case_sensitive = tl::app_flag ("netlist-compare-case-sensitive");
|
|
||||||
m_is_initialized = true;
|
m_is_initialized = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool debug_netcompare;
|
bool debug_netcompare;
|
||||||
bool debug_netgraph;
|
bool debug_netgraph;
|
||||||
bool compare_case_sensitive;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_is_initialized;
|
bool m_is_initialized;
|
||||||
|
|
@ -90,29 +87,19 @@ namespace db
|
||||||
// --------------------------------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------------------------------
|
||||||
// A generic string compare
|
// A generic string compare
|
||||||
|
|
||||||
static int name_compare (const std::string &n1, const std::string &n2)
|
bool combined_case_sensitive (const db::Netlist *a, const db::Netlist *b)
|
||||||
{
|
{
|
||||||
// TODO: unicode support?
|
bool csa = a ? a->is_case_sensitive () : true;
|
||||||
if (options ()->compare_case_sensitive) {
|
bool csb = b ? b->is_case_sensitive () : true;
|
||||||
return strcmp (n1.c_str (), n2.c_str ());
|
return csa && csb;
|
||||||
} else {
|
|
||||||
#if defined(_WIN32)
|
|
||||||
return _stricmp (n1.c_str (), n2.c_str ());
|
|
||||||
#else
|
|
||||||
return strcasecmp (n1.c_str (), n2.c_str ());
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline std::string normalize_name (const std::string &n)
|
int name_compare (const db::Net *a, const db::Net *b)
|
||||||
{
|
{
|
||||||
if (options ()->compare_case_sensitive) {
|
return db::Netlist::name_compare (combined_case_sensitive (a->netlist (), b->netlist ()), a->name (), b->name ());
|
||||||
return n;
|
|
||||||
} else {
|
|
||||||
return tl::to_upper_case (n);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------------------------------
|
||||||
// DeviceCompare definition and implementation
|
// DeviceCompare definition and implementation
|
||||||
|
|
||||||
|
|
@ -404,11 +391,16 @@ class generic_categorizer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
generic_categorizer (bool with_name = true)
|
generic_categorizer (bool with_name = true)
|
||||||
: m_next_cat (0), m_with_name (with_name)
|
: m_next_cat (0), m_with_name (with_name), m_case_sensitive (true)
|
||||||
{
|
{
|
||||||
// .. nothing yet ..
|
// .. nothing yet ..
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void set_case_sensitive (bool f)
|
||||||
|
{
|
||||||
|
m_case_sensitive = f;
|
||||||
|
}
|
||||||
|
|
||||||
void same (const Obj *ca, const Obj *cb)
|
void same (const Obj *ca, const Obj *cb)
|
||||||
{
|
{
|
||||||
if (! ca && ! cb) {
|
if (! ca && ! cb) {
|
||||||
|
|
@ -471,7 +463,7 @@ public:
|
||||||
|
|
||||||
if (m_with_name) {
|
if (m_with_name) {
|
||||||
|
|
||||||
std::string cls_name = normalize_name (cls->name ());
|
std::string cls_name = db::Netlist::normalize_name (m_case_sensitive, cls->name ());
|
||||||
|
|
||||||
std::map<std::string, size_t>::const_iterator c = m_cat_by_name.find (cls_name);
|
std::map<std::string, size_t>::const_iterator c = m_cat_by_name.find (cls_name);
|
||||||
if (c != m_cat_by_name.end ()) {
|
if (c != m_cat_by_name.end ()) {
|
||||||
|
|
@ -498,6 +490,7 @@ public:
|
||||||
std::map<std::string, size_t> m_cat_by_name;
|
std::map<std::string, size_t> m_cat_by_name;
|
||||||
size_t m_next_cat;
|
size_t m_next_cat;
|
||||||
bool m_with_name;
|
bool m_with_name;
|
||||||
|
bool m_case_sensitive;
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
@ -559,6 +552,11 @@ public:
|
||||||
return m_strict_device_categories.find (cat) != m_strict_device_categories.end ();
|
return m_strict_device_categories.find (cat) != m_strict_device_categories.end ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void set_case_sensitive (bool f)
|
||||||
|
{
|
||||||
|
generic_categorizer::set_case_sensitive (f);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::set<size_t> m_strict_device_categories;
|
std::set<size_t> m_strict_device_categories;
|
||||||
};
|
};
|
||||||
|
|
@ -606,6 +604,11 @@ public:
|
||||||
{
|
{
|
||||||
return generic_categorizer<db::Circuit>::cat_for (cr);
|
return generic_categorizer<db::Circuit>::cat_for (cr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void set_case_sensitive (bool f)
|
||||||
|
{
|
||||||
|
generic_categorizer::set_case_sensitive (f);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
@ -1461,7 +1464,7 @@ NetGraphNode::net_less (const db::Net *a, const db::Net *b)
|
||||||
const std::string &pna = a->begin_pins ()->pin ()->name ();
|
const std::string &pna = a->begin_pins ()->pin ()->name ();
|
||||||
const std::string &pnb = b->begin_pins ()->pin ()->name ();
|
const std::string &pnb = b->begin_pins ()->pin ()->name ();
|
||||||
if (! pna.empty () && ! pnb.empty ()) {
|
if (! pna.empty () && ! pnb.empty ()) {
|
||||||
return name_compare (pna, pnb) < 0;
|
return db::Netlist::name_compare (combined_case_sensitive (a->netlist (), b->netlist ()), pna, pnb) < 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -1484,7 +1487,7 @@ NetGraphNode::edge_equal (const db::Net *a, const db::Net *b)
|
||||||
const std::string &pna = a->begin_pins ()->pin ()->name ();
|
const std::string &pna = a->begin_pins ()->pin ()->name ();
|
||||||
const std::string &pnb = b->begin_pins ()->pin ()->name ();
|
const std::string &pnb = b->begin_pins ()->pin ()->name ();
|
||||||
if (! pna.empty () && ! pnb.empty ()) {
|
if (! pna.empty () && ! pnb.empty ()) {
|
||||||
return name_compare (pna, pnb) == 0;
|
return db::Netlist::name_compare (combined_case_sensitive (a->netlist (), b->netlist ()), pna, pnb) == 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -2028,7 +2031,7 @@ NetGraph::derive_node_identities_for_edges (NetGraphNode::edge_iterator e, NetGr
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// propagate pairing in picky mode: this means we only accept exact a match if the node set
|
// propagate pairing in picky mode: this means we only accept a match if the node set
|
||||||
// is exactly identical and no ambiguous nodes are present when ambiguous nodes are forbidden
|
// is exactly identical and no ambiguous nodes are present when ambiguous nodes are forbidden
|
||||||
|
|
||||||
size_t bt_count = derive_node_identities_from_node_set (nodes, other_nodes, depth, n_branch, tentative, data);
|
size_t bt_count = derive_node_identities_from_node_set (nodes, other_nodes, depth, n_branch, tentative, data);
|
||||||
|
|
@ -2256,7 +2259,7 @@ namespace {
|
||||||
bool operator() (const std::pair<const NetGraphNode *, NetGraphNode::edge_iterator> &a, const std::pair<const NetGraphNode *, NetGraphNode::edge_iterator>b) const
|
bool operator() (const std::pair<const NetGraphNode *, NetGraphNode::edge_iterator> &a, const std::pair<const NetGraphNode *, NetGraphNode::edge_iterator>b) const
|
||||||
{
|
{
|
||||||
tl_assert (a.first->net () && b.first->net ());
|
tl_assert (a.first->net () && b.first->net ());
|
||||||
return name_compare (a.first->net ()->name (), b.first->net ()->name ()) < 0;
|
return name_compare (a.first->net (), b.first->net ()) < 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -2317,7 +2320,7 @@ static bool net_names_are_different (const db::Net *a, const db::Net *b)
|
||||||
if (! a || ! b || a->name ().empty () || b->name ().empty ()) {
|
if (! a || ! b || a->name ().empty () || b->name ().empty ()) {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
return name_compare (a->name (), b->name ()) != 0;
|
return name_compare (a, b) != 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2326,7 +2329,7 @@ static bool net_names_are_equal (const db::Net *a, const db::Net *b)
|
||||||
if (! a || ! b || a->name ().empty () || b->name ().empty ()) {
|
if (! a || ! b || a->name ().empty () || b->name ().empty ()) {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
return name_compare (a->name (), b->name ()) == 0;
|
return name_compare (a, b) == 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2354,7 +2357,7 @@ NetGraph::derive_node_identities_from_ambiguity_group (const NodeRange &nr, Devi
|
||||||
{
|
{
|
||||||
|
|
||||||
// marks the nodes from the ambiguity group as unknown so we don't revisit them (causing deep recursion)
|
// marks the nodes from the ambiguity group as unknown so we don't revisit them (causing deep recursion)
|
||||||
TentativeNodeMapping tn2unknown;
|
TentativeNodeMapping tn_temp;
|
||||||
|
|
||||||
// collect and mark the ambiguity combinations to consider
|
// collect and mark the ambiguity combinations to consider
|
||||||
std::vector<std::vector<std::pair<const NetGraphNode *, NetGraphNode::edge_iterator> >::const_iterator> iters1, iters2;
|
std::vector<std::vector<std::pair<const NetGraphNode *, NetGraphNode::edge_iterator> >::const_iterator> iters1, iters2;
|
||||||
|
|
@ -2363,7 +2366,7 @@ NetGraph::derive_node_identities_from_ambiguity_group (const NodeRange &nr, Devi
|
||||||
if (! i1->first->has_any_other ()) {
|
if (! i1->first->has_any_other ()) {
|
||||||
iters1.push_back (i1);
|
iters1.push_back (i1);
|
||||||
size_t ni = node_index_for_net (i1->first->net ());
|
size_t ni = node_index_for_net (i1->first->net ());
|
||||||
TentativeNodeMapping::map_to_unknown (&tn2unknown, this, ni);
|
TentativeNodeMapping::map_to_unknown (&tn_temp, this, ni);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2371,7 +2374,7 @@ NetGraph::derive_node_identities_from_ambiguity_group (const NodeRange &nr, Devi
|
||||||
if (! i2->first->has_any_other ()) {
|
if (! i2->first->has_any_other ()) {
|
||||||
iters2.push_back (i2);
|
iters2.push_back (i2);
|
||||||
size_t other_ni = data->other->node_index_for_net (i2->first->net ());
|
size_t other_ni = data->other->node_index_for_net (i2->first->net ());
|
||||||
TentativeNodeMapping::map_to_unknown (&tn2unknown, data->other, other_ni);
|
TentativeNodeMapping::map_to_unknown (&tn_temp, data->other, other_ni);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2460,7 +2463,22 @@ NetGraph::derive_node_identities_from_ambiguity_group (const NodeRange &nr, Devi
|
||||||
}
|
}
|
||||||
|
|
||||||
if (to_remove != iters2.end ()) {
|
if (to_remove != iters2.end ()) {
|
||||||
|
|
||||||
|
// Add the new pair to the temporary mapping (even in tentative mode)
|
||||||
|
// Reasoning: doing the mapping may render other nets incompatible, so to ensure "edges_are_compatible" works properly we
|
||||||
|
// need to lock the current pairs resources such as devices by listing them in the mapping. This is doing by "derive_*_equivalence" inside
|
||||||
|
// TentativeNodeMapping::map_pair
|
||||||
|
|
||||||
|
std::vector<std::pair<const NetGraphNode *, NetGraphNode::edge_iterator> >::const_iterator i2 = *to_remove;
|
||||||
|
|
||||||
|
size_t ni = node_index_for_net (i1->first->net ());
|
||||||
|
size_t other_ni = data->other->node_index_for_net (i2->first->net ());
|
||||||
|
|
||||||
|
TentativeNodeMapping::map_pair (&tn_temp, this, ni, data->other, other_ni, dm, dm_other, *data->device_equivalence, scm, scm_other, *data->subcircuit_equivalence, depth);
|
||||||
|
|
||||||
|
// now we can get rid of the node and reduce the "other" list of ambiguous nodes
|
||||||
iters2.erase (to_remove);
|
iters2.erase (to_remove);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! any && tentative) {
|
if (! any && tentative) {
|
||||||
|
|
@ -2631,7 +2649,7 @@ NetGraph::derive_node_identities_from_node_set (std::vector<std::pair<const NetG
|
||||||
indent_s += "*" + tl::to_string (n_branch) + " ";
|
indent_s += "*" + tl::to_string (n_branch) + " ";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (depth > data->max_depth) {
|
if (data->max_depth != std::numeric_limits<size_t>::max() && depth > data->max_depth) {
|
||||||
if (options ()->debug_netcompare) {
|
if (options ()->debug_netcompare) {
|
||||||
tl::info << indent_s << "max. depth exhausted (" << depth + 1 << ">" << data->max_depth << ")";
|
tl::info << indent_s << "max. depth exhausted (" << depth + 1 << ">" << data->max_depth << ")";
|
||||||
}
|
}
|
||||||
|
|
@ -2765,7 +2783,7 @@ NetGraph::derive_node_identities_from_node_set (std::vector<std::pair<const NetG
|
||||||
|
|
||||||
new_nodes += n;
|
new_nodes += n;
|
||||||
|
|
||||||
} else if (nr->num * n_branch > data->max_n_branch) {
|
} else if (data->max_n_branch != std::numeric_limits<size_t>::max () && double (nr->num) * double (n_branch) > double (data->max_n_branch)) {
|
||||||
|
|
||||||
if (options ()->debug_netcompare) {
|
if (options ()->debug_netcompare) {
|
||||||
tl::info << indent_s << "max. complexity exhausted (" << nr->num << "*" << n_branch << ">" << data->max_n_branch << ") - mismatch.";
|
tl::info << indent_s << "max. complexity exhausted (" << nr->num << "*" << n_branch << ">" << data->max_n_branch << ") - mismatch.";
|
||||||
|
|
@ -2810,11 +2828,18 @@ NetlistComparer::NetlistComparer (NetlistCompareLogger *logger)
|
||||||
m_cap_threshold = -1.0; // not set
|
m_cap_threshold = -1.0; // not set
|
||||||
m_res_threshold = -1.0; // not set
|
m_res_threshold = -1.0; // not set
|
||||||
|
|
||||||
m_max_depth = 50;
|
// NOTE: as the backtracking algorithm is recursive, we need to limit the number of steps to follow
|
||||||
m_max_n_branch = 500;
|
// Long chains can happen in case of depth-first because the backtracking algorithm will follow
|
||||||
|
// each successful path further to the very end. Depending on the circuit's complexity a long chain of
|
||||||
|
// jumps is possible leading to a deep stack. A value of 500 is compatible with 4M stack depth on a
|
||||||
|
// 64bit machine which is considered acceptable for now.
|
||||||
|
m_max_depth = 500;
|
||||||
|
|
||||||
|
m_max_n_branch = std::numeric_limits<size_t>::max ();
|
||||||
m_depth_first = true;
|
m_depth_first = true;
|
||||||
|
|
||||||
m_dont_consider_net_names = false;
|
m_dont_consider_net_names = false;
|
||||||
|
m_case_sensitive = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
NetlistComparer::~NetlistComparer ()
|
NetlistComparer::~NetlistComparer ()
|
||||||
|
|
@ -2887,6 +2912,7 @@ NetlistComparer::unmatched_circuits (db::Netlist *a, db::Netlist *b, std::vector
|
||||||
{
|
{
|
||||||
// we need to create a copy because this method is supposed to be const.
|
// we need to create a copy because this method is supposed to be const.
|
||||||
db::CircuitCategorizer circuit_categorizer = *mp_circuit_categorizer;
|
db::CircuitCategorizer circuit_categorizer = *mp_circuit_categorizer;
|
||||||
|
circuit_categorizer.set_case_sensitive (m_case_sensitive);
|
||||||
|
|
||||||
std::map<size_t, std::pair<std::vector<db::Circuit *>, std::vector<db::Circuit *> > > cat2circuits;
|
std::map<size_t, std::pair<std::vector<db::Circuit *>, std::vector<db::Circuit *> > > cat2circuits;
|
||||||
|
|
||||||
|
|
@ -2928,11 +2954,16 @@ NetlistComparer::unmatched_circuits (db::Netlist *a, db::Netlist *b, std::vector
|
||||||
bool
|
bool
|
||||||
NetlistComparer::compare (const db::Netlist *a, const db::Netlist *b) const
|
NetlistComparer::compare (const db::Netlist *a, const db::Netlist *b) const
|
||||||
{
|
{
|
||||||
|
m_case_sensitive = combined_case_sensitive (a, b);
|
||||||
|
|
||||||
// we need to create a copy because this method is supposed to be const.
|
// we need to create a copy because this method is supposed to be const.
|
||||||
db::CircuitCategorizer circuit_categorizer = *mp_circuit_categorizer;
|
db::CircuitCategorizer circuit_categorizer = *mp_circuit_categorizer;
|
||||||
db::DeviceCategorizer device_categorizer = *mp_device_categorizer;
|
db::DeviceCategorizer device_categorizer = *mp_device_categorizer;
|
||||||
db::CircuitPinMapper circuit_pin_mapper = *mp_circuit_pin_mapper;
|
db::CircuitPinMapper circuit_pin_mapper = *mp_circuit_pin_mapper;
|
||||||
|
|
||||||
|
circuit_categorizer.set_case_sensitive (m_case_sensitive);
|
||||||
|
device_categorizer.set_case_sensitive (m_case_sensitive);
|
||||||
|
|
||||||
bool good = true;
|
bool good = true;
|
||||||
|
|
||||||
std::map<size_t, std::pair<std::vector<const db::Circuit *>, std::vector<const db::Circuit *> > > cat2circuits;
|
std::map<size_t, std::pair<std::vector<const db::Circuit *>, std::vector<const db::Circuit *> > > cat2circuits;
|
||||||
|
|
@ -3008,7 +3039,7 @@ NetlistComparer::compare (const db::Netlist *a, const db::Netlist *b) const
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// device whether to use a device category in strict mode
|
// decide whether to use a device category in strict mode
|
||||||
|
|
||||||
device_categorizer.clear_strict_device_categories ();
|
device_categorizer.clear_strict_device_categories ();
|
||||||
|
|
||||||
|
|
@ -3745,14 +3776,14 @@ NetlistComparer::do_pin_assignment (const db::Circuit *c1, const db::NetGraph &g
|
||||||
for (db::Circuit::const_pin_iterator p = c2->begin_pins (); p != c2->end_pins (); ++p) {
|
for (db::Circuit::const_pin_iterator p = c2->begin_pins (); p != c2->end_pins (); ++p) {
|
||||||
const db::Net *net = c2->net_for_pin (p->id ());
|
const db::Net *net = c2->net_for_pin (p->id ());
|
||||||
if (!net && !p->name ().empty ()) {
|
if (!net && !p->name ().empty ()) {
|
||||||
abstract_pins_by_name.insert (std::make_pair (normalize_name (p->name ()), std::make_pair ((const db::Pin *) 0, (const db::Pin *) 0))).first->second.second = p.operator-> ();
|
abstract_pins_by_name.insert (std::make_pair (db::Netlist::normalize_name (m_case_sensitive, p->name ()), std::make_pair ((const db::Pin *) 0, (const db::Pin *) 0))).first->second.second = p.operator-> ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (db::Circuit::const_pin_iterator p = c1->begin_pins (); p != c1->end_pins (); ++p) {
|
for (db::Circuit::const_pin_iterator p = c1->begin_pins (); p != c1->end_pins (); ++p) {
|
||||||
const db::Net *net = c1->net_for_pin (p->id ());
|
const db::Net *net = c1->net_for_pin (p->id ());
|
||||||
if (!net && !p->name ().empty ()) {
|
if (!net && !p->name ().empty ()) {
|
||||||
abstract_pins_by_name.insert (std::make_pair (normalize_name (p->name ()), std::make_pair ((const db::Pin *) 0, (const db::Pin *) 0))).first->second.first = p.operator-> ();
|
abstract_pins_by_name.insert (std::make_pair (db::Netlist::normalize_name (m_case_sensitive, p->name ()), std::make_pair ((const db::Pin *) 0, (const db::Pin *) 0))).first->second.first = p.operator-> ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -364,6 +364,7 @@ protected:
|
||||||
size_t m_max_depth;
|
size_t m_max_depth;
|
||||||
bool m_depth_first;
|
bool m_depth_first;
|
||||||
bool m_dont_consider_net_names;
|
bool m_dont_consider_net_names;
|
||||||
|
mutable bool m_case_sensitive;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,33 +35,44 @@ NetlistExtractor::NetlistExtractor ()
|
||||||
// .. nothing yet ..
|
// .. nothing yet ..
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetlistExtractor::set_joined_net_names (const std::string &jnn)
|
void NetlistExtractor::set_joined_net_names (const std::list<tl::GlobPattern> &jnn)
|
||||||
{
|
{
|
||||||
m_joined_net_names = jnn;
|
m_joined_net_names = jnn;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetlistExtractor::set_joined_net_names (const std::string &cellname, const std::string &jnn)
|
void NetlistExtractor::set_joined_net_names (const std::string &cellname, const std::list<tl::GlobPattern> &jnn)
|
||||||
{
|
{
|
||||||
m_joined_net_names_per_cell.push_back (std::make_pair (cellname, jnn));
|
m_joined_net_names_per_cell.push_back (std::make_pair (cellname, jnn));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NetlistExtractor::set_joined_nets (const std::list<std::set<std::string> > &jnn)
|
||||||
|
{
|
||||||
|
m_joined_nets = jnn;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetlistExtractor::set_joined_nets (const std::string &cell_name, const std::list<std::set<std::string> > &jnn)
|
||||||
|
{
|
||||||
|
m_joined_nets_per_cell.push_back (std::make_pair (cell_name, jnn));
|
||||||
|
}
|
||||||
|
|
||||||
void NetlistExtractor::set_include_floating_subcircuits (bool f)
|
void NetlistExtractor::set_include_floating_subcircuits (bool f)
|
||||||
{
|
{
|
||||||
m_include_floating_subcircuits = f;
|
m_include_floating_subcircuits = f;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
build_net_name_equivalence (const db::Layout *layout, const db::Connectivity &conn, db::property_names_id_type net_name_id, const std::string &joined_net_names, tl::equivalence_clusters<size_t> &eq)
|
build_net_name_equivalence (const db::Layout *layout, const db::Connectivity &conn, db::property_names_id_type net_name_id, const std::list<tl::GlobPattern> &jn_pattern, tl::equivalence_clusters<size_t> &eq)
|
||||||
{
|
{
|
||||||
std::map<std::string, std::set<size_t> > prop_by_name;
|
std::map<std::string, std::set<size_t> > prop_by_name;
|
||||||
tl::GlobPattern jn_pattern (joined_net_names);
|
|
||||||
|
|
||||||
for (db::PropertiesRepository::iterator i = layout->properties_repository ().begin (); i != layout->properties_repository ().end (); ++i) {
|
for (db::PropertiesRepository::iterator i = layout->properties_repository ().begin (); i != layout->properties_repository ().end (); ++i) {
|
||||||
for (db::PropertiesRepository::properties_set::const_iterator p = i->second.begin (); p != i->second.end (); ++p) {
|
for (db::PropertiesRepository::properties_set::const_iterator p = i->second.begin (); p != i->second.end (); ++p) {
|
||||||
if (p->first == net_name_id) {
|
if (p->first == net_name_id) {
|
||||||
std::string nn = p->second.to_string ();
|
std::string nn = p->second.to_string ();
|
||||||
if (jn_pattern.match (nn)) {
|
for (std::list<tl::GlobPattern>::const_iterator jp = jn_pattern.begin (); jp != jn_pattern.end (); ++jp) {
|
||||||
prop_by_name [nn].insert (db::prop_id_to_attr (i->first));
|
if (jp->match (nn)) {
|
||||||
|
prop_by_name [nn].insert (db::prop_id_to_attr (i->first));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -70,16 +81,20 @@ build_net_name_equivalence (const db::Layout *layout, const db::Connectivity &co
|
||||||
// include pseudo-attributes for global nets to implement "join_with" for global nets
|
// include pseudo-attributes for global nets to implement "join_with" for global nets
|
||||||
for (size_t gid = 0; gid < conn.global_nets (); ++gid) {
|
for (size_t gid = 0; gid < conn.global_nets (); ++gid) {
|
||||||
const std::string &gn = conn.global_net_name (gid);
|
const std::string &gn = conn.global_net_name (gid);
|
||||||
if (jn_pattern.match (gn)) {
|
for (std::list<tl::GlobPattern>::const_iterator jp = jn_pattern.begin (); jp != jn_pattern.end (); ++jp) {
|
||||||
prop_by_name [gn].insert (db::global_net_id_to_attr (gid));
|
if (jp->match (gn)) {
|
||||||
|
prop_by_name [gn].insert (db::global_net_id_to_attr (gid));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const db::repository<db::Text> &text_repository = layout->shape_repository ().repository (db::object_tag<db::Text> ());
|
const db::repository<db::Text> &text_repository = layout->shape_repository ().repository (db::object_tag<db::Text> ());
|
||||||
for (db::repository<db::Text>::iterator t = text_repository.begin (); t != text_repository.end (); ++t) {
|
for (db::repository<db::Text>::iterator t = text_repository.begin (); t != text_repository.end (); ++t) {
|
||||||
std::string nn = t->string ();
|
std::string nn = t->string ();
|
||||||
if (jn_pattern.match (nn)) {
|
for (std::list<tl::GlobPattern>::const_iterator jp = jn_pattern.begin (); jp != jn_pattern.end (); ++jp) {
|
||||||
prop_by_name [nn].insert (db::text_ref_to_attr (t.operator-> ()));
|
if (jp->match (nn)) {
|
||||||
|
prop_by_name [nn].insert (db::text_ref_to_attr (t.operator-> ()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -93,6 +108,58 @@ build_net_name_equivalence (const db::Layout *layout, const db::Connectivity &co
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
build_net_name_equivalence_for_explicit_connections (const db::Layout *layout, const db::Connectivity &conn, db::property_names_id_type net_name_id, const std::set<std::string> &nets_to_join, tl::equivalence_clusters<size_t> &eq)
|
||||||
|
{
|
||||||
|
std::map<std::string, std::set<size_t> > prop_by_name;
|
||||||
|
|
||||||
|
for (db::PropertiesRepository::iterator i = layout->properties_repository ().begin (); i != layout->properties_repository ().end (); ++i) {
|
||||||
|
for (db::PropertiesRepository::properties_set::const_iterator p = i->second.begin (); p != i->second.end (); ++p) {
|
||||||
|
if (p->first == net_name_id) {
|
||||||
|
std::string nn = p->second.to_string ();
|
||||||
|
if (nets_to_join.find (nn) != nets_to_join.end ()) {
|
||||||
|
prop_by_name [nn].insert (db::prop_id_to_attr (i->first));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// include pseudo-attributes for global nets to implement "join_with" for global nets
|
||||||
|
for (size_t gid = 0; gid < conn.global_nets (); ++gid) {
|
||||||
|
const std::string &gn = conn.global_net_name (gid);
|
||||||
|
if (nets_to_join.find (gn) != nets_to_join.end ()) {
|
||||||
|
prop_by_name [gn].insert (db::global_net_id_to_attr (gid));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const db::repository<db::Text> &text_repository = layout->shape_repository ().repository (db::object_tag<db::Text> ());
|
||||||
|
for (db::repository<db::Text>::iterator t = text_repository.begin (); t != text_repository.end (); ++t) {
|
||||||
|
std::string nn = t->string ();
|
||||||
|
if (nets_to_join.find (nn) != nets_to_join.end ()) {
|
||||||
|
prop_by_name [nn].insert (db::text_ref_to_attr (t.operator-> ()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// first inter-name equivalence (this implies implicit connections for all n1 and n2 labels)
|
||||||
|
for (std::map<std::string, std::set<size_t> >::const_iterator pn = prop_by_name.begin (); pn != prop_by_name.end (); ++pn) {
|
||||||
|
std::set<size_t>::const_iterator p = pn->second.begin ();
|
||||||
|
std::set<size_t>::const_iterator p0 = p;
|
||||||
|
while (p != pn->second.end ()) {
|
||||||
|
eq.same (*p0, *p);
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// second intra-name equivalence
|
||||||
|
for (std::map<std::string, std::set<size_t> >::const_iterator pn1 = prop_by_name.begin (); pn1 != prop_by_name.end (); ++pn1) {
|
||||||
|
std::map<std::string, std::set<size_t> >::const_iterator pn2 = pn1;
|
||||||
|
++pn2;
|
||||||
|
for ( ; pn2 != prop_by_name.end (); ++pn2) {
|
||||||
|
eq.same (*pn1->second.begin (), *pn2->second.begin ());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
NetlistExtractor::extract_nets (const db::DeepShapeStore &dss, unsigned int layout_index, const db::Connectivity &conn, db::Netlist &nl, hier_clusters_type &clusters)
|
NetlistExtractor::extract_nets (const db::DeepShapeStore &dss, unsigned int layout_index, const db::Connectivity &conn, db::Netlist &nl, hier_clusters_type &clusters)
|
||||||
{
|
{
|
||||||
|
|
@ -114,15 +181,31 @@ NetlistExtractor::extract_nets (const db::DeepShapeStore &dss, unsigned int layo
|
||||||
|
|
||||||
std::map<db::cell_index_type, tl::equivalence_clusters<size_t> > net_name_equivalence;
|
std::map<db::cell_index_type, tl::equivalence_clusters<size_t> > net_name_equivalence;
|
||||||
if (m_text_annot_name_id.first) {
|
if (m_text_annot_name_id.first) {
|
||||||
|
|
||||||
if (! m_joined_net_names.empty ()) {
|
if (! m_joined_net_names.empty ()) {
|
||||||
build_net_name_equivalence (mp_layout, conn, m_text_annot_name_id.second, m_joined_net_names, net_name_equivalence [hier_clusters_type::top_cell_index]);
|
build_net_name_equivalence (mp_layout, conn, m_text_annot_name_id.second, m_joined_net_names, net_name_equivalence [hier_clusters_type::top_cell_index]);
|
||||||
}
|
}
|
||||||
for (std::list<std::pair<std::string, std::string> >::const_iterator m = m_joined_net_names_per_cell.begin (); m != m_joined_net_names_per_cell.end (); ++m) {
|
for (std::list<std::pair<std::string, std::list<tl::GlobPattern> > >::const_iterator m = m_joined_net_names_per_cell.begin (); m != m_joined_net_names_per_cell.end (); ++m) {
|
||||||
std::pair<bool, db::cell_index_type> cp = mp_layout->cell_by_name (m->first.c_str ());
|
std::pair<bool, db::cell_index_type> cp = mp_layout->cell_by_name (m->first.c_str ());
|
||||||
if (cp.first) {
|
if (cp.first) {
|
||||||
build_net_name_equivalence (mp_layout, conn, m_text_annot_name_id.second, m->second, net_name_equivalence [cp.second]);
|
build_net_name_equivalence (mp_layout, conn, m_text_annot_name_id.second, m->second, net_name_equivalence [cp.second]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (! m_joined_nets.empty ()) {
|
||||||
|
for (std::list<std::set<std::string> >::const_iterator n = m_joined_nets.begin (); n != m_joined_nets.end (); ++n) {
|
||||||
|
build_net_name_equivalence_for_explicit_connections (mp_layout, conn, m_text_annot_name_id.second, *n, net_name_equivalence [hier_clusters_type::top_cell_index]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (std::list<std::pair<std::string, std::list<std::set<std::string> > > >::const_iterator m = m_joined_nets_per_cell.begin (); m != m_joined_nets_per_cell.end (); ++m) {
|
||||||
|
std::pair<bool, db::cell_index_type> cp = mp_layout->cell_by_name (m->first.c_str ());
|
||||||
|
if (cp.first) {
|
||||||
|
for (std::list<std::set<std::string> >::const_iterator n = m->second.begin (); n != m->second.end (); ++n) {
|
||||||
|
build_net_name_equivalence_for_explicit_connections (mp_layout, conn, m_text_annot_name_id.second, *n, net_name_equivalence [cp.second]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// the big part: actually extract the nets
|
// the big part: actually extract the nets
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@
|
||||||
#include "dbCommon.h"
|
#include "dbCommon.h"
|
||||||
#include "dbHierNetworkProcessor.h"
|
#include "dbHierNetworkProcessor.h"
|
||||||
#include "dbNetShape.h"
|
#include "dbNetShape.h"
|
||||||
|
#include "tlGlobPattern.h"
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
@ -104,23 +105,30 @@ public:
|
||||||
* @brief Sets the joined net names attribute
|
* @brief Sets the joined net names attribute
|
||||||
* This is a glob expression rendering net names where partial nets with the
|
* This is a glob expression rendering net names where partial nets with the
|
||||||
* same name are joined even without explicit connection.
|
* same name are joined even without explicit connection.
|
||||||
|
* The cell-less version applies to top level cells only.
|
||||||
*/
|
*/
|
||||||
void set_joined_net_names (const std::string &jnn);
|
void set_joined_net_names (const std::list<tl::GlobPattern> &jnn);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Sets the joined net names attribute for a given cell name
|
* @brief Sets the joined net names attribute for a given cell name
|
||||||
* While the single-parameter set_joined_net_names only acts on the top cell, this
|
* While the single-parameter set_joined_net_names only acts on the top cell, this
|
||||||
* version will act on the cell with the given name.
|
* version will act on the cell with the given name.
|
||||||
*/
|
*/
|
||||||
void set_joined_net_names (const std::string &cell_name, const std::string &jnn);
|
void set_joined_net_names (const std::string &cell_name, const std::list<tl::GlobPattern> &jnn);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Gets the joined net names expression
|
* @brief Sets the joined nets attribute
|
||||||
|
* This specifies a list of net names to join. Each join group is a set of names which specifies the net
|
||||||
|
* names that are to be connected. Multiple such groups can be specified. Each net name listed in a
|
||||||
|
* group implies implicit joining of the corresponding labels into one net.
|
||||||
|
* The cell-less version applies to top level cells only.
|
||||||
*/
|
*/
|
||||||
const std::string &joined_net_names () const
|
void set_joined_nets (const std::list<std::set<std::string> > &jnn);
|
||||||
{
|
|
||||||
return m_joined_net_names;
|
/**
|
||||||
}
|
* @brief Sets the joined nets attribute per cell
|
||||||
|
*/
|
||||||
|
void set_joined_nets (const std::string &cell_name, const std::list<std::set<std::string> > &jnn);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Extract the nets
|
* @brief Extract the nets
|
||||||
|
|
@ -135,8 +143,10 @@ private:
|
||||||
std::pair<bool, db::property_names_id_type> m_text_annot_name_id;
|
std::pair<bool, db::property_names_id_type> m_text_annot_name_id;
|
||||||
std::pair<bool, db::property_names_id_type> m_device_annot_name_id;
|
std::pair<bool, db::property_names_id_type> m_device_annot_name_id;
|
||||||
std::pair<bool, db::property_names_id_type> m_terminal_annot_name_id;
|
std::pair<bool, db::property_names_id_type> m_terminal_annot_name_id;
|
||||||
std::string m_joined_net_names;
|
std::list<tl::GlobPattern> m_joined_net_names;
|
||||||
std::list<std::pair<std::string, std::string> > m_joined_net_names_per_cell;
|
std::list<std::pair<std::string, std::list<tl::GlobPattern> > > m_joined_net_names_per_cell;
|
||||||
|
std::list<std::set<std::string> > m_joined_nets;
|
||||||
|
std::list<std::pair<std::string, std::list<std::set<std::string> > > > m_joined_nets_per_cell;
|
||||||
bool m_include_floating_subcircuits;
|
bool m_include_floating_subcircuits;
|
||||||
|
|
||||||
bool instance_is_device (db::properties_id_type prop_id) const;
|
bool instance_is_device (db::properties_id_type prop_id) const;
|
||||||
|
|
|
||||||
|
|
@ -299,6 +299,9 @@ void NetlistSpiceReader::read (tl::InputStream &stream, db::Netlist &netlist)
|
||||||
m_global_nets.clear ();
|
m_global_nets.clear ();
|
||||||
m_circuits_read.clear ();
|
m_circuits_read.clear ();
|
||||||
|
|
||||||
|
// SPICE netlists are case insensitive
|
||||||
|
netlist.set_case_sensitive (false);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
mp_delegate->start (&netlist);
|
mp_delegate->start (&netlist);
|
||||||
|
|
@ -775,13 +778,7 @@ std::string NetlistSpiceReader::read_name_with_case (tl::Extractor &ex)
|
||||||
|
|
||||||
std::string NetlistSpiceReader::read_name (tl::Extractor &ex)
|
std::string NetlistSpiceReader::read_name (tl::Extractor &ex)
|
||||||
{
|
{
|
||||||
// TODO: allow configuring Spice reader as case sensitive?
|
return mp_netlist->normalize_name (read_name_with_case (ex));
|
||||||
// this is easy to do: just avoid to_upper here:
|
|
||||||
#if 1
|
|
||||||
return tl::to_upper_case (read_name_with_case (ex));
|
|
||||||
#else
|
|
||||||
return read_name_with_case (ex);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NetlistSpiceReader::read_element (tl::Extractor &ex, const std::string &element, const std::string &name)
|
bool NetlistSpiceReader::read_element (tl::Extractor &ex, const std::string &element, const std::string &name)
|
||||||
|
|
|
||||||
|
|
@ -131,13 +131,13 @@ Region::clear ()
|
||||||
void
|
void
|
||||||
Region::reserve (size_t n)
|
Region::reserve (size_t n)
|
||||||
{
|
{
|
||||||
flat_region ()->reserve (n);
|
mutable_region ()->reserve (n);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
Region &Region::transform (const T &trans)
|
Region &Region::transform (const T &trans)
|
||||||
{
|
{
|
||||||
flat_region ()->transform (trans);
|
mutable_region ()->transform (trans);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -151,7 +151,7 @@ template DB_PUBLIC Region &Region::transform (const db::IMatrix3d &);
|
||||||
template <class Sh>
|
template <class Sh>
|
||||||
void Region::insert (const Sh &shape)
|
void Region::insert (const Sh &shape)
|
||||||
{
|
{
|
||||||
flat_region ()->insert (shape);
|
mutable_region ()->insert (shape);
|
||||||
}
|
}
|
||||||
|
|
||||||
template DB_PUBLIC void Region::insert (const db::Box &);
|
template DB_PUBLIC void Region::insert (const db::Box &);
|
||||||
|
|
@ -161,31 +161,36 @@ template DB_PUBLIC void Region::insert (const db::Path &);
|
||||||
|
|
||||||
void Region::insert (const db::Shape &shape)
|
void Region::insert (const db::Shape &shape)
|
||||||
{
|
{
|
||||||
flat_region ()->insert (shape);
|
mutable_region ()->insert (shape);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
void Region::insert (const db::Shape &shape, const T &trans)
|
void Region::insert (const db::Shape &shape, const T &trans)
|
||||||
{
|
{
|
||||||
flat_region ()->insert (shape, trans);
|
mutable_region ()->insert (shape, trans);
|
||||||
}
|
}
|
||||||
|
|
||||||
template DB_PUBLIC void Region::insert (const db::Shape &, const db::ICplxTrans &);
|
template DB_PUBLIC void Region::insert (const db::Shape &, const db::ICplxTrans &);
|
||||||
template DB_PUBLIC void Region::insert (const db::Shape &, const db::Trans &);
|
template DB_PUBLIC void Region::insert (const db::Shape &, const db::Trans &);
|
||||||
template DB_PUBLIC void Region::insert (const db::Shape &, const db::Disp &);
|
template DB_PUBLIC void Region::insert (const db::Shape &, const db::Disp &);
|
||||||
|
|
||||||
FlatRegion *
|
MutableRegion *
|
||||||
Region::flat_region ()
|
Region::mutable_region ()
|
||||||
{
|
{
|
||||||
FlatRegion *region = dynamic_cast<FlatRegion *> (mp_delegate);
|
MutableRegion *region = dynamic_cast<MutableRegion *> (mp_delegate);
|
||||||
if (! region) {
|
if (! region) {
|
||||||
region = new FlatRegion ();
|
|
||||||
|
FlatRegion *flat_region = new FlatRegion ();
|
||||||
|
region = flat_region;
|
||||||
|
|
||||||
if (mp_delegate) {
|
if (mp_delegate) {
|
||||||
region->RegionDelegate::operator= (*mp_delegate); // copy basic flags
|
flat_region->RegionDelegate::operator= (*mp_delegate); // copy basic flags
|
||||||
region->insert_seq (begin ());
|
flat_region->insert_seq (begin ());
|
||||||
region->set_is_merged (mp_delegate->is_merged ());
|
flat_region->set_is_merged (mp_delegate->is_merged ());
|
||||||
}
|
}
|
||||||
set_delegate (region);
|
|
||||||
|
set_delegate (flat_region);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return region;
|
return region;
|
||||||
|
|
@ -276,6 +281,13 @@ Region::smoothed (coord_type d, bool keep_hv) const
|
||||||
return processed (SmoothingProcessor (d, keep_hv));
|
return processed (SmoothingProcessor (d, keep_hv));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
db::Region &
|
||||||
|
Region::flatten ()
|
||||||
|
{
|
||||||
|
mutable_region ()->flatten ();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Region::snap (db::Coord gx, db::Coord gy)
|
Region::snap (db::Coord gx, db::Coord gy)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@
|
||||||
namespace db {
|
namespace db {
|
||||||
|
|
||||||
class EdgeFilterBase;
|
class EdgeFilterBase;
|
||||||
class FlatRegion;
|
class MutableRegion;
|
||||||
class EmptyRegion;
|
class EmptyRegion;
|
||||||
class DeepShapeStore;
|
class DeepShapeStore;
|
||||||
class TransformationReducer;
|
class TransformationReducer;
|
||||||
|
|
@ -1644,11 +1644,7 @@ public:
|
||||||
*
|
*
|
||||||
* This method will turn any region into a flat shape collection.
|
* This method will turn any region into a flat shape collection.
|
||||||
*/
|
*/
|
||||||
db::Region &flatten ()
|
db::Region &flatten ();
|
||||||
{
|
|
||||||
flat_region ();
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns true, if the region has valid polygons stored within itself
|
* @brief Returns true, if the region has valid polygons stored within itself
|
||||||
|
|
@ -1776,7 +1772,7 @@ private:
|
||||||
RegionDelegate *mp_delegate;
|
RegionDelegate *mp_delegate;
|
||||||
|
|
||||||
void set_delegate (RegionDelegate *delegate, bool keep_attributes = true);
|
void set_delegate (RegionDelegate *delegate, bool keep_attributes = true);
|
||||||
FlatRegion *flat_region ();
|
db::MutableRegion *mutable_region();
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -688,7 +688,8 @@ public:
|
||||||
text<C> &transform (const Tr &t)
|
text<C> &transform (const Tr &t)
|
||||||
{
|
{
|
||||||
typedef typename Tr::target_coord_type target_coord_type;
|
typedef typename Tr::target_coord_type target_coord_type;
|
||||||
m_trans = simple_trans<target_coord_type> ((t.fp_trans () * m_trans.fp_trans ()).rot (), t (point_type () + m_trans.disp ()) - point<target_coord_type> ());
|
fixpoint_trans<coord_type> fp (t);
|
||||||
|
m_trans = simple_trans<target_coord_type> ((fp * m_trans.fp_trans ()).rot (), t (point_type () + m_trans.disp ()) - point<target_coord_type> ());
|
||||||
m_size = t.ctrans (m_size);
|
m_size = t.ctrans (m_size);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
@ -708,13 +709,14 @@ public:
|
||||||
text<typename Tr::target_coord_type> transformed (const Tr &t) const
|
text<typename Tr::target_coord_type> transformed (const Tr &t) const
|
||||||
{
|
{
|
||||||
typedef typename Tr::target_coord_type target_coord_type;
|
typedef typename Tr::target_coord_type target_coord_type;
|
||||||
|
fixpoint_trans<coord_type> fp (t);
|
||||||
size_t p = (size_t) mp_ptr;
|
size_t p = (size_t) mp_ptr;
|
||||||
if (p & 1) {
|
if (p & 1) {
|
||||||
return text<target_coord_type> (reinterpret_cast<StringRef *> (p - 1), simple_trans<target_coord_type> ((t.fp_trans () * m_trans.fp_trans ()).rot (), t (point_type () + m_trans.disp ()) - point<target_coord_type> ()), t.ctrans (m_size), m_font, m_halign, m_valign);
|
return text<target_coord_type> (reinterpret_cast<StringRef *> (p - 1), simple_trans<target_coord_type> ((fp * m_trans.fp_trans ()).rot (), t (point_type () + m_trans.disp ()) - point<target_coord_type> ()), t.ctrans (m_size), m_font, m_halign, m_valign);
|
||||||
} else if (mp_ptr) {
|
} else if (mp_ptr) {
|
||||||
return text<target_coord_type> (mp_ptr, simple_trans<target_coord_type> ((t.fp_trans () * m_trans.fp_trans ()).rot (), t (point_type () + m_trans.disp ()) - point<target_coord_type> ()), t.ctrans (m_size), m_font, m_halign, m_valign);
|
return text<target_coord_type> (mp_ptr, simple_trans<target_coord_type> ((fp * m_trans.fp_trans ()).rot (), t (point_type () + m_trans.disp ()) - point<target_coord_type> ()), t.ctrans (m_size), m_font, m_halign, m_valign);
|
||||||
} else {
|
} else {
|
||||||
return text<target_coord_type> (simple_trans<target_coord_type> ((t.fp_trans () * m_trans.fp_trans ()).rot (), t (point_type () + m_trans.disp ()) - point<target_coord_type> ()), t.ctrans (m_size), m_font, m_halign, m_valign);
|
return text<target_coord_type> (simple_trans<target_coord_type> ((fp * m_trans.fp_trans ()).rot (), t (point_type () + m_trans.disp ()) - point<target_coord_type> ()), t.ctrans (m_size), m_font, m_halign, m_valign);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -93,25 +93,27 @@ Texts::Texts (const RecursiveShapeIterator &si, DeepShapeStore &dss, const db::I
|
||||||
template <class Sh>
|
template <class Sh>
|
||||||
void Texts::insert (const Sh &shape)
|
void Texts::insert (const Sh &shape)
|
||||||
{
|
{
|
||||||
flat_texts ()->insert (shape);
|
mutable_texts ()->insert (shape);
|
||||||
}
|
}
|
||||||
|
|
||||||
template DB_PUBLIC void Texts::insert (const db::Text &);
|
template DB_PUBLIC void Texts::insert (const db::Text &);
|
||||||
|
|
||||||
void Texts::insert (const db::Shape &shape)
|
void Texts::insert (const db::Shape &shape)
|
||||||
{
|
{
|
||||||
flat_texts ()->insert (shape);
|
mutable_texts ()->insert (shape);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
void Texts::insert (const db::Shape &shape, const T &trans)
|
void Texts::insert (const db::Shape &shape, const T &trans)
|
||||||
{
|
{
|
||||||
flat_texts ()->insert (shape, trans);
|
mutable_texts ()->insert (shape, trans);
|
||||||
}
|
}
|
||||||
|
|
||||||
template DB_PUBLIC void Texts::insert (const db::Shape &, const db::ICplxTrans &);
|
template DB_PUBLIC void Texts::insert (const db::Shape &, const db::ICplxTrans &);
|
||||||
template DB_PUBLIC void Texts::insert (const db::Shape &, const db::Trans &);
|
template DB_PUBLIC void Texts::insert (const db::Shape &, const db::Trans &);
|
||||||
template DB_PUBLIC void Texts::insert (const db::Shape &, const db::Disp &);
|
template DB_PUBLIC void Texts::insert (const db::Shape &, const db::Disp &);
|
||||||
|
template DB_PUBLIC void Texts::insert (const db::Shape &, const db::IMatrix2d &);
|
||||||
|
template DB_PUBLIC void Texts::insert (const db::Shape &, const db::IMatrix3d &);
|
||||||
|
|
||||||
void Texts::clear ()
|
void Texts::clear ()
|
||||||
{
|
{
|
||||||
|
|
@ -120,13 +122,18 @@ void Texts::clear ()
|
||||||
|
|
||||||
void Texts::reserve (size_t n)
|
void Texts::reserve (size_t n)
|
||||||
{
|
{
|
||||||
flat_texts ()->reserve (n);
|
mutable_texts ()->reserve (n);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Texts::flatten ()
|
||||||
|
{
|
||||||
|
mutable_texts ()->flatten ();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
Texts &Texts::transform (const T &trans)
|
Texts &Texts::transform (const T &trans)
|
||||||
{
|
{
|
||||||
flat_texts ()->transform (trans);
|
mutable_texts ()->transform (trans);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -161,9 +168,9 @@ void Texts::set_delegate (TextsDelegate *delegate)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FlatTexts *Texts::flat_texts ()
|
MutableTexts *Texts::mutable_texts ()
|
||||||
{
|
{
|
||||||
FlatTexts *texts = dynamic_cast<FlatTexts *> (mp_delegate);
|
MutableTexts *texts = dynamic_cast<MutableTexts *> (mp_delegate);
|
||||||
if (! texts) {
|
if (! texts) {
|
||||||
texts = new FlatTexts ();
|
texts = new FlatTexts ();
|
||||||
if (mp_delegate) {
|
if (mp_delegate) {
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ namespace db
|
||||||
{
|
{
|
||||||
|
|
||||||
class TextFilterBase;
|
class TextFilterBase;
|
||||||
class FlatTexts;
|
class MutableTexts;
|
||||||
class EmptyTexts;
|
class EmptyTexts;
|
||||||
class Edges;
|
class Edges;
|
||||||
class Region;
|
class Region;
|
||||||
|
|
@ -491,10 +491,7 @@ public:
|
||||||
*
|
*
|
||||||
* This method will turn any edge pair collection into a flat one.
|
* This method will turn any edge pair collection into a flat one.
|
||||||
*/
|
*/
|
||||||
void flatten ()
|
void flatten ();
|
||||||
{
|
|
||||||
flat_texts ();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns true, if the text set has valid texts stored within itself
|
* @brief Returns true, if the text set has valid texts stored within itself
|
||||||
|
|
@ -616,7 +613,7 @@ private:
|
||||||
TextsDelegate *mp_delegate;
|
TextsDelegate *mp_delegate;
|
||||||
|
|
||||||
void set_delegate (TextsDelegate *delegate);
|
void set_delegate (TextsDelegate *delegate);
|
||||||
FlatTexts *flat_texts ();
|
MutableTexts *mutable_texts();
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -376,6 +376,32 @@ public:
|
||||||
// .. nothing else ..
|
// .. nothing else ..
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reduction
|
||||||
|
*/
|
||||||
|
template <class T>
|
||||||
|
explicit fixpoint_trans (const T &t)
|
||||||
|
: m_f (0)
|
||||||
|
{
|
||||||
|
*this = t.fp_trans ();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reduction from a matrix2d
|
||||||
|
*/
|
||||||
|
explicit fixpoint_trans (const db::matrix_2d<coord_type> &t)
|
||||||
|
{
|
||||||
|
m_f = ((int (floor (t.angle () / 90.0 + 0.5) + 4)) % 4) + (t.is_mirror () ? 4 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reduction from a matrix3d
|
||||||
|
*/
|
||||||
|
explicit fixpoint_trans (const db::matrix_3d<coord_type> &t)
|
||||||
|
{
|
||||||
|
m_f = ((int (floor (t.angle () / 90.0 + 0.5) + 4)) % 4) + (t.is_mirror () ? 4 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns true, if the transformation is unity
|
* @brief Returns true, if the transformation is unity
|
||||||
*/
|
*/
|
||||||
|
|
@ -420,7 +446,18 @@ public:
|
||||||
// .. nothing else ..
|
// .. nothing else ..
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @brief The standard constructor using a code rather than angle and mirror and no displacement
|
||||||
|
*
|
||||||
|
* @param f The rotation/mirror code (r0 .. m135 constants)
|
||||||
|
*/
|
||||||
|
explicit fixpoint_trans (unsigned int f)
|
||||||
|
: m_f (f)
|
||||||
|
{
|
||||||
|
// .. nothing else ..
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
* @brief The rotation/mirror codes
|
* @brief The rotation/mirror codes
|
||||||
*/
|
*/
|
||||||
static const int r0 = 0; // No rotation
|
static const int r0 = 0; // No rotation
|
||||||
|
|
@ -1651,7 +1688,7 @@ public:
|
||||||
{
|
{
|
||||||
tl_assert (! m.has_shear ());
|
tl_assert (! m.has_shear ());
|
||||||
tl_assert (! m.has_perspective ());
|
tl_assert (! m.has_perspective ());
|
||||||
std::pair<double, double> mag = m.mag ();
|
std::pair<double, double> mag = m.mag2 ();
|
||||||
tl_assert (fabs (mag.first - mag.second) < 1e-10);
|
tl_assert (fabs (mag.first - mag.second) < 1e-10);
|
||||||
double rot = m.angle () * M_PI / 180.0;
|
double rot = m.angle () * M_PI / 180.0;
|
||||||
m_mag = m.is_mirror () ? -mag.first : mag.first;
|
m_mag = m.is_mirror () ? -mag.first : mag.first;
|
||||||
|
|
@ -1674,7 +1711,7 @@ public:
|
||||||
: m_u (u)
|
: m_u (u)
|
||||||
{
|
{
|
||||||
tl_assert (! m.has_shear ());
|
tl_assert (! m.has_shear ());
|
||||||
std::pair<double, double> mag = m.mag ();
|
std::pair<double, double> mag = m.mag2 ();
|
||||||
tl_assert (fabs (mag.first - mag.second) < 1e-10);
|
tl_assert (fabs (mag.first - mag.second) < 1e-10);
|
||||||
double rot = m.angle () * M_PI / 180.0;
|
double rot = m.angle () * M_PI / 180.0;
|
||||||
m_mag = m.is_mirror () ? -mag.first : mag.first;
|
m_mag = m.is_mirror () ? -mag.first : mag.first;
|
||||||
|
|
|
||||||
|
|
@ -140,6 +140,68 @@ static db::Region antenna_check (db::LayoutToNetlist *l2n, const db::Region &pol
|
||||||
return antenna_check3 (l2n, poly, 1, 0, metal, 1, 0, ratio, diodes);
|
return antenna_check3 (l2n, poly, 1, 0, metal, 1, 0, ratio, diodes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void join_net_names (db::LayoutToNetlist *l2n, const std::string &s)
|
||||||
|
{
|
||||||
|
l2n->join_net_names (tl::GlobPattern (s));
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string dump_joined_net_names (const db::LayoutToNetlist *l2n)
|
||||||
|
{
|
||||||
|
const std::list<tl::GlobPattern> &jn = l2n->joined_net_names ();
|
||||||
|
std::vector<std::string> s;
|
||||||
|
for (std::list<tl::GlobPattern>::const_iterator j = jn.begin (); j != jn.end (); ++j) {
|
||||||
|
s.push_back (j->pattern ());
|
||||||
|
}
|
||||||
|
return tl::join (s, ",");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void join_net_names2 (db::LayoutToNetlist *l2n, const std::string &c, const std::string &s)
|
||||||
|
{
|
||||||
|
l2n->join_net_names (tl::GlobPattern (c), tl::GlobPattern (s));
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string dump_joined_net_names_per_cell (const db::LayoutToNetlist *l2n)
|
||||||
|
{
|
||||||
|
const std::list<std::pair<tl::GlobPattern, tl::GlobPattern> > &jn = l2n->joined_net_names_per_cell ();
|
||||||
|
std::vector<std::string> s;
|
||||||
|
for (std::list<std::pair<tl::GlobPattern, tl::GlobPattern> >::const_iterator i = jn.begin (); i != jn.end (); ++i) {
|
||||||
|
s.push_back (i->first.pattern () + ":" + i->second.pattern ());
|
||||||
|
}
|
||||||
|
return tl::join (s, ",");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void join_nets (db::LayoutToNetlist *l2n, const std::set<std::string> &s)
|
||||||
|
{
|
||||||
|
l2n->join_nets (s);
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string dump_joined_nets (const db::LayoutToNetlist *l2n)
|
||||||
|
{
|
||||||
|
const std::list<std::set<std::string> > &jn = l2n->joined_nets ();
|
||||||
|
std::vector<std::string> s;
|
||||||
|
for (std::list<std::set<std::string> >::const_iterator j = jn.begin (); j != jn.end (); ++j) {
|
||||||
|
std::vector<std::string> t (j->begin (), j->end ());
|
||||||
|
s.push_back (tl::join (t, "+"));
|
||||||
|
}
|
||||||
|
return tl::join (s, ",");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void join_nets2 (db::LayoutToNetlist *l2n, const std::string &c, const std::set<std::string> &s)
|
||||||
|
{
|
||||||
|
l2n->join_nets (tl::GlobPattern (c), s);
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string dump_joined_nets_per_cell (const db::LayoutToNetlist *l2n)
|
||||||
|
{
|
||||||
|
const std::list<std::pair<tl::GlobPattern, std::set<std::string> > > &jn = l2n->joined_nets_per_cell ();
|
||||||
|
std::vector<std::string> s;
|
||||||
|
for (std::list<std::pair<tl::GlobPattern, std::set<std::string> > >::const_iterator i = jn.begin (); i != jn.end (); ++i) {
|
||||||
|
std::vector<std::string> t (i->second.begin (), i->second.end ());
|
||||||
|
s.push_back (i->first.pattern () + ":" + tl::join (t, "+"));
|
||||||
|
}
|
||||||
|
return tl::join (s, ",");
|
||||||
|
}
|
||||||
|
|
||||||
Class<db::LayoutToNetlist> decl_dbLayoutToNetlist ("db", "LayoutToNetlist",
|
Class<db::LayoutToNetlist> decl_dbLayoutToNetlist ("db", "LayoutToNetlist",
|
||||||
gsi::constructor ("new", &make_l2n, gsi::arg ("iter"),
|
gsi::constructor ("new", &make_l2n, gsi::arg ("iter"),
|
||||||
"@brief Creates a new extractor connected to an original layout\n"
|
"@brief Creates a new extractor connected to an original layout\n"
|
||||||
|
|
@ -334,7 +396,7 @@ Class<db::LayoutToNetlist> decl_dbLayoutToNetlist ("db", "LayoutToNetlist",
|
||||||
) +
|
) +
|
||||||
gsi::method ("connect", (void (db::LayoutToNetlist::*) (const db::Region &)) &db::LayoutToNetlist::connect, gsi::arg ("l"),
|
gsi::method ("connect", (void (db::LayoutToNetlist::*) (const db::Region &)) &db::LayoutToNetlist::connect, gsi::arg ("l"),
|
||||||
"@brief Defines an intra-layer connection for the given layer.\n"
|
"@brief Defines an intra-layer connection for the given layer.\n"
|
||||||
"The layer is either an original layer created with \\make_layer and it's variants or\n"
|
"The layer is either an original layer created with \\make_incluidelayer and it's variants or\n"
|
||||||
"a derived layer. Certain limitations apply. It's safe to use\n"
|
"a derived layer. Certain limitations apply. It's safe to use\n"
|
||||||
"boolean operations for deriving layers. Other operations are applicable as long as they are\n"
|
"boolean operations for deriving layers. Other operations are applicable as long as they are\n"
|
||||||
"capable of delivering hierarchical layers.\n"
|
"capable of delivering hierarchical layers.\n"
|
||||||
|
|
@ -372,13 +434,38 @@ Class<db::LayoutToNetlist> decl_dbLayoutToNetlist ("db", "LayoutToNetlist",
|
||||||
gsi::method ("global_net_name", &db::LayoutToNetlist::global_net_name, gsi::arg ("global_net_id"),
|
gsi::method ("global_net_name", &db::LayoutToNetlist::global_net_name, gsi::arg ("global_net_id"),
|
||||||
"@brief Gets the global net name for the given global net ID."
|
"@brief Gets the global net name for the given global net ID."
|
||||||
) +
|
) +
|
||||||
gsi::method ("extract_netlist", &db::LayoutToNetlist::extract_netlist, gsi::arg ("join_net_names", std::string (), "\"\""), gsi::arg ("include_floating_subcircuits", false),
|
gsi::method ("include_floating_subcircuits=", &db::LayoutToNetlist::set_include_floating_subcircuits, gsi::arg ("flag"),
|
||||||
"@brief Runs the netlist extraction\n"
|
"@brief Sets a flag indicating whether to include floating subcircuits in the netlist.\n"
|
||||||
"'join_net_names' is a glob expression for labels. Nets on top level carrying the same label which matches this glob "
|
|
||||||
"expression will be connected implicitly even if there is no physical connection. This feature is useful to simulate a connection "
|
|
||||||
"which will be made later when integrating the component.\n"
|
|
||||||
"\n"
|
"\n"
|
||||||
"Valid glob expressions are:\n"
|
"With 'include_floating_subcircuits' set to true, subcircuits with no connection to their parent "
|
||||||
|
"circuit are still included in the circuit as floating subcircuits. Specifically on flattening this "
|
||||||
|
"means that these subcircuits are properly propagated to their parent instead of appearing as "
|
||||||
|
"additional top circuits.\n"
|
||||||
|
"\n"
|
||||||
|
"This attribute has been introduced in version 0.27 and replaces the arguments of \\extract_netlist."
|
||||||
|
) +
|
||||||
|
gsi::method ("include_floating_subcircuits", &db::LayoutToNetlist::include_floating_subcircuits,
|
||||||
|
"@brief Gets a flag indicating whether to include floating subcircuits in the netlist.\n"
|
||||||
|
"See \\include_floating_subcircuits= for details.\n"
|
||||||
|
"\n"
|
||||||
|
"This attribute has been introduced in version 0.27.\n"
|
||||||
|
) +
|
||||||
|
gsi::method ("clear_join_net_names", &db::LayoutToNetlist::clear_join_net_names,
|
||||||
|
"@brief Clears all implicit net joining expressions.\n"
|
||||||
|
"See \\extract_netlist for more details about this feature.\n"
|
||||||
|
"\n"
|
||||||
|
"This method has been introduced in version 0.27 and replaces the arguments of \\extract_netlist."
|
||||||
|
) +
|
||||||
|
gsi::method_ext ("join_net_names", &join_net_names, gsi::arg ("pattern"),
|
||||||
|
"@brief Specifies another pattern for implicit joining of nets for the top level cell.\n"
|
||||||
|
"Use this method to register a pattern for net labels considered in implicit net joining. Implicit net joining "
|
||||||
|
"allows connecting multiple parts of the same nets (e.g. supply rails) without need for a physical connection. "
|
||||||
|
"The pattern specifies labels to look for. When parts are labelled with a name matching the expression, "
|
||||||
|
"the parts carrying the same name are joined.\n"
|
||||||
|
"\n"
|
||||||
|
"This method adds a new pattern. Use \\clear_join_net_names to clear the registered pattern.\n"
|
||||||
|
"\n"
|
||||||
|
"Each pattern is a glob expression. Valid glob expressions are:\n"
|
||||||
"@ul\n"
|
"@ul\n"
|
||||||
"@li \"\" no implicit connections.@/li\n"
|
"@li \"\" no implicit connections.@/li\n"
|
||||||
"@li \"*\" to make all labels candidates for implicit connections.@/li\n"
|
"@li \"*\" to make all labels candidates for implicit connections.@/li\n"
|
||||||
|
|
@ -389,27 +476,45 @@ Class<db::LayoutToNetlist> decl_dbLayoutToNetlist ("db", "LayoutToNetlist",
|
||||||
"\n"
|
"\n"
|
||||||
"Label matching is case sensitive.\n"
|
"Label matching is case sensitive.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"With 'include_floating_subcircuits' set to true, subcircuits with no connection to their parent "
|
"This method has been introduced in version 0.27 and replaces the arguments of \\extract_netlist."
|
||||||
"circuit are still included in the circuit as floating subcircuits. Specifically on flattening this "
|
) +
|
||||||
"means that these subcircuits are property propagated to their parent instead of appearing as "
|
gsi::method_ext ("join_net_names", &join_net_names2, gsi::arg ("cell_pattern"), gsi::arg ("pattern"),
|
||||||
"additional top circuits.\n"
|
"@brief Specifies another pattern for implicit joining of nets for the cells from the given cell pattern.\n"
|
||||||
|
"This method allows applying implicit net joining for specific cells, not only for the top cell.\n"
|
||||||
|
"\n"
|
||||||
|
"This method adds a new pattern. Use \\clear_join_net_names to clear the registered pattern.\n"
|
||||||
|
"\n"
|
||||||
|
"This method has been introduced in version 0.27 and replaces the arguments of \\extract_netlist."
|
||||||
|
) +
|
||||||
|
gsi::method ("clear_join_nets", &db::LayoutToNetlist::clear_join_nets,
|
||||||
|
"@brief Clears all explicit net joining expressions.\n"
|
||||||
|
"See \\extract_netlist for more details about this feature.\n"
|
||||||
|
"\n"
|
||||||
|
"Explicit net joining has been introduced in version 0.27."
|
||||||
|
) +
|
||||||
|
gsi::method_ext ("join_nets", &join_nets, gsi::arg ("net_names"),
|
||||||
|
"@brief Specifies another name list for explicit joining of nets for the top level cell.\n"
|
||||||
|
"Use this method to join nets from the set of net names. All these nets will be connected together forming a single net.\n"
|
||||||
|
"Explicit joining will imply implicit joining for the involved nets - partial nets involved will be connected too (intra-net joining).\n"
|
||||||
|
"\n"
|
||||||
|
"This method adds a new name list. Use \\clear_join_nets to clear the registered pattern.\n"
|
||||||
|
"\n"
|
||||||
|
"Explicit net joining has been introduced in version 0.27."
|
||||||
|
) +
|
||||||
|
gsi::method_ext ("join_nets", &join_nets2, gsi::arg ("cell_pattern"), gsi::arg ("net_names"),
|
||||||
|
"@brief Specifies another name list for explicit joining of nets for the cells from the given cell pattern.\n"
|
||||||
|
"This method allows applying explicit net joining for specific cells, not only for the top cell.\n"
|
||||||
|
"\n"
|
||||||
|
"This method adds a new name list. Use \\clear_join_nets to clear the registered pattern.\n"
|
||||||
|
"\n"
|
||||||
|
"Explicit net joining has been introduced in version 0.27."
|
||||||
|
) +
|
||||||
|
gsi::method ("extract_netlist", &db::LayoutToNetlist::extract_netlist,
|
||||||
|
"@brief Runs the netlist extraction\n"
|
||||||
"\n"
|
"\n"
|
||||||
"See the class description for more details.\n"
|
"See the class description for more details.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"The 'include_floating_subcircuits' argument has been introduced in version 0.26.2."
|
"This method has been made parameter-less in version 0.27. Use \\include_floating_subcircuits= and \\join_net_names as substitutes for the arguments of previous versions."
|
||||||
) +
|
|
||||||
gsi::method ("extract_netlist", &db::LayoutToNetlist::extract_netlist, gsi::arg ("join_net_names"), gsi::arg ("join_net_names_per_cell"), gsi::arg ("include_floating_subcircuits", false),
|
|
||||||
"@brief Runs the netlist extraction\n"
|
|
||||||
"This method runs the netlist extraction like the two-parameter version. In addition to the latter, this method "
|
|
||||||
"can be given a per-cell net label joining specification in 'join_net_names_per_cell'. The keys of this array "
|
|
||||||
"are cell names or cell names or cell name match expressions (glob style). The values are label match expressions.\n"
|
|
||||||
"\n"
|
|
||||||
"If not an empty string, the 'join_net_names' label match expression is applied to the top cell. For all non-top cells "
|
|
||||||
"the per-cell label match expression is applied and determines what labels are joined into single nets. "
|
|
||||||
"As the keys of 'join_net_names_per_cell' are glob expressions, a single cell may fall into more than one category. In this "
|
|
||||||
"case, the label match pattern are combined. In any case, the 'join_net_names' has priority for the top cell.\n"
|
|
||||||
"\n"
|
|
||||||
"This variant of 'extract_netlist' has been introduced in version 0.26.2."
|
|
||||||
) +
|
) +
|
||||||
gsi::method_ext ("internal_layout", &l2n_internal_layout,
|
gsi::method_ext ("internal_layout", &l2n_internal_layout,
|
||||||
"@brief Gets the internal layout\n"
|
"@brief Gets the internal layout\n"
|
||||||
|
|
@ -658,7 +763,13 @@ Class<db::LayoutToNetlist> decl_dbLayoutToNetlist ("db", "LayoutToNetlist",
|
||||||
"considered.\n"
|
"considered.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"This variant has been introduced in version 0.26.6.\n"
|
"This variant has been introduced in version 0.26.6.\n"
|
||||||
),
|
) +
|
||||||
|
// test API
|
||||||
|
gsi::method_ext ("dump_joined_net_names", &dump_joined_net_names, "@hide") +
|
||||||
|
gsi::method_ext ("dump_joined_net_names_per_cell", &dump_joined_net_names_per_cell, "@hide") +
|
||||||
|
gsi::method_ext ("dump_joined_nets", &dump_joined_nets, "@hide") +
|
||||||
|
gsi::method_ext ("dump_joined_nets_per_cell", &dump_joined_nets_per_cell, "@hide")
|
||||||
|
,
|
||||||
"@brief A generic framework for extracting netlists from layouts\n"
|
"@brief A generic framework for extracting netlists from layouts\n"
|
||||||
"\n"
|
"\n"
|
||||||
"This class wraps various concepts from db::NetlistExtractor and db::NetlistDeviceExtractor\n"
|
"This class wraps various concepts from db::NetlistExtractor and db::NetlistDeviceExtractor\n"
|
||||||
|
|
@ -674,7 +785,7 @@ Class<db::LayoutToNetlist> decl_dbLayoutToNetlist ("db", "LayoutToNetlist",
|
||||||
" hierarchy and the layout taken as input.\n"
|
" hierarchy and the layout taken as input.\n"
|
||||||
"@/li\n"
|
"@/li\n"
|
||||||
"@li Preparation\n"
|
"@li Preparation\n"
|
||||||
" In this step, the device recognitions and extraction layers are drawn from\n"
|
" In this step, the device recognition and extraction layers are drawn from\n"
|
||||||
" the framework. Derived can now be computed using boolean operations.\n"
|
" the framework. Derived can now be computed using boolean operations.\n"
|
||||||
" Methods to use in this step are \\make_layer and it's variants.\n"
|
" Methods to use in this step are \\make_layer and it's variants.\n"
|
||||||
" Layer preparation is not necessarily required to happen before all\n"
|
" Layer preparation is not necessarily required to happen before all\n"
|
||||||
|
|
|
||||||
|
|
@ -519,6 +519,9 @@ Class<db::NetlistComparer> decl_dbNetlistComparer ("db", "NetlistComparer",
|
||||||
"@brief Sets the maximum seach depth\n"
|
"@brief Sets the maximum seach depth\n"
|
||||||
"This value limits the search depth of the backtracking algorithm to the\n"
|
"This value limits the search depth of the backtracking algorithm to the\n"
|
||||||
"given number of jumps.\n"
|
"given number of jumps.\n"
|
||||||
|
"\n"
|
||||||
|
"By default, from version 0.27 on the depth is unlimited and can be reduced in cases where runtimes need to be limited at the cost "
|
||||||
|
"less elaborate matching evaluation.\n"
|
||||||
) +
|
) +
|
||||||
gsi::method ("max_depth", &db::NetlistComparer::max_depth,
|
gsi::method ("max_depth", &db::NetlistComparer::max_depth,
|
||||||
"@brief Gets the maximum seach depth\n"
|
"@brief Gets the maximum seach depth\n"
|
||||||
|
|
@ -531,6 +534,9 @@ Class<db::NetlistComparer> decl_dbNetlistComparer ("db", "NetlistComparer",
|
||||||
"net matches. Backtracking will stop when the maximum number of options\n"
|
"net matches. Backtracking will stop when the maximum number of options\n"
|
||||||
"has been exceeded.\n"
|
"has been exceeded.\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
"By default, from version 0.27 on the complexity is unlimited and can be reduced in cases where runtimes need to be limited at the cost "
|
||||||
|
"less elaborate matching evaluation.\n"
|
||||||
|
"\n"
|
||||||
"As the computational complexity is the square of the branch count,\n"
|
"As the computational complexity is the square of the branch count,\n"
|
||||||
"this value should be adjusted carefully.\n"
|
"this value should be adjusted carefully.\n"
|
||||||
) +
|
) +
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ TEST(1)
|
||||||
EXPECT_EQ (r.bbox ().to_string (), "(0,0;100,200)");
|
EXPECT_EQ (r.bbox ().to_string (), "(0,0;100,200)");
|
||||||
EXPECT_EQ (r.transformed (db::Trans (db::Vector (1, 2))).bbox ().to_string (), "(1,2;101,202)");
|
EXPECT_EQ (r.transformed (db::Trans (db::Vector (1, 2))).bbox ().to_string (), "(1,2;101,202)");
|
||||||
EXPECT_EQ (r.empty (), false);
|
EXPECT_EQ (r.empty (), false);
|
||||||
EXPECT_EQ (r.is_merged (), true);
|
EXPECT_EQ (r.is_merged (), false);
|
||||||
EXPECT_EQ (r.begin ().at_end (), false);
|
EXPECT_EQ (r.begin ().at_end (), false);
|
||||||
|
|
||||||
db::Edges r1 = r;
|
db::Edges r1 = r;
|
||||||
|
|
|
||||||
|
|
@ -3156,7 +3156,7 @@ TEST(12_FlattenCircuitDoesFlattenLayout)
|
||||||
db::compare_layouts (_this, ly, au);
|
db::compare_layouts (_this, ly, au);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(13_JoinNets)
|
TEST(13_JoinNetNames)
|
||||||
{
|
{
|
||||||
db::Layout ly;
|
db::Layout ly;
|
||||||
db::LayerMap lmap;
|
db::LayerMap lmap;
|
||||||
|
|
@ -3299,7 +3299,8 @@ TEST(13_JoinNets)
|
||||||
l2n.connect_global (*rbulk, "VSS");
|
l2n.connect_global (*rbulk, "VSS");
|
||||||
|
|
||||||
// Extract with joining VSS and VDD
|
// Extract with joining VSS and VDD
|
||||||
l2n.extract_netlist ("{VSS,VDD}");
|
l2n.join_net_names (tl::GlobPattern ("{VSS,VDD}"));
|
||||||
|
l2n.extract_netlist ();
|
||||||
|
|
||||||
// debug layers produced for nets
|
// debug layers produced for nets
|
||||||
// 201/0 -> Well
|
// 201/0 -> Well
|
||||||
|
|
@ -3385,3 +3386,249 @@ TEST(13_JoinNets)
|
||||||
db::compare_layouts (_this, ly, au);
|
db::compare_layouts (_this, ly, au);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST(14_JoinNets)
|
||||||
|
{
|
||||||
|
db::Layout ly;
|
||||||
|
db::LayerMap lmap;
|
||||||
|
|
||||||
|
unsigned int nwell = define_layer (ly, lmap, 1);
|
||||||
|
unsigned int nwell_lbl = define_layer (ly, lmap, 1, 1);
|
||||||
|
unsigned int active = define_layer (ly, lmap, 2);
|
||||||
|
unsigned int pplus = define_layer (ly, lmap, 10);
|
||||||
|
unsigned int nplus = define_layer (ly, lmap, 11);
|
||||||
|
unsigned int poly = define_layer (ly, lmap, 3);
|
||||||
|
unsigned int poly_lbl = define_layer (ly, lmap, 3, 1);
|
||||||
|
unsigned int diff_cont = define_layer (ly, lmap, 4);
|
||||||
|
unsigned int poly_cont = define_layer (ly, lmap, 5);
|
||||||
|
unsigned int metal1 = define_layer (ly, lmap, 6);
|
||||||
|
unsigned int metal1_lbl = define_layer (ly, lmap, 6, 1);
|
||||||
|
unsigned int via1 = define_layer (ly, lmap, 7);
|
||||||
|
unsigned int metal2 = define_layer (ly, lmap, 8);
|
||||||
|
unsigned int metal2_lbl = define_layer (ly, lmap, 8, 1);
|
||||||
|
|
||||||
|
{
|
||||||
|
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_l14.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 (db::RecursiveShapeIterator (ly, tc, std::set<unsigned int> ()));
|
||||||
|
|
||||||
|
std::unique_ptr<db::Region> rbulk (l2n.make_layer ("bulk"));
|
||||||
|
std::unique_ptr<db::Region> rnwell (l2n.make_layer (nwell, "nwell"));
|
||||||
|
std::unique_ptr<db::Region> rnwell_lbl (l2n.make_layer (nwell_lbl, "nwell_lbl"));
|
||||||
|
std::unique_ptr<db::Region> ractive (l2n.make_layer (active, "active"));
|
||||||
|
std::unique_ptr<db::Region> rpplus (l2n.make_layer (pplus, "pplus"));
|
||||||
|
std::unique_ptr<db::Region> rnplus (l2n.make_layer (nplus, "nplus"));
|
||||||
|
std::unique_ptr<db::Region> rpoly (l2n.make_polygon_layer (poly, "poly"));
|
||||||
|
std::unique_ptr<db::Texts> rpoly_lbl (l2n.make_text_layer (poly_lbl, "poly_lbl"));
|
||||||
|
std::unique_ptr<db::Region> rdiff_cont (l2n.make_polygon_layer (diff_cont, "diff_cont"));
|
||||||
|
std::unique_ptr<db::Region> rpoly_cont (l2n.make_polygon_layer (poly_cont, "poly_cont"));
|
||||||
|
std::unique_ptr<db::Region> rmetal1 (l2n.make_polygon_layer (metal1, "metal1"));
|
||||||
|
std::unique_ptr<db::Texts> rmetal1_lbl (l2n.make_text_layer (metal1_lbl, "metal1_lbl"));
|
||||||
|
std::unique_ptr<db::Region> rvia1 (l2n.make_polygon_layer (via1, "via1"));
|
||||||
|
std::unique_ptr<db::Region> rmetal2 (l2n.make_polygon_layer (metal2, "metal2"));
|
||||||
|
std::unique_ptr<db::Texts> rmetal2_lbl (l2n.make_text_layer (metal2_lbl, "metal2_lbl"));
|
||||||
|
|
||||||
|
// derived regions
|
||||||
|
|
||||||
|
db::Region ractive_in_nwell = *ractive & *rnwell;
|
||||||
|
db::Region rpactive = ractive_in_nwell & *rpplus;
|
||||||
|
db::Region rntie = ractive_in_nwell & *rnplus;
|
||||||
|
db::Region rpgate = rpactive & *rpoly;
|
||||||
|
db::Region rpsd = rpactive - rpgate;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
// return the computed layers into the original layout and write it for debugging purposes
|
||||||
|
|
||||||
|
unsigned int lgate = ly.insert_layer (db::LayerProperties (20, 0)); // 20/0 -> Gate
|
||||||
|
unsigned int lsd = ly.insert_layer (db::LayerProperties (21, 0)); // 21/0 -> Source/Drain
|
||||||
|
unsigned int lpdiff = ly.insert_layer (db::LayerProperties (22, 0)); // 22/0 -> P Diffusion
|
||||||
|
unsigned int lndiff = ly.insert_layer (db::LayerProperties (23, 0)); // 23/0 -> N Diffusion
|
||||||
|
unsigned int lptie = ly.insert_layer (db::LayerProperties (24, 0)); // 24/0 -> P Tie
|
||||||
|
unsigned int lntie = ly.insert_layer (db::LayerProperties (25, 0)); // 25/0 -> N Tie
|
||||||
|
|
||||||
|
rpgate.insert_into (&ly, tc.cell_index (), lgate);
|
||||||
|
rngate.insert_into (&ly, tc.cell_index (), lgate);
|
||||||
|
rpsd.insert_into (&ly, tc.cell_index (), lsd);
|
||||||
|
rnsd.insert_into (&ly, tc.cell_index (), lsd);
|
||||||
|
rpsd.insert_into (&ly, tc.cell_index (), lpdiff);
|
||||||
|
rnsd.insert_into (&ly, tc.cell_index (), lndiff);
|
||||||
|
rpsd.insert_into (&ly, tc.cell_index (), lptie);
|
||||||
|
rnsd.insert_into (&ly, tc.cell_index (), lntie);
|
||||||
|
|
||||||
|
db::NetlistDeviceExtractorMOS4Transistor pmos_ex ("PMOS");
|
||||||
|
db::NetlistDeviceExtractorMOS4Transistor nmos_ex ("NMOS");
|
||||||
|
|
||||||
|
// device extraction
|
||||||
|
|
||||||
|
db::NetlistDeviceExtractor::input_layers dl;
|
||||||
|
|
||||||
|
dl["SD"] = &rpsd;
|
||||||
|
dl["G"] = &rpgate;
|
||||||
|
dl["P"] = rpoly.get (); // not needed for extraction but to return terminal shapes
|
||||||
|
dl["W"] = rnwell.get ();
|
||||||
|
l2n.extract_devices (pmos_ex, dl);
|
||||||
|
|
||||||
|
dl["SD"] = &rnsd;
|
||||||
|
dl["G"] = &rngate;
|
||||||
|
dl["P"] = rpoly.get (); // not needed for extraction but to return terminal shapes
|
||||||
|
dl["W"] = rbulk.get ();
|
||||||
|
l2n.extract_devices (nmos_ex, dl);
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
l2n.connect (*rnwell);
|
||||||
|
l2n.connect (*rpoly);
|
||||||
|
l2n.connect (*rdiff_cont);
|
||||||
|
l2n.connect (*rpoly_cont);
|
||||||
|
l2n.connect (*rmetal1);
|
||||||
|
l2n.connect (*rvia1);
|
||||||
|
l2n.connect (*rmetal2);
|
||||||
|
l2n.connect (rptie);
|
||||||
|
l2n.connect (rntie);
|
||||||
|
// Inter-layer
|
||||||
|
l2n.connect (rpsd, *rdiff_cont);
|
||||||
|
l2n.connect (rnsd, *rdiff_cont);
|
||||||
|
l2n.connect (rntie, *rnwell);
|
||||||
|
l2n.connect (*rpoly, *rpoly_cont);
|
||||||
|
l2n.connect (*rpoly_cont, *rmetal1);
|
||||||
|
l2n.connect (*rdiff_cont, *rmetal1);
|
||||||
|
l2n.connect (*rdiff_cont, rptie);
|
||||||
|
l2n.connect (*rdiff_cont, rntie);
|
||||||
|
l2n.connect (*rnwell, rntie);
|
||||||
|
l2n.connect (*rmetal1, *rvia1);
|
||||||
|
l2n.connect (*rvia1, *rmetal2);
|
||||||
|
l2n.connect (*rnwell, *rnwell_lbl); // attaches labels
|
||||||
|
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 (*rbulk, "BULK");
|
||||||
|
l2n.connect_global (rptie, "BULK");
|
||||||
|
|
||||||
|
// Extract while joining VSS with BULK and VDD with NWELL
|
||||||
|
std::set<std::string> jn;
|
||||||
|
jn.insert ("VDD");
|
||||||
|
jn.insert ("NWELL");
|
||||||
|
l2n.join_nets (tl::GlobPattern ("INV2"), jn);
|
||||||
|
jn.clear ();
|
||||||
|
jn.insert ("VSS");
|
||||||
|
jn.insert ("BULK");
|
||||||
|
l2n.join_nets (tl::GlobPattern ("INV2"), jn);
|
||||||
|
|
||||||
|
// This will trigger an implicit connection on top level (side effect of explicit connections)
|
||||||
|
jn.clear ();
|
||||||
|
jn.insert ("VDD");
|
||||||
|
l2n.join_nets (jn);
|
||||||
|
|
||||||
|
l2n.extract_netlist ();
|
||||||
|
|
||||||
|
// debug layers produced for nets
|
||||||
|
// 201/0 -> Well
|
||||||
|
// 203/0 -> Poly
|
||||||
|
// 204/0 -> Diffusion contacts
|
||||||
|
// 205/0 -> Poly contacts
|
||||||
|
// 206/0 -> Metal1
|
||||||
|
// 207/0 -> Via1
|
||||||
|
// 208/0 -> Metal2
|
||||||
|
// 210/0 -> N source/drain
|
||||||
|
// 211/0 -> P source/drain
|
||||||
|
// 212/0 -> N tie
|
||||||
|
// 213/0 -> P tie
|
||||||
|
std::map<const db::Region *, unsigned int> dump_map;
|
||||||
|
dump_map [&rpsd ] = ly.insert_layer (db::LayerProperties (210, 0));
|
||||||
|
dump_map [&rnsd ] = ly.insert_layer (db::LayerProperties (211, 0));
|
||||||
|
dump_map [&rptie ] = ly.insert_layer (db::LayerProperties (212, 0));
|
||||||
|
dump_map [&rntie ] = ly.insert_layer (db::LayerProperties (213, 0));
|
||||||
|
dump_map [rbulk.get () ] = ly.insert_layer (db::LayerProperties (214, 0));
|
||||||
|
dump_map [rnwell.get () ] = ly.insert_layer (db::LayerProperties (201, 0));
|
||||||
|
dump_map [rpoly.get () ] = ly.insert_layer (db::LayerProperties (203, 0));
|
||||||
|
dump_map [rdiff_cont.get ()] = ly.insert_layer (db::LayerProperties (204, 0));
|
||||||
|
dump_map [rpoly_cont.get ()] = ly.insert_layer (db::LayerProperties (205, 0));
|
||||||
|
dump_map [rmetal1.get () ] = ly.insert_layer (db::LayerProperties (206, 0));
|
||||||
|
dump_map [rvia1.get () ] = ly.insert_layer (db::LayerProperties (207, 0));
|
||||||
|
dump_map [rmetal2.get () ] = ly.insert_layer (db::LayerProperties (208, 0));
|
||||||
|
|
||||||
|
// write nets to layout
|
||||||
|
db::CellMapping cm = l2n.cell_mapping_into (ly, tc);
|
||||||
|
dump_nets_to_layout (l2n, ly, dump_map, cm);
|
||||||
|
|
||||||
|
dump_map.clear ();
|
||||||
|
dump_map [&rpsd ] = ly.insert_layer (db::LayerProperties (310, 0));
|
||||||
|
dump_map [&rnsd ] = ly.insert_layer (db::LayerProperties (311, 0));
|
||||||
|
dump_map [&rptie ] = ly.insert_layer (db::LayerProperties (312, 0));
|
||||||
|
dump_map [&rntie ] = ly.insert_layer (db::LayerProperties (313, 0));
|
||||||
|
dump_map [rbulk.get () ] = ly.insert_layer (db::LayerProperties (314, 0));
|
||||||
|
dump_map [rnwell.get () ] = ly.insert_layer (db::LayerProperties (301, 0));
|
||||||
|
dump_map [rpoly.get () ] = ly.insert_layer (db::LayerProperties (303, 0));
|
||||||
|
dump_map [rdiff_cont.get ()] = ly.insert_layer (db::LayerProperties (304, 0));
|
||||||
|
dump_map [rpoly_cont.get ()] = ly.insert_layer (db::LayerProperties (305, 0));
|
||||||
|
dump_map [rmetal1.get () ] = ly.insert_layer (db::LayerProperties (306, 0));
|
||||||
|
dump_map [rvia1.get () ] = ly.insert_layer (db::LayerProperties (307, 0));
|
||||||
|
dump_map [rmetal2.get () ] = ly.insert_layer (db::LayerProperties (308, 0));
|
||||||
|
|
||||||
|
dump_recursive_nets_to_layout (l2n, ly, dump_map, cm);
|
||||||
|
|
||||||
|
// compare netlist as string
|
||||||
|
CHECKPOINT ();
|
||||||
|
db::compare_netlist (_this, *l2n.netlist (),
|
||||||
|
"circuit RINGO ();\n"
|
||||||
|
" subcircuit INV2 $1 ('NWELL,VDD'=VDD,IN=$I15,$3=FB,OUT=OSC,VSS=VSS);\n"
|
||||||
|
" subcircuit INV2 $2 ('NWELL,VDD'=VDD,IN=FB,$3=$I26,OUT=$I25,VSS=VSS);\n"
|
||||||
|
" subcircuit INV2 $3 ('NWELL,VDD'=VDD,IN=$3,$3=$I30,OUT=$I12,VSS=VSS);\n"
|
||||||
|
" subcircuit INV2 $4 ('NWELL,VDD'=VDD,IN=$I10,$3=$I29,OUT=$3,VSS=VSS);\n"
|
||||||
|
" subcircuit INV2 $5 ('NWELL,VDD'=VDD,IN=$I12,$3=$I31,OUT=$I13,VSS=VSS);\n"
|
||||||
|
" subcircuit INV2 $6 ('NWELL,VDD'=VDD,IN=$I13,$3=$I32,OUT=$I14,VSS=VSS);\n"
|
||||||
|
" subcircuit INV2 $7 ('NWELL,VDD'=VDD,IN=$I14,$3=$I33,OUT=$I15,VSS=VSS);\n"
|
||||||
|
" subcircuit INV2 $8 ('NWELL,VDD'=VDD,IN=$I25,$3=$I27,OUT=$I9,VSS=VSS);\n"
|
||||||
|
" subcircuit INV2 $9 ('NWELL,VDD'=VDD,IN=$I9,$3=$I28,OUT=$I10,VSS=VSS);\n"
|
||||||
|
"end;\n"
|
||||||
|
"circuit INV2 ('NWELL,VDD'='NWELL,VDD',IN=IN,$3=$3,OUT=OUT,VSS=VSS);\n"
|
||||||
|
" device PMOS $1 (S=$3,G=IN,D='NWELL,VDD',B='NWELL,VDD') (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||||
|
" device PMOS $2 (S='NWELL,VDD',G=$3,D=OUT,B='NWELL,VDD') (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n"
|
||||||
|
" device NMOS $3 (S=$3,G=IN,D=VSS,B=VSS) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||||
|
" device NMOS $4 (S=VSS,G=$3,D=OUT,B=VSS) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n"
|
||||||
|
" subcircuit TRANS $1 ($1=$3,$2='NWELL,VDD',$3=IN);\n"
|
||||||
|
" subcircuit TRANS $2 ($1='NWELL,VDD',$2=OUT,$3=$3);\n"
|
||||||
|
" subcircuit TRANS $3 ($1=$3,$2=VSS,$3=IN);\n"
|
||||||
|
" subcircuit TRANS $4 ($1=VSS,$2=OUT,$3=$3);\n"
|
||||||
|
"end;\n"
|
||||||
|
"circuit TRANS ($1=$1,$2=$2,$3=$3);\n"
|
||||||
|
"end;\n"
|
||||||
|
);
|
||||||
|
|
||||||
|
// compare the collected test data
|
||||||
|
|
||||||
|
std::string au = tl::testsrc ();
|
||||||
|
au = tl::combine_path (au, "testdata");
|
||||||
|
au = tl::combine_path (au, "algo");
|
||||||
|
au = tl::combine_path (au, "device_extract_au14_circuits.gds");
|
||||||
|
|
||||||
|
db::compare_layouts (_this, ly, au);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -114,10 +114,10 @@ TEST(1)
|
||||||
EXPECT_EQ (tl::to_string (db::Matrix2d::shear (17).has_shear ()), "true");
|
EXPECT_EQ (tl::to_string (db::Matrix2d::shear (17).has_shear ()), "true");
|
||||||
EXPECT_EQ (tl::to_string (db::Matrix2d::shear (40).shear_angle ()), "40");
|
EXPECT_EQ (tl::to_string (db::Matrix2d::shear (40).shear_angle ()), "40");
|
||||||
EXPECT_EQ (tl::to_string (db::Matrix2d::shear (-40).shear_angle ()), "-40");
|
EXPECT_EQ (tl::to_string (db::Matrix2d::shear (-40).shear_angle ()), "-40");
|
||||||
EXPECT_EQ (tl::to_string (1.0 / db::Matrix2d::mag (17.5).inverted ().mag ().first), "17.5");
|
EXPECT_EQ (tl::to_string (1.0 / db::Matrix2d::mag (17.5).inverted ().mag2 ().first), "17.5");
|
||||||
EXPECT_EQ (tl::to_string (1.0 / db::Matrix2d::mag (17.5).inverted ().mag ().second), "17.5");
|
EXPECT_EQ (tl::to_string (1.0 / db::Matrix2d::mag (17.5).inverted ().mag2 ().second), "17.5");
|
||||||
EXPECT_EQ (tl::to_string (1.0 / db::Matrix2d::mag (27.5, 7.5).inverted ().mag ().first), "27.5");
|
EXPECT_EQ (tl::to_string (1.0 / db::Matrix2d::mag (27.5, 7.5).inverted ().mag2 ().first), "27.5");
|
||||||
EXPECT_EQ (tl::to_string (1.0 / db::Matrix2d::mag (27.5, 7.5).inverted ().mag ().second), "7.5");
|
EXPECT_EQ (tl::to_string (1.0 / db::Matrix2d::mag (27.5, 7.5).inverted ().mag2 ().second), "7.5");
|
||||||
EXPECT_EQ (tl::to_string (db::Matrix2d::mirror (true).inverted ().is_mirror ()), "true");
|
EXPECT_EQ (tl::to_string (db::Matrix2d::mirror (true).inverted ().is_mirror ()), "true");
|
||||||
EXPECT_EQ (tl::to_string (db::Matrix2d::mirror (false).inverted ().is_mirror ()), "false");
|
EXPECT_EQ (tl::to_string (db::Matrix2d::mirror (false).inverted ().is_mirror ()), "false");
|
||||||
EXPECT_EQ (tl::to_string (db::Matrix2d::rotation (25).inverted ().angle ()), "-25");
|
EXPECT_EQ (tl::to_string (db::Matrix2d::rotation (25).inverted ().angle ()), "-25");
|
||||||
|
|
|
||||||
|
|
@ -958,19 +958,38 @@ TEST(3_DeviceAndNetExtractionWithImplicitConnections)
|
||||||
|
|
||||||
// extract the nets
|
// extract the nets
|
||||||
|
|
||||||
|
std::list<tl::GlobPattern> gp;
|
||||||
|
|
||||||
db::Netlist nl2 = nl;
|
db::Netlist nl2 = nl;
|
||||||
net_ex.set_joined_net_names ("{VDDZ,VSSZ,NEXT,FB}");
|
gp.clear ();
|
||||||
|
gp.push_back (tl::GlobPattern ("{VDDZ,VSSZ,NEXT,FB}"));
|
||||||
|
net_ex.set_joined_net_names (gp);
|
||||||
net_ex.extract_nets (dss, 0, conn, nl2, cl);
|
net_ex.extract_nets (dss, 0, conn, nl2, cl);
|
||||||
|
|
||||||
EXPECT_EQ (all_net_names_unique (nl2), true);
|
EXPECT_EQ (all_net_names_unique (nl2), true);
|
||||||
|
|
||||||
nl2 = nl;
|
nl2 = nl;
|
||||||
net_ex.set_joined_net_names ("{VDDZ,VSSZ,NEXT}");
|
gp.clear ();
|
||||||
|
gp.push_back (tl::GlobPattern ("VDDZ"));
|
||||||
|
gp.push_back (tl::GlobPattern ("VSSZ"));
|
||||||
|
gp.push_back (tl::GlobPattern ("NEXT"));
|
||||||
|
gp.push_back (tl::GlobPattern ("FB"));
|
||||||
|
net_ex.set_joined_net_names (gp);
|
||||||
|
net_ex.extract_nets (dss, 0, conn, nl2, cl);
|
||||||
|
|
||||||
|
EXPECT_EQ (all_net_names_unique (nl2), true);
|
||||||
|
|
||||||
|
nl2 = nl;
|
||||||
|
gp.clear ();
|
||||||
|
gp.push_back (tl::GlobPattern ("{VDDZ,VSSZ,NEXT}"));
|
||||||
|
net_ex.set_joined_net_names (gp);
|
||||||
net_ex.extract_nets (dss, 0, conn, nl2, cl);
|
net_ex.extract_nets (dss, 0, conn, nl2, cl);
|
||||||
|
|
||||||
EXPECT_EQ (all_net_names_unique (nl2), false);
|
EXPECT_EQ (all_net_names_unique (nl2), false);
|
||||||
|
|
||||||
net_ex.set_joined_net_names ("*");
|
gp.clear ();
|
||||||
|
gp.push_back (tl::GlobPattern ("*"));
|
||||||
|
net_ex.set_joined_net_names (gp);
|
||||||
net_ex.extract_nets (dss, 0, conn, nl, cl);
|
net_ex.extract_nets (dss, 0, conn, nl, cl);
|
||||||
|
|
||||||
EXPECT_EQ (all_net_names_unique (nl), true);
|
EXPECT_EQ (all_net_names_unique (nl), true);
|
||||||
|
|
@ -1233,7 +1252,9 @@ TEST(4_ResAndCapExtraction)
|
||||||
|
|
||||||
// extract the nets
|
// extract the nets
|
||||||
|
|
||||||
net_ex.set_joined_net_names ("*");
|
std::list<tl::GlobPattern> gp;
|
||||||
|
gp.push_back (tl::GlobPattern ("*"));
|
||||||
|
net_ex.set_joined_net_names (gp);
|
||||||
net_ex.extract_nets (dss, 0, conn, nl, cl);
|
net_ex.extract_nets (dss, 0, conn, nl, cl);
|
||||||
|
|
||||||
// Flatten device circuits
|
// Flatten device circuits
|
||||||
|
|
@ -1507,7 +1528,9 @@ TEST(5_ResAndCapWithBulkExtraction)
|
||||||
|
|
||||||
// extract the nets
|
// extract the nets
|
||||||
|
|
||||||
net_ex.set_joined_net_names ("*");
|
std::list<tl::GlobPattern> gp;
|
||||||
|
gp.push_back (tl::GlobPattern ("*"));
|
||||||
|
net_ex.set_joined_net_names (gp);
|
||||||
net_ex.extract_nets (dss, 0, conn, nl, cl);
|
net_ex.extract_nets (dss, 0, conn, nl, cl);
|
||||||
|
|
||||||
// Flatten device circuits
|
// Flatten device circuits
|
||||||
|
|
@ -1749,7 +1772,9 @@ TEST(6_BJT3TransistorExtraction)
|
||||||
|
|
||||||
// extract the nets
|
// extract the nets
|
||||||
|
|
||||||
net_ex.set_joined_net_names ("*");
|
std::list<tl::GlobPattern> gp;
|
||||||
|
gp.push_back (tl::GlobPattern ("*"));
|
||||||
|
net_ex.set_joined_net_names (gp);
|
||||||
net_ex.extract_nets (dss, 0, conn, nl, cl);
|
net_ex.extract_nets (dss, 0, conn, nl, cl);
|
||||||
|
|
||||||
// Flatten device circuits
|
// Flatten device circuits
|
||||||
|
|
@ -1915,7 +1940,9 @@ TEST(7_DiodeExtraction)
|
||||||
|
|
||||||
// extract the nets
|
// extract the nets
|
||||||
|
|
||||||
net_ex.set_joined_net_names ("*");
|
std::list<tl::GlobPattern> gp;
|
||||||
|
gp.push_back (tl::GlobPattern ("*"));
|
||||||
|
net_ex.set_joined_net_names (gp);
|
||||||
net_ex.extract_nets (dss, 0, conn, nl, cl);
|
net_ex.extract_nets (dss, 0, conn, nl, cl);
|
||||||
|
|
||||||
// cleanup + completion
|
// cleanup + completion
|
||||||
|
|
@ -2048,7 +2075,9 @@ TEST(8_DiodeExtractionScaled)
|
||||||
|
|
||||||
// extract the nets
|
// extract the nets
|
||||||
|
|
||||||
net_ex.set_joined_net_names ("*");
|
std::list<tl::GlobPattern> gp;
|
||||||
|
gp.push_back (tl::GlobPattern ("*"));
|
||||||
|
net_ex.set_joined_net_names (gp);
|
||||||
net_ex.extract_nets (dss, 0, conn, nl, cl);
|
net_ex.extract_nets (dss, 0, conn, nl, cl);
|
||||||
|
|
||||||
// cleanup + completion
|
// cleanup + completion
|
||||||
|
|
@ -2922,3 +2951,255 @@ TEST(13_RemoveDummyPins)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(14_JoinNets)
|
||||||
|
{
|
||||||
|
db::Layout ly;
|
||||||
|
db::LayerMap lmap;
|
||||||
|
|
||||||
|
unsigned int nwell = define_layer (ly, lmap, 1);
|
||||||
|
unsigned int active = define_layer (ly, lmap, 2);
|
||||||
|
unsigned int poly = define_layer (ly, lmap, 3);
|
||||||
|
unsigned int poly_lbl = define_layer (ly, lmap, 3, 1);
|
||||||
|
unsigned int diff_cont = define_layer (ly, lmap, 4);
|
||||||
|
unsigned int poly_cont = define_layer (ly, lmap, 5);
|
||||||
|
unsigned int metal1 = define_layer (ly, lmap, 6);
|
||||||
|
unsigned int metal1_lbl = define_layer (ly, lmap, 6, 1);
|
||||||
|
unsigned int via1 = define_layer (ly, lmap, 7);
|
||||||
|
unsigned int metal2 = define_layer (ly, lmap, 8);
|
||||||
|
unsigned int metal2_lbl = define_layer (ly, lmap, 8, 1);
|
||||||
|
|
||||||
|
{
|
||||||
|
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_l1_join_nets.gds");
|
||||||
|
|
||||||
|
tl::InputStream stream (fn);
|
||||||
|
db::Reader reader (stream);
|
||||||
|
reader.read (ly, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
db::Cell &tc = ly.cell (*ly.begin_top_down ());
|
||||||
|
|
||||||
|
db::DeepShapeStore dss;
|
||||||
|
dss.set_text_enlargement (1);
|
||||||
|
dss.set_text_property_name (tl::Variant ("LABEL"));
|
||||||
|
|
||||||
|
// original layers
|
||||||
|
db::Region rnwell (db::RecursiveShapeIterator (ly, tc, nwell), dss);
|
||||||
|
db::Region ractive (db::RecursiveShapeIterator (ly, tc, active), dss);
|
||||||
|
db::Region rpoly (db::RecursiveShapeIterator (ly, tc, poly), dss);
|
||||||
|
db::Region rpoly_lbl (db::RecursiveShapeIterator (ly, tc, poly_lbl), dss);
|
||||||
|
db::Region rdiff_cont (db::RecursiveShapeIterator (ly, tc, diff_cont), dss);
|
||||||
|
db::Region rpoly_cont (db::RecursiveShapeIterator (ly, tc, poly_cont), dss);
|
||||||
|
db::Region rmetal1 (db::RecursiveShapeIterator (ly, tc, metal1), dss);
|
||||||
|
db::Region rmetal1_lbl (db::RecursiveShapeIterator (ly, tc, metal1_lbl), dss);
|
||||||
|
db::Region rvia1 (db::RecursiveShapeIterator (ly, tc, via1), dss);
|
||||||
|
db::Region rmetal2 (db::RecursiveShapeIterator (ly, tc, metal2), dss);
|
||||||
|
db::Region rmetal2_lbl (db::RecursiveShapeIterator (ly, tc, metal2_lbl), dss);
|
||||||
|
|
||||||
|
// derived regions
|
||||||
|
|
||||||
|
db::Region rpactive = ractive & rnwell;
|
||||||
|
db::Region rpgate = rpactive & rpoly;
|
||||||
|
db::Region rpsd = rpactive - rpgate;
|
||||||
|
|
||||||
|
db::Region rnactive = ractive - rnwell;
|
||||||
|
db::Region rngate = rnactive & rpoly;
|
||||||
|
db::Region rnsd = rnactive - rngate;
|
||||||
|
|
||||||
|
// Global
|
||||||
|
|
||||||
|
db::Region bulk (dss);
|
||||||
|
|
||||||
|
// return the computed layers into the original layout and write it for debugging purposes
|
||||||
|
|
||||||
|
unsigned int lgate = ly.insert_layer (db::LayerProperties (10, 0)); // 10/0 -> Gate
|
||||||
|
unsigned int lsd = ly.insert_layer (db::LayerProperties (11, 0)); // 11/0 -> Source/Drain
|
||||||
|
unsigned int lpdiff = ly.insert_layer (db::LayerProperties (12, 0)); // 12/0 -> P Diffusion
|
||||||
|
unsigned int lndiff = ly.insert_layer (db::LayerProperties (13, 0)); // 13/0 -> N Diffusion
|
||||||
|
|
||||||
|
rpgate.insert_into (&ly, tc.cell_index (), lgate);
|
||||||
|
rngate.insert_into (&ly, tc.cell_index (), lgate);
|
||||||
|
rpsd.insert_into (&ly, tc.cell_index (), lsd);
|
||||||
|
rnsd.insert_into (&ly, tc.cell_index (), lsd);
|
||||||
|
rpsd.insert_into (&ly, tc.cell_index (), lpdiff);
|
||||||
|
rnsd.insert_into (&ly, tc.cell_index (), lndiff);
|
||||||
|
|
||||||
|
// perform the extraction
|
||||||
|
|
||||||
|
db::Netlist nl;
|
||||||
|
db::hier_clusters<db::NetShape> cl;
|
||||||
|
|
||||||
|
db::NetlistDeviceExtractorMOS4Transistor pmos_ex ("PMOS");
|
||||||
|
db::NetlistDeviceExtractorMOS4Transistor nmos_ex ("NMOS");
|
||||||
|
|
||||||
|
db::NetlistDeviceExtractor::input_layers dl;
|
||||||
|
|
||||||
|
dl["SD"] = &rpsd;
|
||||||
|
dl["G"] = &rpgate;
|
||||||
|
dl["W"] = &rnwell;
|
||||||
|
dl["P"] = &rpoly; // not needed for extraction but to return terminal shapes
|
||||||
|
pmos_ex.extract (dss, 0, dl, nl, cl);
|
||||||
|
|
||||||
|
dl["SD"] = &rnsd;
|
||||||
|
dl["G"] = &rngate;
|
||||||
|
dl["W"] = &bulk;
|
||||||
|
dl["P"] = &rpoly; // not needed for extraction but to return terminal shapes
|
||||||
|
nmos_ex.extract (dss, 0, dl, nl, cl);
|
||||||
|
|
||||||
|
// perform the net extraction
|
||||||
|
|
||||||
|
db::NetlistExtractor net_ex;
|
||||||
|
|
||||||
|
db::Connectivity conn;
|
||||||
|
|
||||||
|
// Global nets
|
||||||
|
conn.connect_global (bulk, "BULK");
|
||||||
|
conn.connect_global (rnwell, "NWELL");
|
||||||
|
|
||||||
|
// Intra-layer
|
||||||
|
conn.connect (rpsd);
|
||||||
|
conn.connect (rnsd);
|
||||||
|
conn.connect (rpoly);
|
||||||
|
conn.connect (rdiff_cont);
|
||||||
|
conn.connect (rpoly_cont);
|
||||||
|
conn.connect (rmetal1);
|
||||||
|
conn.connect (rvia1);
|
||||||
|
conn.connect (rmetal2);
|
||||||
|
// Inter-layer
|
||||||
|
conn.connect (rpsd, rdiff_cont);
|
||||||
|
conn.connect (rnsd, rdiff_cont);
|
||||||
|
conn.connect (rpoly, rpoly_cont);
|
||||||
|
conn.connect (rpoly_cont, rmetal1);
|
||||||
|
conn.connect (rdiff_cont, rmetal1);
|
||||||
|
conn.connect (rmetal1, rvia1);
|
||||||
|
conn.connect (rvia1, rmetal2);
|
||||||
|
conn.connect (rpoly, rpoly_lbl); // attaches labels
|
||||||
|
conn.connect (rmetal1, rmetal1_lbl); // attaches labels
|
||||||
|
conn.connect (rmetal2, rmetal2_lbl); // attaches labels
|
||||||
|
|
||||||
|
// extract the nets
|
||||||
|
|
||||||
|
std::list<std::set<std::string> > jn;
|
||||||
|
|
||||||
|
jn.push_back (std::set<std::string> ());
|
||||||
|
jn.back ().insert ("BULK");
|
||||||
|
jn.back ().insert ("VSS");
|
||||||
|
|
||||||
|
jn.push_back (std::set<std::string> ());
|
||||||
|
jn.back ().insert ("NWELL");
|
||||||
|
jn.back ().insert ("VDD");
|
||||||
|
|
||||||
|
net_ex.set_joined_nets ("INV2", jn);
|
||||||
|
|
||||||
|
std::list<tl::GlobPattern> gp;
|
||||||
|
gp.push_back (tl::GlobPattern ("NEXT"));
|
||||||
|
gp.push_back (tl::GlobPattern ("FB"));
|
||||||
|
net_ex.set_joined_net_names (gp);
|
||||||
|
|
||||||
|
net_ex.extract_nets (dss, 0, conn, nl, cl);
|
||||||
|
|
||||||
|
EXPECT_EQ (all_net_names_unique (nl), true);
|
||||||
|
|
||||||
|
// debug layers produced for nets
|
||||||
|
// 202/0 -> Active
|
||||||
|
// 203/0 -> Poly
|
||||||
|
// 204/0 -> Diffusion contacts
|
||||||
|
// 205/0 -> Poly contacts
|
||||||
|
// 206/0 -> Metal1
|
||||||
|
// 207/0 -> Via1
|
||||||
|
// 208/0 -> Metal2
|
||||||
|
// 210/0 -> N source/drain
|
||||||
|
// 211/0 -> P source/drain
|
||||||
|
// 212/0 -> Bulk
|
||||||
|
// 213/0 -> NWell
|
||||||
|
std::map<unsigned int, unsigned int> dump_map;
|
||||||
|
dump_map [layer_of (bulk) ] = ly.insert_layer (db::LayerProperties (212, 0));
|
||||||
|
dump_map [layer_of (rnwell) ] = ly.insert_layer (db::LayerProperties (213, 0));
|
||||||
|
dump_map [layer_of (rpsd) ] = ly.insert_layer (db::LayerProperties (210, 0));
|
||||||
|
dump_map [layer_of (rnsd) ] = ly.insert_layer (db::LayerProperties (211, 0));
|
||||||
|
dump_map [layer_of (rpoly) ] = ly.insert_layer (db::LayerProperties (203, 0));
|
||||||
|
dump_map [layer_of (rdiff_cont)] = ly.insert_layer (db::LayerProperties (204, 0));
|
||||||
|
dump_map [layer_of (rpoly_cont)] = ly.insert_layer (db::LayerProperties (205, 0));
|
||||||
|
dump_map [layer_of (rmetal1) ] = ly.insert_layer (db::LayerProperties (206, 0));
|
||||||
|
dump_map [layer_of (rvia1) ] = ly.insert_layer (db::LayerProperties (207, 0));
|
||||||
|
dump_map [layer_of (rmetal2) ] = ly.insert_layer (db::LayerProperties (208, 0));
|
||||||
|
|
||||||
|
// write nets to layout
|
||||||
|
db::CellMapping cm = dss.cell_mapping_to_original (0, &ly, tc.cell_index ());
|
||||||
|
dump_nets_to_layout (nl, cl, ly, dump_map, cm, true);
|
||||||
|
|
||||||
|
// compare netlist as string
|
||||||
|
CHECKPOINT ();
|
||||||
|
db::compare_netlist (_this, nl,
|
||||||
|
"circuit RINGO ();\n"
|
||||||
|
" subcircuit INV2 $1 (IN=$I8,$2=FB,OUT=OSC,VDD='VDD,VDDZ',VSS='VSS,VSSZ');\n"
|
||||||
|
" subcircuit INV2 $2 (IN=FB,$2=$I20,OUT=$I19,VDD='VDD,VDDZ',VSS='VSS,VSSZ');\n"
|
||||||
|
" subcircuit INV2 $3 (IN=NEXT,$2=$I25,OUT=$I5,VDD='VDD,VDDZ',VSS='VSS,VSSZ');\n"
|
||||||
|
" subcircuit INV2 $4 (IN=$I3,$2=$I24,OUT=NEXT,VDD='VDD,VDDZ',VSS='VSS,VSSZ');\n"
|
||||||
|
" subcircuit INV2 $5 (IN=$I5,$2=$I26,OUT=$I6,VDD='VDD,VDDZ',VSS='VSS,VSSZ');\n"
|
||||||
|
" subcircuit INV2 $6 (IN=$I6,$2=$I27,OUT=$I7,VDD='VDD,VDDZ',VSS='VSS,VSSZ');\n"
|
||||||
|
" subcircuit INV2 $7 (IN=$I7,$2=$I28,OUT=$I8,VDD='VDD,VDDZ',VSS='VSS,VSSZ');\n"
|
||||||
|
" subcircuit INV2 $8 (IN=$I19,$2=$I21,OUT=$I1,VDD='VDD,VDDZ',VSS='VSS,VSSZ');\n"
|
||||||
|
" subcircuit INV2 $9 (IN=$I1,$2=$I22,OUT=$I2,VDD='VDD,VDDZ',VSS='VSS,VSSZ');\n"
|
||||||
|
" subcircuit INV2 $10 (IN=$I2,$2=$I23,OUT=$I3,VDD='VDD,VDDZ',VSS='VSS,VSSZ');\n"
|
||||||
|
"end;\n"
|
||||||
|
"circuit INV2 (IN=IN,$2=$2,OUT=OUT,VDD=VDD,VSS=VSS);\n"
|
||||||
|
" device PMOS $1 (S=$2,G=IN,D=VDD,B=VDD) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||||
|
" device PMOS $2 (S=VDD,G=$2,D=OUT,B=VDD) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n"
|
||||||
|
" device NMOS $3 (S=$2,G=IN,D=VSS,B=VSS) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||||
|
" device NMOS $4 (S=VSS,G=$2,D=OUT,B=VSS) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n"
|
||||||
|
" subcircuit TRANS $1 ($1=$2,$2=VSS,$3=IN);\n"
|
||||||
|
" subcircuit TRANS $2 ($1=$2,$2=VDD,$3=IN);\n"
|
||||||
|
" subcircuit TRANS $3 ($1=VDD,$2=OUT,$3=$2);\n"
|
||||||
|
" subcircuit TRANS $4 ($1=VSS,$2=OUT,$3=$2);\n"
|
||||||
|
"end;\n"
|
||||||
|
"circuit TRANS ($1=$1,$2=$2,$3=$3);\n"
|
||||||
|
"end;\n"
|
||||||
|
);
|
||||||
|
|
||||||
|
// doesn't do anything here, but we test that this does not destroy anything:
|
||||||
|
nl.combine_devices ();
|
||||||
|
|
||||||
|
// make pins for named nets of top-level circuits - this way they are not purged
|
||||||
|
nl.make_top_level_pins ();
|
||||||
|
nl.purge ();
|
||||||
|
|
||||||
|
// compare netlist as string
|
||||||
|
CHECKPOINT ();
|
||||||
|
db::compare_netlist (_this, nl,
|
||||||
|
"circuit RINGO (FB=FB,OSC=OSC,NEXT=NEXT,'VDD,VDDZ'='VDD,VDDZ','VSS,VSSZ'='VSS,VSSZ');\n"
|
||||||
|
" subcircuit INV2 $1 (IN=$I8,$2=FB,OUT=OSC,VDD='VDD,VDDZ',VSS='VSS,VSSZ');\n"
|
||||||
|
" subcircuit INV2 $2 (IN=FB,$2=$I20,OUT=$I19,VDD='VDD,VDDZ',VSS='VSS,VSSZ');\n"
|
||||||
|
" subcircuit INV2 $3 (IN=NEXT,$2=$I25,OUT=$I5,VDD='VDD,VDDZ',VSS='VSS,VSSZ');\n"
|
||||||
|
" subcircuit INV2 $4 (IN=$I3,$2=$I24,OUT=NEXT,VDD='VDD,VDDZ',VSS='VSS,VSSZ');\n"
|
||||||
|
" subcircuit INV2 $5 (IN=$I5,$2=$I26,OUT=$I6,VDD='VDD,VDDZ',VSS='VSS,VSSZ');\n"
|
||||||
|
" subcircuit INV2 $6 (IN=$I6,$2=$I27,OUT=$I7,VDD='VDD,VDDZ',VSS='VSS,VSSZ');\n"
|
||||||
|
" subcircuit INV2 $7 (IN=$I7,$2=$I28,OUT=$I8,VDD='VDD,VDDZ',VSS='VSS,VSSZ');\n"
|
||||||
|
" subcircuit INV2 $8 (IN=$I19,$2=$I21,OUT=$I1,VDD='VDD,VDDZ',VSS='VSS,VSSZ');\n"
|
||||||
|
" subcircuit INV2 $9 (IN=$I1,$2=$I22,OUT=$I2,VDD='VDD,VDDZ',VSS='VSS,VSSZ');\n"
|
||||||
|
" subcircuit INV2 $10 (IN=$I2,$2=$I23,OUT=$I3,VDD='VDD,VDDZ',VSS='VSS,VSSZ');\n"
|
||||||
|
"end;\n"
|
||||||
|
"circuit INV2 (IN=IN,$2=$2,OUT=OUT,VDD=VDD,VSS=VSS);\n"
|
||||||
|
" device PMOS $1 (S=$2,G=IN,D=VDD,B=VDD) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||||
|
" device PMOS $2 (S=VDD,G=$2,D=OUT,B=VDD) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n"
|
||||||
|
" device NMOS $3 (S=$2,G=IN,D=VSS,B=VSS) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||||
|
" device NMOS $4 (S=VSS,G=$2,D=OUT,B=VSS) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n"
|
||||||
|
"end;\n"
|
||||||
|
);
|
||||||
|
|
||||||
|
// compare the collected test data
|
||||||
|
|
||||||
|
std::string au = tl::testsrc ();
|
||||||
|
au = tl::combine_path (au, "testdata");
|
||||||
|
au = tl::combine_path (au, "algo");
|
||||||
|
au = tl::combine_path (au, "device_extract_au1_join_nets.gds");
|
||||||
|
|
||||||
|
db::compare_layouts (_this, ly, au);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1854,6 +1854,14 @@ CODE
|
||||||
# @synopsis connect_implicit(cell_pattern, label_pattern)
|
# @synopsis connect_implicit(cell_pattern, label_pattern)
|
||||||
# See \Netter#connect_implicit for a description of that function.
|
# See \Netter#connect_implicit for a description of that function.
|
||||||
|
|
||||||
|
# %DRC%
|
||||||
|
# @name connect_explicit
|
||||||
|
# @brief Specifies explicit net connections
|
||||||
|
# @synopsis connect_explicit(net_names)
|
||||||
|
# @synopsis connect_explicit(cell_pattern, net_names)
|
||||||
|
# See \Netter#connect_explicit for a description of that function.
|
||||||
|
# Net names is an array (use square brackets to list the net names).
|
||||||
|
|
||||||
# %DRC%
|
# %DRC%
|
||||||
# @name antenna_check
|
# @name antenna_check
|
||||||
# @brief Performs an antenna check
|
# @brief Performs an antenna check
|
||||||
|
|
@ -1892,6 +1900,7 @@ CODE
|
||||||
connect
|
connect
|
||||||
connect_global
|
connect_global
|
||||||
connect_implicit
|
connect_implicit
|
||||||
|
connect_explicit
|
||||||
device_scaling
|
device_scaling
|
||||||
extract_devices
|
extract_devices
|
||||||
l2n_data
|
l2n_data
|
||||||
|
|
|
||||||
|
|
@ -67,6 +67,8 @@ module DRC
|
||||||
@netlisted = false
|
@netlisted = false
|
||||||
@connect_implicit = []
|
@connect_implicit = []
|
||||||
@connect_implicit_per_cell = {}
|
@connect_implicit_per_cell = {}
|
||||||
|
@connect_explicit = []
|
||||||
|
@connect_explicit_per_cell = {}
|
||||||
@l2n = nil
|
@l2n = nil
|
||||||
@lnum = 0
|
@lnum = 0
|
||||||
@device_scaling = 1.0
|
@device_scaling = 1.0
|
||||||
|
|
@ -241,6 +243,8 @@ module DRC
|
||||||
@netlisted = false
|
@netlisted = false
|
||||||
@connect_implicit = []
|
@connect_implicit = []
|
||||||
@connect_implicit_per_cell = {}
|
@connect_implicit_per_cell = {}
|
||||||
|
@connect_explicit = []
|
||||||
|
@connect_explicit_per_cell = {}
|
||||||
_clear_data
|
_clear_data
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -286,6 +290,67 @@ module DRC
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# %DRC%
|
||||||
|
# @name connect_explicit
|
||||||
|
# @brief Specifies a list of net names for nets to connect explicitly
|
||||||
|
# @synopsis connect_explicit(net_names)
|
||||||
|
# @synopsis connect_explicit(cell_pattern, net_names)
|
||||||
|
# Use this method to explicitly connect nets even if there is no physical connection.
|
||||||
|
# As this breaks with the concept of physical verification, this feature should be used
|
||||||
|
# with care.
|
||||||
|
#
|
||||||
|
# The first version of this function will connect all nets listed in the "net_names" array
|
||||||
|
# in the top level cell. The second version takes a cell name pattern and connects all nets listed
|
||||||
|
# in "net_names" for cells matching this pattern.
|
||||||
|
#
|
||||||
|
# A use case for this method is the following: consider a set of standard cells. These do not have a bulk
|
||||||
|
# or n-well pin in the schematics. They also do not have build in tie-down diodes for the
|
||||||
|
# substrate connections. In this case there is a build-in discrepancy between the
|
||||||
|
# schematics and the layout: bulk and VSS are separate nets within the layout, but the
|
||||||
|
# schematic does not list them as separate. The solution is to make an explicit connection
|
||||||
|
# between VDD and n-well and VSS and bulk, provided VDD and VSS are properly labelled as "VDD" and "VSS"
|
||||||
|
# and n-well and bulk are accessible as named nets (for bulk you can use "connect_global").
|
||||||
|
#
|
||||||
|
# The following code will establish an explicit connection for all cells called "INV.." between
|
||||||
|
# BULK and VSS nets:
|
||||||
|
#
|
||||||
|
# @code
|
||||||
|
# connect_global(bulk, "BULK")
|
||||||
|
# ...
|
||||||
|
# connect_explicit("INV*", [ "BULK", "VSS" ])
|
||||||
|
# @/code
|
||||||
|
#
|
||||||
|
# Explicit connections also imply implicit connections between different parts of
|
||||||
|
# one of the nets. In the example before, "VSS" pieces without a physical connection
|
||||||
|
# will also be connected.
|
||||||
|
#
|
||||||
|
# When you use explicit connections you should make sure by other ways that the connection
|
||||||
|
# is made physically. For example, for the bulk/n-well pin example above, by enforcing at least one
|
||||||
|
# tie-down diode per n-well island and in the substrate by means of a DRC rule.
|
||||||
|
#
|
||||||
|
# The explicit connections are applied on the next net extraction and cleared
|
||||||
|
# on "clear_connections".
|
||||||
|
|
||||||
|
def connect_explicit(arg1, arg2 = nil)
|
||||||
|
|
||||||
|
@engine._context("connect_explicit") do
|
||||||
|
|
||||||
|
cleanup
|
||||||
|
if arg2
|
||||||
|
arg2.is_a?(Array) || raise("The second argument has to be an array of strings")
|
||||||
|
arg2.find { |a| !a.is_a?(String) } && raise("The second argument has to be an array of strings")
|
||||||
|
arg1.is_a?(String) || raise("The first argument has to be a string")
|
||||||
|
@connect_explicit_per_cell[arg1] ||= []
|
||||||
|
@connect_explicit_per_cell[arg1] << arg2
|
||||||
|
else
|
||||||
|
arg1.is_a?(String) || raise("The argument has to be a string")
|
||||||
|
@connect_explicit << arg1
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
# %DRC%
|
# %DRC%
|
||||||
# @brief Performs an antenna check
|
# @brief Performs an antenna check
|
||||||
# @name antenna_check
|
# @name antenna_check
|
||||||
|
|
@ -481,16 +546,29 @@ module DRC
|
||||||
# run extraction in a timed environment
|
# run extraction in a timed environment
|
||||||
if ! @netlisted
|
if ! @netlisted
|
||||||
|
|
||||||
# build a glob expression from the parts
|
# configure implicit net connections
|
||||||
expr = _join_glob_pattern(@connect_implicit)
|
@l2n.clear_join_net_names
|
||||||
|
@connect_implicit.each do |label_pattern|
|
||||||
# build cell-pattern specific glob expressions from the parts
|
@l2n.join_net_names(label_pattern)
|
||||||
per_cell_expr = {}
|
end
|
||||||
@connect_implicit_per_cell.each do |cell_pattern,label_pattern|
|
@connect_implicit_per_cell.each do |cell_pattern,label_pattern|
|
||||||
per_cell_expr[cell_pattern] = _join_glob_pattern(label_pattern)
|
label_pattern.each do |lp|
|
||||||
|
@l2n.join_net_names(cell_pattern, lp)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@engine._cmd(@l2n, :extract_netlist, expr, per_cell_expr)
|
# configure explicit net connections
|
||||||
|
@l2n.clear_join_nets
|
||||||
|
@connect_explicit.each do |names|
|
||||||
|
@l2n.join_nets(names)
|
||||||
|
end
|
||||||
|
@connect_explicit_per_cell.each do |cell_pattern,name_lists|
|
||||||
|
name_lists.each do |names|
|
||||||
|
@l2n.join_nets(cell_pattern, names)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
@engine._cmd(@l2n, :extract_netlist)
|
||||||
@netlisted = true
|
@netlisted = true
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
@ -548,18 +626,6 @@ module DRC
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def _join_glob_pattern(exprs)
|
|
||||||
|
|
||||||
if exprs.size > 1
|
|
||||||
expr = "{" + exprs.join(",") + "}"
|
|
||||||
else
|
|
||||||
expr = exprs[0] || ""
|
|
||||||
end
|
|
||||||
|
|
||||||
expr
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
def _make_data
|
def _make_data
|
||||||
|
|
||||||
if @engine._dss
|
if @engine._dss
|
||||||
|
|
|
||||||
|
|
@ -312,6 +312,17 @@ l1 = input(1, 0)
|
||||||
<p>
|
<p>
|
||||||
See <a href="/about/drc_ref_netter.xml#connect">Netter#connect</a> for a description of that function.
|
See <a href="/about/drc_ref_netter.xml#connect">Netter#connect</a> for a description of that function.
|
||||||
</p>
|
</p>
|
||||||
|
<a name="connect_explicit"/><h2>"connect_explicit" - Specifies explicit net connections</h2>
|
||||||
|
<keyword name="connect_explicit"/>
|
||||||
|
<p>Usage:</p>
|
||||||
|
<ul>
|
||||||
|
<li><tt>connect_explicit(net_names)</tt></li>
|
||||||
|
<li><tt>connect_explicit(cell_pattern, net_names)</tt></li>
|
||||||
|
</ul>
|
||||||
|
<p>
|
||||||
|
See <a href="/about/drc_ref_netter.xml#connect_explicit">Netter#connect_explicit</a> for a description of that function.
|
||||||
|
Net names is an array (use square brackets to list the net names).
|
||||||
|
</p>
|
||||||
<a name="connect_global"/><h2>"connect_global" - Specifies a connection to a global net</h2>
|
<a name="connect_global"/><h2>"connect_global" - Specifies a connection to a global net</h2>
|
||||||
<keyword name="connect_global"/>
|
<keyword name="connect_global"/>
|
||||||
<p>Usage:</p>
|
<p>Usage:</p>
|
||||||
|
|
|
||||||
|
|
@ -219,6 +219,50 @@ joins.
|
||||||
Connections are accumulated. The connections defined so far
|
Connections are accumulated. The connections defined so far
|
||||||
can be cleared with <a href="#clear_connections">clear_connections</a>.
|
can be cleared with <a href="#clear_connections">clear_connections</a>.
|
||||||
</p>
|
</p>
|
||||||
|
<a name="connect_explicit"/><h2>"connect_explicit" - Specifies a list of net names for nets to connect explicitly</h2>
|
||||||
|
<keyword name="connect_explicit"/>
|
||||||
|
<p>Usage:</p>
|
||||||
|
<ul>
|
||||||
|
<li><tt>connect_explicit(net_names)</tt></li>
|
||||||
|
<li><tt>connect_explicit(cell_pattern, net_names)</tt></li>
|
||||||
|
</ul>
|
||||||
|
<p>
|
||||||
|
Use this method to explicitly connect nets even if there is no physical connection.
|
||||||
|
As this breaks with the concept of physical verification, this feature should be used
|
||||||
|
with care.
|
||||||
|
</p><p>
|
||||||
|
The first version of this function will connect all nets listed in the "net_names" array
|
||||||
|
in the top level cell. The second version takes a cell name pattern and connects all nets listed
|
||||||
|
in "net_names" for cells matching this pattern.
|
||||||
|
</p><p>
|
||||||
|
A use case for this method is the following: consider a set of standard cells. These do not have a bulk
|
||||||
|
or n-well pin in the schematics. They also do not have build in tie-down diodes for the
|
||||||
|
substrate connections. In this case there is a build-in discrepancy between the
|
||||||
|
schematics and the layout: bulk and VSS are separate nets within the layout, but the
|
||||||
|
schematic does not list them as separate. The solution is to make an explicit connection
|
||||||
|
between VDD and n-well and VSS and bulk, provided VDD and VSS are properly labelled as "VDD" and "VSS"
|
||||||
|
and n-well and bulk are accessible as named nets (for bulk you can use "connect_global").
|
||||||
|
</p><p>
|
||||||
|
The following code will establish an explicit connection for all cells called "INV.." between
|
||||||
|
BULK and VSS nets:
|
||||||
|
</p><p>
|
||||||
|
<pre>
|
||||||
|
connect_global(bulk, "BULK")
|
||||||
|
...
|
||||||
|
connect_explicit("INV*", [ "BULK", "VSS" ])
|
||||||
|
</pre>
|
||||||
|
</p><p>
|
||||||
|
Explicit connections also imply implicit connections between different parts of
|
||||||
|
one of the nets. In the example before, "VSS" pieces without a physical connection
|
||||||
|
will also be connected.
|
||||||
|
</p><p>
|
||||||
|
When you use explicit connections you should make sure by other ways that the connection
|
||||||
|
is made physically. For example, for the bulk/n-well pin example above, by enforcing at least one
|
||||||
|
tie-down diode per n-well island and in the substrate by means of a DRC rule.
|
||||||
|
</p><p>
|
||||||
|
The explicit connections are applied on the next net extraction and cleared
|
||||||
|
on "clear_connections".
|
||||||
|
</p>
|
||||||
<a name="connect_global"/><h2>"connect_global" - Connects a layer with a global net</h2>
|
<a name="connect_global"/><h2>"connect_global" - Connects a layer with a global net</h2>
|
||||||
<keyword name="connect_global"/>
|
<keyword name="connect_global"/>
|
||||||
<p>Usage:</p>
|
<p>Usage:</p>
|
||||||
|
|
|
||||||
|
|
@ -114,13 +114,15 @@ netter.equivalent_pins("NAND2", 0, 1)
|
||||||
</pre>
|
</pre>
|
||||||
</p><p>
|
</p><p>
|
||||||
The circuit argument is either a circuit name (a string) or a Circuit object
|
The circuit argument is either a circuit name (a string) or a Circuit object
|
||||||
from the schematic netlist.
|
from the schematic netlist.
|
||||||
|
</p><p>
|
||||||
|
Names are case sensitive for layout-derived netlists and case-insensitive for SPICE schematic netlists.
|
||||||
</p><p>
|
</p><p>
|
||||||
The pin arguments are zero-based pin numbers, where 0 is the first number, 1 the second etc.
|
The pin arguments are zero-based pin numbers, where 0 is the first number, 1 the second etc.
|
||||||
If the netlist provides named pins, names can be used instead of numbers.
|
If the netlist provides named pins, names can be used instead of numbers. Again, use upper
|
||||||
|
case pin names for SPICE netlists.
|
||||||
</p><p>
|
</p><p>
|
||||||
Before this method can be used, a schematic netlist needs to be loaded with
|
Use this method andwhere in the script before the <a href="#compare">compare</a> call.
|
||||||
<a href="#schematic">schematic</a>.
|
|
||||||
</p>
|
</p>
|
||||||
<a name="join_symmetric_nets"/><h2>"join_symmetric_nets" - Joins symmetric nets of selected circuits on the extracted netlist</h2>
|
<a name="join_symmetric_nets"/><h2>"join_symmetric_nets" - Joins symmetric nets of selected circuits on the extracted netlist</h2>
|
||||||
<keyword name="join_symmetric_nets"/>
|
<keyword name="join_symmetric_nets"/>
|
||||||
|
|
@ -174,6 +176,12 @@ with inherent ambiguity such as decoders, the complexity
|
||||||
can be increased at the expense of potentially larger runtimes.
|
can be increased at the expense of potentially larger runtimes.
|
||||||
The runtime penality is roughly proportional to the branch
|
The runtime penality is roughly proportional to the branch
|
||||||
complexity.
|
complexity.
|
||||||
|
</p><p>
|
||||||
|
By default, the branch complexity is unlimited, but it may
|
||||||
|
be reduced in order to limit the compare runtimes at the cost
|
||||||
|
of a less elaborate compare attempt. The preferred solution
|
||||||
|
however is to use labels for net name hints which also reduces
|
||||||
|
the depth.
|
||||||
</p>
|
</p>
|
||||||
<a name="max_depth"/><h2>"max_depth" - Configures the maximum search depth for net match deduction</h2>
|
<a name="max_depth"/><h2>"max_depth" - Configures the maximum search depth for net match deduction</h2>
|
||||||
<keyword name="max_depth"/>
|
<keyword name="max_depth"/>
|
||||||
|
|
@ -191,6 +199,12 @@ the next net. With higher values for the depth, the algorithm
|
||||||
pursues this "deduction path" in greater depth while with
|
pursues this "deduction path" in greater depth while with
|
||||||
smaller values, the algorithm prefers picking nets in a random fashion
|
smaller values, the algorithm prefers picking nets in a random fashion
|
||||||
as the seeds for this deduction path. The default value is 8.
|
as the seeds for this deduction path. The default value is 8.
|
||||||
|
</p><p>
|
||||||
|
By default, the depth is unlimited, but it may
|
||||||
|
be reduced in order to limit the compare runtimes at the cost
|
||||||
|
of a less elaborate compare attempt. The preferred solution
|
||||||
|
however is to use labels for net name hints which also reduces
|
||||||
|
the branch complexity.
|
||||||
</p>
|
</p>
|
||||||
<a name="max_res"/><h2>"max_res" - Ignores resistors with a resistance above a certain value</h2>
|
<a name="max_res"/><h2>"max_res" - Ignores resistors with a resistance above a certain value</h2>
|
||||||
<keyword name="max_res"/>
|
<keyword name="max_res"/>
|
||||||
|
|
@ -223,11 +237,13 @@ This method will force an equivalence between the two circuits.
|
||||||
By default, circuits are identified by name. If names are different, this
|
By default, circuits are identified by name. If names are different, this
|
||||||
method allows establishing an explicit correspondence.
|
method allows establishing an explicit correspondence.
|
||||||
</p><p>
|
</p><p>
|
||||||
|
circuit_a is for the layout netlist, circuit_b for the schematic netlist.
|
||||||
|
Names are case sensitive for layout-derived netlists and case-insensitive for SPICE schematic netlists.
|
||||||
|
</p><p>
|
||||||
One of the circuits may be nil. In this case, the corresponding
|
One of the circuits may be nil. In this case, the corresponding
|
||||||
other circuit is mapped to "nothing", i.e. ignored.
|
other circuit is mapped to "nothing", i.e. ignored.
|
||||||
</p><p>
|
</p><p>
|
||||||
Before this method can be used, a schematic netlist needs to be loaded with
|
Use this method andwhere in the script before the <a href="#compare">compare</a> call.
|
||||||
<a href="#schematic">schematic</a>.
|
|
||||||
</p>
|
</p>
|
||||||
<a name="same_device_classes"/><h2>"same_device_classes" - Establishes an equivalence between the device classes</h2>
|
<a name="same_device_classes"/><h2>"same_device_classes" - Establishes an equivalence between the device classes</h2>
|
||||||
<keyword name="same_device_classes"/>
|
<keyword name="same_device_classes"/>
|
||||||
|
|
@ -244,6 +260,9 @@ method allows establishing an explicit correspondence.
|
||||||
Before this method can be used, a schematic netlist needs to be loaded with
|
Before this method can be used, a schematic netlist needs to be loaded with
|
||||||
<a href="#schematic">schematic</a>.
|
<a href="#schematic">schematic</a>.
|
||||||
</p><p>
|
</p><p>
|
||||||
|
class_a is for the layout netlist, class_b for the schematic netlist.
|
||||||
|
Names are case sensitive for layout-derived netlists and case-insensitive for SPICE schematic netlists.
|
||||||
|
</p><p>
|
||||||
One of the device classes may be "nil". In this case, the corresponding
|
One of the device classes may be "nil". In this case, the corresponding
|
||||||
other device class is mapped to "nothing", i.e. ignored.
|
other device class is mapped to "nothing", i.e. ignored.
|
||||||
</p><p>
|
</p><p>
|
||||||
|
|
@ -260,7 +279,11 @@ schematic side.
|
||||||
</p><p>
|
</p><p>
|
||||||
Once a device class is mentioned with "same_device_classes", matching by
|
Once a device class is mentioned with "same_device_classes", matching by
|
||||||
name is disabled for this class. So after using 'same_device_classes("A", "B")'
|
name is disabled for this class. So after using 'same_device_classes("A", "B")'
|
||||||
"A" is no longer equivalent to "A" on the other side.
|
"A" is no longer equivalent to "A" on the other side. If you want "A" to
|
||||||
|
stay equivalent to "A" too, you need to use 'same_device_classes("A", "A")'
|
||||||
|
in addition.
|
||||||
|
</p><p>
|
||||||
|
Use this method andwhere in the script before the <a href="#compare">compare</a> call.
|
||||||
</p>
|
</p>
|
||||||
<a name="same_nets"/><h2>"same_nets" - Establishes an equivalence between the nets</h2>
|
<a name="same_nets"/><h2>"same_nets" - Establishes an equivalence between the nets</h2>
|
||||||
<keyword name="same_nets"/>
|
<keyword name="same_nets"/>
|
||||||
|
|
@ -281,8 +304,10 @@ After using this function, the compare algorithm will consider these nets equiva
|
||||||
Use this method to provide hints for the comparer in cases which are difficult to
|
Use this method to provide hints for the comparer in cases which are difficult to
|
||||||
resolve otherwise.
|
resolve otherwise.
|
||||||
</p><p>
|
</p><p>
|
||||||
Before this method can be used, a schematic netlist needs to be loaded with
|
circuit_a and net_a are for the layout netlist, circuit_b and net_b for the schematic netlist.
|
||||||
<a href="#schematic">schematic</a>.
|
Names are case sensitive for layout-derived netlists and case-insensitive for SPICE schematic netlists.
|
||||||
|
</p><p>
|
||||||
|
Use this method andwhere in the script before the <a href="#compare">compare</a> call.
|
||||||
</p>
|
</p>
|
||||||
<a name="schematic"/><h2>"schematic" - Gets, sets or reads the reference netlist</h2>
|
<a name="schematic"/><h2>"schematic" - Gets, sets or reads the reference netlist</h2>
|
||||||
<keyword name="schematic"/>
|
<keyword name="schematic"/>
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 4.8 KiB |
|
Before Width: | Height: | Size: 8.4 KiB After Width: | Height: | Size: 8.4 KiB |
|
Before Width: | Height: | Size: 7.9 KiB After Width: | Height: | Size: 7.9 KiB |
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 4.8 KiB |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
|
@ -183,4 +183,76 @@ connect(metal2, metal2_labels)</pre>
|
||||||
statements.
|
statements.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<h2>Explicit connections</h2>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Explicit connections can be useful to enforce a connection in the layout
|
||||||
|
which is made in the schematic, but not physically on the level of the cell.
|
||||||
|
For example consider the following layout for an inverter:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<img src="/manual/inv.png"/>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
In the layout there are no tie-down diodes, hence there is no physical
|
||||||
|
connection to the n-well region and no physical connection to the bulk
|
||||||
|
substrate. This saves space, but these diodes need to be added by other
|
||||||
|
ways.
|
||||||
|
Usually this is done when the standard cells are combined into
|
||||||
|
macros. Filler cells will be added which include these substrate and
|
||||||
|
well contacts.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
On the inverter level however, there is no such connection. Therefore
|
||||||
|
the inverter has separate bulk and n-well pins. The schematic sometimes
|
||||||
|
is a simplified version which does not offer these pins. Hence there is
|
||||||
|
an intrinsic mismatch between layout and schematic.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<img src="/manual/inv_explicit.png"/>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
To align layout and schematics, bulk and VSS pins can be connected
|
||||||
|
explicitly. Same for n-well and VDD.
|
||||||
|
There is a certain risk to forget making these connections later.
|
||||||
|
But this risk can be mitigated by implementing DRC rules which
|
||||||
|
demand at least one tie-down diode for each isolated n-well island
|
||||||
|
or the bulk.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
To establish an explicit connection, make sure that n-well and
|
||||||
|
bulk have proper names. For the n-well this can be done by creating
|
||||||
|
labels on the n-well islands giving them a proper name - e.g. "NWELL".
|
||||||
|
The bulk isn't a real layout layer with polygons on it. Using "connect_global"
|
||||||
|
will both connect everthing on this layer and give it a name.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The following code will connect the bulk net with "VSS" inside the cell "INV":
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre>connect_global(bulk, "BULK")
|
||||||
|
...
|
||||||
|
connect_explicit("INV", [ "BULK", "VSS" ])
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The cell name can be a pattern. For example "INV*" will apply this rule on all
|
||||||
|
cells starting with "INV".
|
||||||
|
The cell is not mandatory: if it is omitted, the rule is applied to top level only
|
||||||
|
to avoid introducing rules in subcells where they would mask layout errors.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
An explicit connection will also imply implicit connections on the nets
|
||||||
|
listed in the net names. So in the example above, different pieces of "VSS"
|
||||||
|
are connected even if they are not physically connected.
|
||||||
|
</p>
|
||||||
|
|
||||||
</doc>
|
</doc>
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 4.5 KiB |
|
After Width: | Height: | Size: 4.4 KiB |
|
After Width: | Height: | Size: 35 KiB |
|
|
@ -92,6 +92,7 @@
|
||||||
<file alias="lvs_symm_nodes.png">doc/manual/lvs_symm_nodes.png</file>
|
<file alias="lvs_symm_nodes.png">doc/manual/lvs_symm_nodes.png</file>
|
||||||
<file alias="lvs_connect.xml">doc/manual/lvs_connect.xml</file>
|
<file alias="lvs_connect.xml">doc/manual/lvs_connect.xml</file>
|
||||||
<file alias="inv.png">doc/manual/inv.png</file>
|
<file alias="inv.png">doc/manual/inv.png</file>
|
||||||
|
<file alias="inv_explicit.png">doc/manual/inv_explicit.png</file>
|
||||||
<file alias="inv_no_transistors.png">doc/manual/inv_no_transistors.png</file>
|
<file alias="inv_no_transistors.png">doc/manual/inv_no_transistors.png</file>
|
||||||
<file alias="inv_transistors.png">doc/manual/inv_transistors.png</file>
|
<file alias="inv_transistors.png">doc/manual/inv_transistors.png</file>
|
||||||
<file alias="inv_with_diodes.png">doc/manual/inv_with_diodes.png</file>
|
<file alias="inv_with_diodes.png">doc/manual/inv_with_diodes.png</file>
|
||||||
|
|
|
||||||
|
|
@ -513,40 +513,90 @@ static std::pair<const db::DeviceTerminalDefinition *, const db::DeviceTerminalD
|
||||||
return std::make_pair (termrefs.first ? termrefs.first->terminal_def () : 0, termrefs.second ? termrefs.second->terminal_def () : 0);
|
return std::make_pair (termrefs.first ? termrefs.first->terminal_def () : 0, termrefs.second ? termrefs.second->terminal_def () : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::pair<const db::DeviceTerminalDefinition *, const db::DeviceTerminalDefinition *> terminal_defs_from_device_classes (IndexedNetlistModel *model, const std::pair<const db::DeviceClass *, const db::DeviceClass *> &device_classes, const std::pair<const db::Device *, const db::Device *> &devices, size_t terminal_id)
|
static std::vector<std::pair<const db::DeviceTerminalDefinition *, const db::DeviceTerminalDefinition *> > terminal_defs_from_device_classes (IndexedNetlistModel *model, const std::pair<const db::DeviceClass *, const db::DeviceClass *> &device_classes, const std::pair<const db::Device *, const db::Device *> &devices)
|
||||||
{
|
{
|
||||||
const db::DeviceTerminalDefinition *td1 = 0, *td2 = 0;
|
std::vector<std::pair<const db::DeviceTerminalDefinition *, const db::DeviceTerminalDefinition *> > result;
|
||||||
if (device_classes.first && device_classes.first->terminal_definitions ().size () > terminal_id) {
|
|
||||||
td1 = &device_classes.first->terminal_definitions () [terminal_id];
|
std::map<size_t, std::pair<std::vector<std::pair<const db::DeviceTerminalDefinition *, const db::Net *> >, std::vector<std::pair<const db::DeviceTerminalDefinition *, const db::Net *> > > > nets;
|
||||||
|
|
||||||
|
size_t n1 = 0;
|
||||||
|
if (device_classes.first) {
|
||||||
|
n1 = device_classes.first->terminal_definitions ().size ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t n2 = 0;
|
||||||
if (device_classes.second) {
|
if (device_classes.second) {
|
||||||
|
n2 = device_classes.second->terminal_definitions ().size ();
|
||||||
|
}
|
||||||
|
|
||||||
size_t second_terminal_id = terminal_id;
|
for (size_t i = 0; i < n1 || i < n2; ++i) {
|
||||||
|
|
||||||
// Because of terminal swapping we need to look up the second terminal by looking for equivalent terminals which carry the corresponding net
|
if (i < n2) {
|
||||||
if (td1 && devices.first && devices.second) {
|
const db::DeviceTerminalDefinition &td = device_classes.second->terminal_definitions () [i];
|
||||||
|
size_t id = td.id ();
|
||||||
|
size_t id_norm = device_classes.second->normalize_terminal_id (id);
|
||||||
|
nets [id_norm].second.push_back (std::make_pair (&td, devices.second->net_for_terminal (id)));
|
||||||
|
}
|
||||||
|
|
||||||
size_t td1_id_norm = device_classes.first->normalize_terminal_id (td1->id ());
|
if (i < n1) {
|
||||||
const db::Net *n2 = model->second_net_for (devices.first->net_for_terminal (terminal_id));
|
const db::DeviceTerminalDefinition &td = device_classes.first->terminal_definitions () [i];
|
||||||
|
size_t id = td.id ();
|
||||||
|
size_t id_norm = device_classes.first->normalize_terminal_id (id);
|
||||||
|
nets [id_norm].first.push_back (std::make_pair (&td, devices.first->net_for_terminal (id)));
|
||||||
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < device_classes.second->terminal_definitions ().size (); ++i) {
|
}
|
||||||
const db::DeviceTerminalDefinition &td = device_classes.second->terminal_definitions () [i];
|
|
||||||
if (device_classes.second->normalize_terminal_id (td.id ()) == td1_id_norm) {
|
for (std::map<size_t, std::pair<std::vector<std::pair<const db::DeviceTerminalDefinition *, const db::Net *> >, std::vector<std::pair<const db::DeviceTerminalDefinition *, const db::Net *> > > >::iterator n = nets.begin (); n != nets.end (); ++n) {
|
||||||
if (devices.second->net_for_terminal (i) == n2) {
|
|
||||||
second_terminal_id = i;
|
std::vector<std::pair<const db::DeviceTerminalDefinition *, const db::Net *> > &nn1 = n->second.first;
|
||||||
break;
|
std::vector<std::pair<const db::DeviceTerminalDefinition *, const db::Net *> > &nn2 = n->second.second;
|
||||||
|
|
||||||
|
if (nn2.empty ()) {
|
||||||
|
|
||||||
|
for (std::vector<std::pair<const db::DeviceTerminalDefinition *, const db::Net *> >::const_iterator i = nn1.begin (); i != nn1.end (); ++i) {
|
||||||
|
result.push_back (std::make_pair (i->first, (const db::DeviceTerminalDefinition *) 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (nn1.empty ()) {
|
||||||
|
|
||||||
|
for (std::vector<std::pair<const db::DeviceTerminalDefinition *, const db::Net *> >::const_iterator j = nn2.begin (); j != nn2.end (); ++j) {
|
||||||
|
result.push_back (std::make_pair ((const db::DeviceTerminalDefinition *) 0, j->first));
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
std::vector<std::pair<const db::DeviceTerminalDefinition *, const db::Net *> >::iterator w = nn1.begin ();
|
||||||
|
for (std::vector<std::pair<const db::DeviceTerminalDefinition *, const db::Net *> >::const_iterator i = nn1.begin (); i != nn1.end (); ++i) {
|
||||||
|
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
|
for (std::vector<std::pair<const db::DeviceTerminalDefinition *, const db::Net *> >::iterator j = nn2.begin (); j != nn2.end () && ! found; ++j) {
|
||||||
|
const db::Net *n2 = model->second_net_for (i->second);
|
||||||
|
if (n2 == j->second) {
|
||||||
|
result.push_back (std::make_pair (i->first, j->first));
|
||||||
|
nn2.erase (j);
|
||||||
|
found = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (! found) {
|
||||||
|
*w++ = *i;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
nn1.erase (w, nn1.end ());
|
||||||
|
|
||||||
|
for (size_t i = 0; i < nn1.size () && i < nn2.size (); ++i) {
|
||||||
|
result.push_back (std::make_pair (nn1 [i].first, nn2 [i].first));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
td2 = &device_classes.second->terminal_definitions () [second_terminal_id];
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::make_pair (td1, td2);
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
|
|
@ -585,24 +635,6 @@ static std::string combine_search_strings (const std::string &s1, const std::str
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t rows_for (const db::Device *device)
|
|
||||||
{
|
|
||||||
if (! device || ! device->device_class ()) {
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
return device->device_class ()->terminal_definitions ().size ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t rows_for (const db::NetTerminalRef *ref)
|
|
||||||
{
|
|
||||||
if (! ref || ! ref->device_class ()) {
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
return ref->device_class ()->terminal_definitions ().size ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static QIcon icon_for_net ()
|
static QIcon icon_for_net ()
|
||||||
{
|
{
|
||||||
static QIcon icon;
|
static QIcon icon;
|
||||||
|
|
@ -1965,12 +1997,14 @@ CircuitNetDeviceTerminalItemData::do_ensure_children (NetlistBrowserModel *model
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t n = std::max (rows_for (m_tp.first), rows_for (m_tp.second));
|
std::pair<const db::Device *, const db::Device *> devices = dp ();
|
||||||
for (size_t i = 0; i < n; ++i) {
|
std::pair<const db::DeviceClass *, const db::DeviceClass *> device_classes = device_classes_from_devices (devices);
|
||||||
std::pair<const db::DeviceClass *, const db::DeviceClass *> device_classes = device_classes_from_devices (dp ());
|
|
||||||
std::pair<const db::DeviceTerminalDefinition *, const db::DeviceTerminalDefinition *> termdefs = terminal_defs_from_device_classes (model->indexer (), device_classes, dp (), i);
|
std::vector<std::pair<const db::DeviceTerminalDefinition *, const db::DeviceTerminalDefinition *> > tp = terminal_defs_from_device_classes (model->indexer (), device_classes, devices);
|
||||||
IndexedNetlistModel::net_pair nets = nets_from_device_terminals (dp (), termdefs);
|
|
||||||
push_back (new CircuitNetDeviceTerminalOthersItemData (this, nets, termdefs));
|
for (std::vector<std::pair<const db::DeviceTerminalDefinition *, const db::DeviceTerminalDefinition *> >::const_iterator i = tp.begin (); i != tp.end (); ++i) {
|
||||||
|
IndexedNetlistModel::net_pair nets = nets_from_device_terminals (dp (), *i);
|
||||||
|
push_back (new CircuitNetDeviceTerminalOthersItemData (this, nets, *i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2320,10 +2354,13 @@ CircuitDeviceItemData::CircuitDeviceItemData (NetlistModelItemData *parent, cons
|
||||||
void
|
void
|
||||||
CircuitDeviceItemData::do_ensure_children (NetlistBrowserModel *model)
|
CircuitDeviceItemData::do_ensure_children (NetlistBrowserModel *model)
|
||||||
{
|
{
|
||||||
size_t n = std::max (rows_for (dp ().first), rows_for (dp ().second));
|
std::pair<const db::Device *, const db::Device *> devices = dp ();
|
||||||
for (size_t i = 0; i < n; ++i) {
|
std::pair<const db::DeviceClass *, const db::DeviceClass *> device_classes = device_classes_from_devices (devices);
|
||||||
std::pair<const db::DeviceTerminalDefinition *, const db::DeviceTerminalDefinition *> tp = terminal_defs_from_device_classes (model->indexer (), device_classes_from_devices (dp ()), dp (), i);
|
|
||||||
push_back (new CircuitDeviceTerminalItemData (this, tp));
|
std::vector<std::pair<const db::DeviceTerminalDefinition *, const db::DeviceTerminalDefinition *> > tp = terminal_defs_from_device_classes (model->indexer (), device_classes, devices);
|
||||||
|
|
||||||
|
for (std::vector<std::pair<const db::DeviceTerminalDefinition *, const db::DeviceTerminalDefinition *> >::const_iterator i = tp.begin (); i != tp.end (); ++i) {
|
||||||
|
push_back (new CircuitDeviceTerminalItemData (this, *i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -330,10 +330,10 @@ TEST (2)
|
||||||
EXPECT_EQ (model->rowCount (inv2Net0TerminalIndex), 4);
|
EXPECT_EQ (model->rowCount (inv2Net0TerminalIndex), 4);
|
||||||
EXPECT_EQ (model->parent (inv2Net0TerminalIndex) == inv2Net0Index, true);
|
EXPECT_EQ (model->parent (inv2Net0TerminalIndex) == inv2Net0Index, true);
|
||||||
// .. whose second terminal is gate
|
// .. whose second terminal is gate
|
||||||
EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, inv2Net0TerminalIndex), Qt::UserRole).toString ()), "G|G|IN|2");
|
EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, inv2Net0TerminalIndex), Qt::UserRole).toString ()), "D|D|VDD|5");
|
||||||
EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, inv2Net0TerminalIndex), Qt::DisplayRole).toString ()), "G");
|
EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, inv2Net0TerminalIndex), Qt::DisplayRole).toString ()), "D");
|
||||||
EXPECT_EQ (tl::to_string (model->data (model->index (1, 2, inv2Net0TerminalIndex), Qt::DisplayRole).toString ()), "IN (3)");
|
EXPECT_EQ (tl::to_string (model->data (model->index (1, 2, inv2Net0TerminalIndex), Qt::DisplayRole).toString ()), "VDD (2)");
|
||||||
EXPECT_EQ (tl::to_string (model->data (model->index (1, 3, inv2Net0TerminalIndex), Qt::DisplayRole).toString ()), "2 (3)");
|
EXPECT_EQ (tl::to_string (model->data (model->index (1, 3, inv2Net0TerminalIndex), Qt::DisplayRole).toString ()), "5 (2)");
|
||||||
|
|
||||||
// The Pin
|
// The Pin
|
||||||
EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, inv2Net0Index), Qt::UserRole).toString ()), "");
|
EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, inv2Net0Index), Qt::UserRole).toString ()), "");
|
||||||
|
|
|
||||||
|
|
@ -297,8 +297,10 @@ module LVS
|
||||||
# Use this method to provide hints for the comparer in cases which are difficult to
|
# Use this method to provide hints for the comparer in cases which are difficult to
|
||||||
# resolve otherwise.
|
# resolve otherwise.
|
||||||
#
|
#
|
||||||
# Before this method can be used, a schematic netlist needs to be loaded with
|
# circuit_a and net_a are for the layout netlist, circuit_b and net_b for the schematic netlist.
|
||||||
# \schematic.
|
# Names are case sensitive for layout-derived netlists and case-insensitive for SPICE schematic netlists.
|
||||||
|
#
|
||||||
|
# Use this method andwhere in the script before the \compare call.
|
||||||
|
|
||||||
def same_nets(*args)
|
def same_nets(*args)
|
||||||
|
|
||||||
|
|
@ -373,12 +375,14 @@ module LVS
|
||||||
# This method will force an equivalence between the two circuits.
|
# This method will force an equivalence between the two circuits.
|
||||||
# By default, circuits are identified by name. If names are different, this
|
# By default, circuits are identified by name. If names are different, this
|
||||||
# method allows establishing an explicit correspondence.
|
# method allows establishing an explicit correspondence.
|
||||||
|
#
|
||||||
|
# circuit_a is for the layout netlist, circuit_b for the schematic netlist.
|
||||||
|
# Names are case sensitive for layout-derived netlists and case-insensitive for SPICE schematic netlists.
|
||||||
#
|
#
|
||||||
# One of the circuits may be nil. In this case, the corresponding
|
# One of the circuits may be nil. In this case, the corresponding
|
||||||
# other circuit is mapped to "nothing", i.e. ignored.
|
# other circuit is mapped to "nothing", i.e. ignored.
|
||||||
#
|
#
|
||||||
# Before this method can be used, a schematic netlist needs to be loaded with
|
# Use this method andwhere in the script before the \compare call.
|
||||||
# \schematic.
|
|
||||||
|
|
||||||
def same_circuits(a, b)
|
def same_circuits(a, b)
|
||||||
|
|
||||||
|
|
@ -413,6 +417,9 @@ module LVS
|
||||||
# Before this method can be used, a schematic netlist needs to be loaded with
|
# Before this method can be used, a schematic netlist needs to be loaded with
|
||||||
# \schematic.
|
# \schematic.
|
||||||
#
|
#
|
||||||
|
# class_a is for the layout netlist, class_b for the schematic netlist.
|
||||||
|
# Names are case sensitive for layout-derived netlists and case-insensitive for SPICE schematic netlists.
|
||||||
|
#
|
||||||
# One of the device classes may be "nil". In this case, the corresponding
|
# One of the device classes may be "nil". In this case, the corresponding
|
||||||
# other device class is mapped to "nothing", i.e. ignored.
|
# other device class is mapped to "nothing", i.e. ignored.
|
||||||
#
|
#
|
||||||
|
|
@ -429,7 +436,11 @@ module LVS
|
||||||
#
|
#
|
||||||
# Once a device class is mentioned with "same_device_classes", matching by
|
# Once a device class is mentioned with "same_device_classes", matching by
|
||||||
# name is disabled for this class. So after using 'same_device_classes("A", "B")'
|
# name is disabled for this class. So after using 'same_device_classes("A", "B")'
|
||||||
# "A" is no longer equivalent to "A" on the other side.
|
# "A" is no longer equivalent to "A" on the other side. If you want "A" to
|
||||||
|
# stay equivalent to "A" too, you need to use 'same_device_classes("A", "A")'
|
||||||
|
# in addition.
|
||||||
|
#
|
||||||
|
# Use this method andwhere in the script before the \compare call.
|
||||||
|
|
||||||
def same_device_classes(a, b)
|
def same_device_classes(a, b)
|
||||||
|
|
||||||
|
|
@ -468,13 +479,15 @@ module LVS
|
||||||
# @/code
|
# @/code
|
||||||
#
|
#
|
||||||
# The circuit argument is either a circuit name (a string) or a Circuit object
|
# The circuit argument is either a circuit name (a string) or a Circuit object
|
||||||
# from the schematic netlist.
|
# from the schematic netlist.
|
||||||
|
#
|
||||||
|
# Names are case sensitive for layout-derived netlists and case-insensitive for SPICE schematic netlists.
|
||||||
#
|
#
|
||||||
# The pin arguments are zero-based pin numbers, where 0 is the first number, 1 the second etc.
|
# The pin arguments are zero-based pin numbers, where 0 is the first number, 1 the second etc.
|
||||||
# If the netlist provides named pins, names can be used instead of numbers.
|
# If the netlist provides named pins, names can be used instead of numbers. Again, use upper
|
||||||
|
# case pin names for SPICE netlists.
|
||||||
#
|
#
|
||||||
# Before this method can be used, a schematic netlist needs to be loaded with
|
# Use this method andwhere in the script before the \compare call.
|
||||||
# \schematic.
|
|
||||||
|
|
||||||
def equivalent_pins(circuit, *pins)
|
def equivalent_pins(circuit, *pins)
|
||||||
|
|
||||||
|
|
@ -603,6 +616,12 @@ module LVS
|
||||||
# pursues this "deduction path" in greater depth while with
|
# pursues this "deduction path" in greater depth while with
|
||||||
# smaller values, the algorithm prefers picking nets in a random fashion
|
# smaller values, the algorithm prefers picking nets in a random fashion
|
||||||
# as the seeds for this deduction path. The default value is 8.
|
# as the seeds for this deduction path. The default value is 8.
|
||||||
|
#
|
||||||
|
# By default, the depth is unlimited, but it may
|
||||||
|
# be reduced in order to limit the compare runtimes at the cost
|
||||||
|
# of a less elaborate compare attempt. The preferred solution
|
||||||
|
# however is to use labels for net name hints which also reduces
|
||||||
|
# the branch complexity.
|
||||||
|
|
||||||
def max_depth(value)
|
def max_depth(value)
|
||||||
v = value.to_i
|
v = value.to_i
|
||||||
|
|
@ -625,6 +644,12 @@ module LVS
|
||||||
# can be increased at the expense of potentially larger runtimes.
|
# can be increased at the expense of potentially larger runtimes.
|
||||||
# The runtime penality is roughly proportional to the branch
|
# The runtime penality is roughly proportional to the branch
|
||||||
# complexity.
|
# complexity.
|
||||||
|
#
|
||||||
|
# By default, the branch complexity is unlimited, but it may
|
||||||
|
# be reduced in order to limit the compare runtimes at the cost
|
||||||
|
# of a less elaborate compare attempt. The preferred solution
|
||||||
|
# however is to use labels for net name hints which also reduces
|
||||||
|
# the depth.
|
||||||
|
|
||||||
def max_branch_complexity(value)
|
def max_branch_complexity(value)
|
||||||
v = value.to_i
|
v = value.to_i
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@
|
||||||
#include "lymMacro.h"
|
#include "lymMacro.h"
|
||||||
#include "tlFileUtils.h"
|
#include "tlFileUtils.h"
|
||||||
|
|
||||||
void run_test (tl::TestBase *_this, const std::string &suffix, const std::string &layout, bool with_l2n = false, const std::string &top = std::string ())
|
void run_test (tl::TestBase *_this, const std::string &suffix, const std::string &layout, bool with_l2n = false, const std::string &top = std::string (), bool change_case = false)
|
||||||
{
|
{
|
||||||
std::string rs = tl::testsrc ();
|
std::string rs = tl::testsrc ();
|
||||||
rs += "/testdata/lvs/" + suffix + ".lvs";
|
rs += "/testdata/lvs/" + suffix + ".lvs";
|
||||||
|
|
@ -58,7 +58,8 @@ void run_test (tl::TestBase *_this, const std::string &suffix, const std::string
|
||||||
"$lvs_test_target_cir = '%s'\n"
|
"$lvs_test_target_cir = '%s'\n"
|
||||||
"$lvs_test_target_l2n = '%s'\n"
|
"$lvs_test_target_l2n = '%s'\n"
|
||||||
"$lvs_test_top = '%s'\n"
|
"$lvs_test_top = '%s'\n"
|
||||||
, src, output_lvsdb, output_cir, output_l2n, top)
|
"$change_case = %s\n"
|
||||||
|
, src, output_lvsdb, output_cir, output_l2n, top, change_case ? "true" : "false")
|
||||||
);
|
);
|
||||||
config.set_interpreter (lym::Macro::Ruby);
|
config.set_interpreter (lym::Macro::Ruby);
|
||||||
EXPECT_EQ (config.run (), 0);
|
EXPECT_EQ (config.run (), 0);
|
||||||
|
|
@ -108,11 +109,15 @@ TEST(5_simple_same_device_classes)
|
||||||
TEST(6_simple_pin_swapping)
|
TEST(6_simple_pin_swapping)
|
||||||
{
|
{
|
||||||
run_test (_this, "ringo_simple_pin_swapping", "ringo.gds");
|
run_test (_this, "ringo_simple_pin_swapping", "ringo.gds");
|
||||||
|
// change case
|
||||||
|
run_test (_this, "ringo_simple_pin_swapping", "ringo.gds", false, std::string (), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(7_net_and_circuit_equivalence)
|
TEST(7_net_and_circuit_equivalence)
|
||||||
{
|
{
|
||||||
run_test (_this, "ringo_simple_net_and_circuit_equivalence", "ringo_renamed.gds");
|
run_test (_this, "ringo_simple_net_and_circuit_equivalence", "ringo_renamed.gds");
|
||||||
|
// change case
|
||||||
|
run_test (_this, "ringo_simple_net_and_circuit_equivalence", "ringo_renamed.gds", false, std::string (), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(8_simplification)
|
TEST(8_simplification)
|
||||||
|
|
@ -143,6 +148,8 @@ TEST(12_simple_dmos)
|
||||||
TEST(13_simple_ringo_device_subcircuits)
|
TEST(13_simple_ringo_device_subcircuits)
|
||||||
{
|
{
|
||||||
run_test (_this, "ringo_device_subcircuits", "ringo.gds");
|
run_test (_this, "ringo_device_subcircuits", "ringo.gds");
|
||||||
|
// change case
|
||||||
|
run_test (_this, "ringo_device_subcircuits", "ringo.gds", false, std::string (), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(14_simple_ringo_mixed_hierarchy)
|
TEST(14_simple_ringo_mixed_hierarchy)
|
||||||
|
|
|
||||||
|
|
@ -154,3 +154,16 @@ TEST(17_private)
|
||||||
test_is_long_runner ();
|
test_is_long_runner ();
|
||||||
run_test (_this, "test_17.lylvs", "test_17.cir.gz", "test_17.gds.gz", true, "test_17.lvsdb");
|
run_test (_this, "test_17.lylvs", "test_17.cir.gz", "test_17.gds.gz", true, "test_17.lvsdb");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(18_private)
|
||||||
|
{
|
||||||
|
// test_is_long_runner ();
|
||||||
|
run_test (_this, "test_18.lvs", "test_18.cir.gz", "test_18.gds.gz", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(19_private)
|
||||||
|
{
|
||||||
|
// test_is_long_runner ();
|
||||||
|
run_test (_this, "test_19.lvs", "test_19.cir.gz", "test_19.gds.gz", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1704,7 +1704,12 @@ NetTracerDialog::trace_all_nets (db::LayoutToNetlist *l2ndb, const lay::CellView
|
||||||
|
|
||||||
tracer_data.configure_l2n (*l2ndb);
|
tracer_data.configure_l2n (*l2ndb);
|
||||||
|
|
||||||
l2ndb->extract_netlist (std::string (), flat /*include floating subcircuits for netlist to flatten*/);
|
l2ndb->clear_join_nets ();
|
||||||
|
l2ndb->clear_join_net_names ();
|
||||||
|
|
||||||
|
// include floating subcircuits for netlist to flatten
|
||||||
|
l2ndb->set_include_floating_subcircuits (flat);
|
||||||
|
l2ndb->extract_netlist ();
|
||||||
|
|
||||||
if (flat) {
|
if (flat) {
|
||||||
l2ndb->netlist ()->flatten ();
|
l2ndb->netlist ()->flatten ();
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,30 @@ public:
|
||||||
*/
|
*/
|
||||||
GlobPattern &operator= (const std::string &s);
|
GlobPattern &operator= (const std::string &s);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Equality
|
||||||
|
*/
|
||||||
|
bool operator== (const tl::GlobPattern &other) const
|
||||||
|
{
|
||||||
|
return m_p == other.m_p;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Less
|
||||||
|
*/
|
||||||
|
bool operator< (const tl::GlobPattern &other) const
|
||||||
|
{
|
||||||
|
return m_p < other.m_p;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Pattern is empty
|
||||||
|
*/
|
||||||
|
bool empty () const
|
||||||
|
{
|
||||||
|
return m_p.empty ();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Sets a value indicating whether to treat the match case sensitive
|
* @brief Sets a value indicating whether to treat the match case sensitive
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -116,7 +116,7 @@ connect_global(bulk, "SUBSTRATE")
|
||||||
connect_global(ptie, "SUBSTRATE")
|
connect_global(ptie, "SUBSTRATE")
|
||||||
|
|
||||||
# Test same_device_classes
|
# Test same_device_classes
|
||||||
same_device_classes("PMOS", "XPMOS")
|
same_device_classes("PMOS", $change_case ? "xpMos" : "XPMOS")
|
||||||
|
|
||||||
# Compare section
|
# Compare section
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ target_netlist($lvs_test_target_cir, write_spice, "Extracted by KLayout")
|
||||||
schematic("ringo.cir")
|
schematic("ringo.cir")
|
||||||
|
|
||||||
# preempt configuration (see below)
|
# preempt configuration (see below)
|
||||||
same_nets("top", "ENABLE", "RINGO", "ENABLE")
|
same_nets("top", "ENABLE", $change_case ? "Ringo" : "RINGO", $change_case ? "enable" : "ENABLE")
|
||||||
|
|
||||||
deep
|
deep
|
||||||
|
|
||||||
|
|
@ -71,8 +71,8 @@ connect_global(ptie, "SUBSTRATE")
|
||||||
|
|
||||||
# Compare section
|
# Compare section
|
||||||
|
|
||||||
same_circuits("top", "RINGO")
|
same_circuits("top", $change_case ? "ringo" : "RINGO")
|
||||||
same_circuits("INV", "INVX1")
|
same_circuits("INV", $change_case ? "invX1" : "INVX1")
|
||||||
same_circuits("DOESNOTEXIST", "DOESNOTEXIST2")
|
same_circuits("DOESNOTEXIST", "DOESNOTEXIST2")
|
||||||
same_nets("DOESNOTEXIST", "ENABLE", "DOESNOTEXIST2", "ENABLE")
|
same_nets("DOESNOTEXIST", "ENABLE", "DOESNOTEXIST2", "ENABLE")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ target_netlist($lvs_test_target_cir, write_spice, "Extracted by KLayout")
|
||||||
schematic("ringo_pin_swapping.cir")
|
schematic("ringo_pin_swapping.cir")
|
||||||
|
|
||||||
# preempt configuration
|
# preempt configuration
|
||||||
equivalent_pins("ND2X1", 4, 5)
|
equivalent_pins($change_case ? "nd2X1" : "ND2X1", 4, 5)
|
||||||
|
|
||||||
deep
|
deep
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -179,12 +179,11 @@ class DBEdgePairs_TestClass < TestBase
|
||||||
assert_equal(r.is_deep?, true)
|
assert_equal(r.is_deep?, true)
|
||||||
|
|
||||||
r.flatten
|
r.flatten
|
||||||
assert_equal(r.has_valid_edge_pairs?, true)
|
assert_equal(r.has_valid_edge_pairs?, false)
|
||||||
assert_equal(r[1].to_s, "(0,101;2,103)/(10,111;12,113)")
|
assert_equal(r.to_s, "(0,1;2,3)/(10,11;12,13);(0,101;2,103)/(10,111;12,113);(200,101;202,103)/(210,111;212,113)")
|
||||||
assert_equal(r[100].inspect, "nil")
|
|
||||||
assert_equal(r.bbox.to_s, "(0,1;212,113)")
|
assert_equal(r.bbox.to_s, "(0,1;212,113)")
|
||||||
|
|
||||||
assert_equal(r.is_deep?, false)
|
assert_equal(r.is_deep?, true)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,7 @@ class DBEdges_TestClass < TestBase
|
||||||
assert_equal(r.count, 4)
|
assert_equal(r.count, 4)
|
||||||
assert_equal(r.hier_count, 4)
|
assert_equal(r.hier_count, 4)
|
||||||
assert_equal(r.bbox.to_s, "(10,20;100,200)")
|
assert_equal(r.bbox.to_s, "(10,20;100,200)")
|
||||||
assert_equal(r.is_merged?, true)
|
assert_equal(r.is_merged?, false)
|
||||||
|
|
||||||
assert_equal(r.moved(RBA::Point::new(10, 20)).bbox.to_s, "(20,40;110,220)")
|
assert_equal(r.moved(RBA::Point::new(10, 20)).bbox.to_s, "(20,40;110,220)")
|
||||||
assert_equal(r.moved(10, 20).bbox.to_s, "(20,40;110,220)")
|
assert_equal(r.moved(10, 20).bbox.to_s, "(20,40;110,220)")
|
||||||
|
|
@ -615,12 +615,11 @@ class DBEdges_TestClass < TestBase
|
||||||
|
|
||||||
r.flatten
|
r.flatten
|
||||||
|
|
||||||
assert_equal(r.is_deep?, false)
|
assert_equal(r.is_deep?, true)
|
||||||
|
|
||||||
assert_equal(r.count, 12)
|
assert_equal(r.count, 12)
|
||||||
assert_equal(r.hier_count, 12)
|
assert_equal(r.hier_count, 12)
|
||||||
assert_equal(r[1].to_s, "(-10,20;10,20)")
|
assert_equal(r.to_s, "(-10,-20;-10,20);(-10,20;10,20);(10,20;10,-20);(10,-20;-10,-20);(-10,80;-10,120);(-10,120;10,120);(10,120;10,80);(10,80;-10,80);(190,80;190,120);(190,120;210,120)...")
|
||||||
assert_equal(r[100].to_s, "")
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||