|
|
@ -50,6 +50,10 @@ SOURCES = \
|
|||
dbManager.cc \
|
||||
dbMatrix.cc \
|
||||
dbMemStatistics.cc \
|
||||
dbMutableEdgePairs.cc \
|
||||
dbMutableEdges.cc \
|
||||
dbMutableRegion.cc \
|
||||
dbMutableTexts.cc \
|
||||
dbObject.cc \
|
||||
dbPath.cc \
|
||||
dbPCellDeclaration.cc \
|
||||
|
|
@ -258,6 +262,10 @@ HEADERS = \
|
|||
dbMatrix.h \
|
||||
dbMemStatistics.h \
|
||||
dbMetaInfo.h \
|
||||
dbMutableEdgePairs.h \
|
||||
dbMutableEdges.h \
|
||||
dbMutableRegion.h \
|
||||
dbMutableTexts.h \
|
||||
dbObject.h \
|
||||
dbObjectTag.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
|
||||
{
|
||||
std::string nn = mp_netlist ? mp_netlist->normalize_name (name) : name;
|
||||
|
||||
for (Circuit::const_pin_iterator p = begin_pins (); p != end_pins (); ++p) {
|
||||
if (p->name () == name) {
|
||||
if (p->name () == nn) {
|
||||
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)
|
||||
{
|
||||
if (! net) {
|
||||
|
|
@ -423,6 +430,11 @@ void Circuit::remove_device (Device *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)
|
||||
{
|
||||
if (! subcircuit) {
|
||||
|
|
@ -456,6 +468,11 @@ void Circuit::remove_subcircuit (SubCircuit *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)
|
||||
{
|
||||
m_refs.push_back (r);
|
||||
|
|
|
|||
|
|
@ -496,10 +496,7 @@ public:
|
|||
*
|
||||
* If the name is not valid, null is returned.
|
||||
*/
|
||||
Net *net_by_name (const std::string &name)
|
||||
{
|
||||
return m_net_by_name.object_by (name);
|
||||
}
|
||||
Net *net_by_name (const std::string &name);
|
||||
|
||||
/**
|
||||
* @brief Adds a device to this circuit
|
||||
|
|
@ -556,10 +553,7 @@ public:
|
|||
*
|
||||
* If the name is not valid, null is returned.
|
||||
*/
|
||||
Device *device_by_name (const std::string &name)
|
||||
{
|
||||
return m_device_by_name.object_by (name);
|
||||
}
|
||||
Device *device_by_name (const std::string &name);
|
||||
|
||||
/**
|
||||
* @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.
|
||||
*/
|
||||
SubCircuit *subcircuit_by_name (const std::string &name)
|
||||
{
|
||||
return m_subcircuit_by_name.object_by (name);
|
||||
}
|
||||
SubCircuit *subcircuit_by_name (const std::string &name);
|
||||
|
||||
/**
|
||||
* @brief Begin iterator for the subcircuits of the circuit (non-const version)
|
||||
|
|
|
|||
|
|
@ -112,31 +112,31 @@ private:
|
|||
|
||||
|
||||
DeepEdgePairs::DeepEdgePairs ()
|
||||
: AsIfFlatEdgePairs ()
|
||||
: MutableEdgePairs ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
DeepEdgePairs::DeepEdgePairs (const RecursiveShapeIterator &si, DeepShapeStore &dss)
|
||||
: AsIfFlatEdgePairs ()
|
||||
: MutableEdgePairs ()
|
||||
{
|
||||
set_deep_layer (dss.create_edge_pair_layer (si));
|
||||
}
|
||||
|
||||
DeepEdgePairs::DeepEdgePairs (const RecursiveShapeIterator &si, DeepShapeStore &dss, const db::ICplxTrans &trans)
|
||||
: AsIfFlatEdgePairs ()
|
||||
: MutableEdgePairs ()
|
||||
{
|
||||
set_deep_layer (dss.create_edge_pair_layer (si, trans));
|
||||
}
|
||||
|
||||
DeepEdgePairs::DeepEdgePairs (const DeepEdgePairs &other)
|
||||
: AsIfFlatEdgePairs (other), db::DeepShapeCollectionDelegateBase (other)
|
||||
: MutableEdgePairs (other), db::DeepShapeCollectionDelegateBase (other)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
DeepEdgePairs::DeepEdgePairs (const DeepLayer &dl)
|
||||
: AsIfFlatEdgePairs ()
|
||||
: MutableEdgePairs ()
|
||||
{
|
||||
set_deep_layer (dl);
|
||||
}
|
||||
|
|
@ -151,6 +151,86 @@ EdgePairsDelegate *DeepEdgePairs::clone () const
|
|||
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
|
||||
{
|
||||
return new DeepEdgePairsIterator (begin_iter ().first);
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
#include "dbCommon.h"
|
||||
|
||||
#include "dbAsIfFlatEdgePairs.h"
|
||||
#include "dbMutableEdgePairs.h"
|
||||
#include "dbDeepShapeStore.h"
|
||||
#include "dbEdgePairs.h"
|
||||
|
||||
|
|
@ -36,7 +36,7 @@ namespace db {
|
|||
* @brief Provides hierarchical edges implementation
|
||||
*/
|
||||
class DB_PUBLIC DeepEdgePairs
|
||||
: public db::AsIfFlatEdgePairs, public db::DeepShapeCollectionDelegateBase
|
||||
: public db::MutableEdgePairs, public db::DeepShapeCollectionDelegateBase
|
||||
{
|
||||
public:
|
||||
DeepEdgePairs ();
|
||||
|
|
@ -50,6 +50,17 @@ public:
|
|||
|
||||
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 std::pair<db::RecursiveShapeIterator, db::ICplxTrans> begin_iter () const;
|
||||
|
||||
|
|
|
|||
|
|
@ -123,14 +123,14 @@ private:
|
|||
// DeepEdges implementation
|
||||
|
||||
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));
|
||||
init ();
|
||||
}
|
||||
|
||||
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));
|
||||
init ();
|
||||
|
|
@ -138,7 +138,7 @@ DeepEdges::DeepEdges (const RecursiveShapeIterator &si, DeepShapeStore &dss, con
|
|||
}
|
||||
|
||||
DeepEdges::DeepEdges (const db::Edges &other, DeepShapeStore &dss)
|
||||
: AsIfFlatEdges (), m_merged_edges ()
|
||||
: MutableEdges (), m_merged_edges ()
|
||||
{
|
||||
set_deep_layer (dss.create_from_flat (other));
|
||||
|
||||
|
|
@ -147,13 +147,13 @@ DeepEdges::DeepEdges (const db::Edges &other, DeepShapeStore &dss)
|
|||
}
|
||||
|
||||
DeepEdges::DeepEdges ()
|
||||
: AsIfFlatEdges ()
|
||||
: MutableEdges ()
|
||||
{
|
||||
init ();
|
||||
}
|
||||
|
||||
DeepEdges::DeepEdges (const DeepLayer &dl)
|
||||
: AsIfFlatEdges ()
|
||||
: MutableEdges ()
|
||||
{
|
||||
set_deep_layer (dl);
|
||||
init ();
|
||||
|
|
@ -165,7 +165,7 @@ DeepEdges::~DeepEdges ()
|
|||
}
|
||||
|
||||
DeepEdges::DeepEdges (const DeepEdges &other)
|
||||
: AsIfFlatEdges (other), DeepShapeCollectionDelegateBase (other),
|
||||
: MutableEdges (other), DeepShapeCollectionDelegateBase (other),
|
||||
m_merged_edges_valid (other.m_merged_edges_valid),
|
||||
m_is_merged (other.m_is_merged)
|
||||
{
|
||||
|
|
@ -211,6 +211,86 @@ void DeepEdges::merged_semantics_changed ()
|
|||
// .. 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 *
|
||||
DeepEdges::begin () const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
#include "dbCommon.h"
|
||||
|
||||
#include "dbAsIfFlatEdges.h"
|
||||
#include "dbMutableEdges.h"
|
||||
#include "dbDeepShapeStore.h"
|
||||
#include "dbEdgeBoolean.h"
|
||||
#include "dbEdgePairs.h"
|
||||
|
|
@ -40,7 +40,7 @@ class DeepRegion;
|
|||
* @brief Provides hierarchical edges implementation
|
||||
*/
|
||||
class DB_PUBLIC DeepEdges
|
||||
: public db::AsIfFlatEdges, public db::DeepShapeCollectionDelegateBase
|
||||
: public db::MutableEdges, public db::DeepShapeCollectionDelegateBase
|
||||
{
|
||||
public:
|
||||
DeepEdges ();
|
||||
|
|
@ -53,6 +53,17 @@ public:
|
|||
|
||||
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;
|
||||
|
||||
virtual EdgesIteratorDelegate *begin () const;
|
||||
|
|
|
|||
|
|
@ -127,14 +127,14 @@ private:
|
|||
// DeepRegion implementation
|
||||
|
||||
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));
|
||||
init ();
|
||||
}
|
||||
|
||||
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));
|
||||
init ();
|
||||
|
|
@ -142,7 +142,7 @@ DeepRegion::DeepRegion (const RecursiveShapeIterator &si, DeepShapeStore &dss, c
|
|||
}
|
||||
|
||||
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));
|
||||
|
||||
|
|
@ -151,13 +151,13 @@ DeepRegion::DeepRegion (const db::Region &other, DeepShapeStore &dss)
|
|||
}
|
||||
|
||||
DeepRegion::DeepRegion ()
|
||||
: AsIfFlatRegion ()
|
||||
: MutableRegion ()
|
||||
{
|
||||
init ();
|
||||
}
|
||||
|
||||
DeepRegion::DeepRegion (const DeepLayer &dl)
|
||||
: AsIfFlatRegion ()
|
||||
: MutableRegion ()
|
||||
{
|
||||
set_deep_layer (dl);
|
||||
init ();
|
||||
|
|
@ -169,7 +169,7 @@ DeepRegion::~DeepRegion ()
|
|||
}
|
||||
|
||||
DeepRegion::DeepRegion (const DeepRegion &other)
|
||||
: AsIfFlatRegion (other), DeepShapeCollectionDelegateBase (other),
|
||||
: MutableRegion (other), DeepShapeCollectionDelegateBase (other),
|
||||
m_merged_polygons_valid (other.m_merged_polygons_valid),
|
||||
m_is_merged (other.m_is_merged)
|
||||
{
|
||||
|
|
@ -220,6 +220,90 @@ void DeepRegion::min_coherence_changed ()
|
|||
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 *
|
||||
DeepRegion::begin () const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
#include "dbCommon.h"
|
||||
|
||||
#include "dbAsIfFlatRegion.h"
|
||||
#include "dbMutableRegion.h"
|
||||
#include "dbDeepShapeStore.h"
|
||||
|
||||
namespace db {
|
||||
|
|
@ -35,7 +35,7 @@ namespace db {
|
|||
* @brief A deep, polygon-set delegate
|
||||
*/
|
||||
class DB_PUBLIC DeepRegion
|
||||
: public AsIfFlatRegion, public DeepShapeCollectionDelegateBase
|
||||
: public MutableRegion, public DeepShapeCollectionDelegateBase
|
||||
{
|
||||
public:
|
||||
typedef db::layer<db::Polygon, db::unstable_layer_tag> polygon_layer_type;
|
||||
|
|
@ -53,6 +53,17 @@ public:
|
|||
|
||||
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_merged () const;
|
||||
|
||||
|
|
|
|||
|
|
@ -399,6 +399,18 @@ DeepShapeStoreState::max_vertex_count () const
|
|||
|
||||
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 ()
|
||||
{
|
||||
++s_instance_count;
|
||||
|
|
@ -433,7 +445,9 @@ DeepLayer DeepShapeStore::create_from_flat (const db::Region ®ion, bool for_n
|
|||
|
||||
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) {
|
||||
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 ();
|
||||
|
||||
unsigned int layer = layout ().insert_layer ();
|
||||
unsigned int layer = init_layer (layout (), edges.iter ());
|
||||
|
||||
db::Shapes *shapes = &initial_cell ().shapes (layer);
|
||||
db::Box world = db::Box::world ();
|
||||
|
|
@ -510,7 +524,7 @@ DeepLayer DeepShapeStore::create_from_flat (const db::Texts &texts, const db::IC
|
|||
|
||||
require_singular ();
|
||||
|
||||
unsigned int layer = layout ().insert_layer ();
|
||||
unsigned int layer = init_layer (layout (), texts.iter ());
|
||||
|
||||
db::Shapes *shapes = &initial_cell ().shapes (layer);
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if (max_area_ratio == 0.0) {
|
||||
|
|
|
|||
|
|
@ -116,31 +116,31 @@ private:
|
|||
};
|
||||
|
||||
DeepTexts::DeepTexts ()
|
||||
: AsIfFlatTexts ()
|
||||
: MutableTexts ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
DeepTexts::DeepTexts (const db::Texts &other, DeepShapeStore &dss)
|
||||
: AsIfFlatTexts ()
|
||||
: MutableTexts ()
|
||||
{
|
||||
set_deep_layer (dss.create_from_flat (other));
|
||||
}
|
||||
|
||||
DeepTexts::DeepTexts (const RecursiveShapeIterator &si, DeepShapeStore &dss)
|
||||
: AsIfFlatTexts ()
|
||||
: MutableTexts ()
|
||||
{
|
||||
set_deep_layer (dss.create_text_layer (si));
|
||||
}
|
||||
|
||||
DeepTexts::DeepTexts (const RecursiveShapeIterator &si, DeepShapeStore &dss, const db::ICplxTrans &trans)
|
||||
: AsIfFlatTexts ()
|
||||
: MutableTexts ()
|
||||
{
|
||||
set_deep_layer (dss.create_text_layer (si, trans));
|
||||
}
|
||||
|
||||
DeepTexts::DeepTexts (const DeepTexts &other)
|
||||
: AsIfFlatTexts (other), DeepShapeCollectionDelegateBase (other)
|
||||
: MutableTexts (other), DeepShapeCollectionDelegateBase (other)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
@ -156,7 +156,7 @@ DeepTexts::operator= (const DeepTexts &other)
|
|||
}
|
||||
|
||||
DeepTexts::DeepTexts (const DeepLayer &dl)
|
||||
: AsIfFlatTexts ()
|
||||
: MutableTexts ()
|
||||
{
|
||||
set_deep_layer (dl);
|
||||
}
|
||||
|
|
@ -171,6 +171,90 @@ TextsDelegate *DeepTexts::clone () const
|
|||
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
|
||||
{
|
||||
return new DeepTextsIterator (begin_iter ().first);
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
#include "dbCommon.h"
|
||||
|
||||
#include "dbAsIfFlatTexts.h"
|
||||
#include "dbMutableTexts.h"
|
||||
#include "dbDeepShapeStore.h"
|
||||
#include "dbTexts.h"
|
||||
|
||||
|
|
@ -36,7 +36,7 @@ namespace db {
|
|||
* @brief Provides hierarchical edges implementation
|
||||
*/
|
||||
class DB_PUBLIC DeepTexts
|
||||
: public db::AsIfFlatTexts, public db::DeepShapeCollectionDelegateBase
|
||||
: public db::MutableTexts, public db::DeepShapeCollectionDelegateBase
|
||||
{
|
||||
public:
|
||||
DeepTexts ();
|
||||
|
|
@ -51,6 +51,17 @@ public:
|
|||
|
||||
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 std::pair<db::RecursiveShapeIterator, db::ICplxTrans> begin_iter () const;
|
||||
|
||||
|
|
|
|||
|
|
@ -93,20 +93,20 @@ EdgePairs::EdgePairs (const RecursiveShapeIterator &si, DeepShapeStore &dss, con
|
|||
template <class Sh>
|
||||
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 &);
|
||||
|
||||
void EdgePairs::insert (const db::Shape &shape)
|
||||
{
|
||||
flat_edge_pairs ()->insert (shape);
|
||||
mutable_edge_pairs ()->insert (shape);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
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 &);
|
||||
|
|
@ -120,13 +120,18 @@ void EdgePairs::clear ()
|
|||
|
||||
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>
|
||||
EdgePairs &EdgePairs::transform (const T &trans)
|
||||
{
|
||||
flat_edge_pairs ()->transform (trans);
|
||||
mutable_edge_pairs ()->transform (trans);
|
||||
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) {
|
||||
edge_pairs = new FlatEdgePairs ();
|
||||
if (mp_delegate) {
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ namespace db
|
|||
{
|
||||
|
||||
class EdgePairFilterBase;
|
||||
class FlatEdgePairs;
|
||||
class MutableEdgePairs;
|
||||
class EmptyEdgePairs;
|
||||
class Edges;
|
||||
class Region;
|
||||
|
|
@ -469,10 +469,7 @@ public:
|
|||
*
|
||||
* This method will turn any edge pair collection into a flat one.
|
||||
*/
|
||||
void flatten ()
|
||||
{
|
||||
flat_edge_pairs ();
|
||||
}
|
||||
void flatten ();
|
||||
|
||||
/**
|
||||
* @brief Returns true, if the edge pair set has valid edges stored within itself
|
||||
|
|
@ -615,7 +612,7 @@ private:
|
|||
EdgePairsDelegate *mp_delegate;
|
||||
|
||||
void set_delegate (EdgePairsDelegate *delegate);
|
||||
FlatEdgePairs *flat_edge_pairs ();
|
||||
MutableEdgePairs *mutable_edge_pairs ();
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
#include "dbDeepEdges.h"
|
||||
#include "dbOriginalLayerEdges.h"
|
||||
#include "dbEmptyEdges.h"
|
||||
#include "dbMutableEdges.h"
|
||||
#include "dbFlatEdges.h"
|
||||
#include "dbEdgesUtils.h"
|
||||
#include "dbRegion.h"
|
||||
|
|
@ -133,7 +134,7 @@ Edges::clear ()
|
|||
void
|
||||
Edges::reserve (size_t n)
|
||||
{
|
||||
flat_edges ()->reserve (n);
|
||||
mutable_edges ()->reserve (n);
|
||||
}
|
||||
|
||||
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)));
|
||||
}
|
||||
|
||||
void
|
||||
Edges::flatten ()
|
||||
{
|
||||
mutable_edges ()->flatten ();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
Edges &Edges::transform (const T &trans)
|
||||
{
|
||||
flat_edges ()->transform (trans);
|
||||
mutable_edges ()->transform (trans);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
|
@ -183,7 +190,7 @@ template DB_PUBLIC Edges &Edges::transform (const db::IMatrix3d &);
|
|||
template <class Sh>
|
||||
void Edges::insert (const Sh &shape)
|
||||
{
|
||||
flat_edges ()->insert (shape);
|
||||
mutable_edges ()->insert (shape);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
flat_edges ()->insert (shape);
|
||||
mutable_edges ()->insert (shape);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
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::Trans &);
|
||||
template DB_PUBLIC void Edges::insert (const db::Shape &, const db::Disp &);
|
||||
|
||||
FlatEdges *
|
||||
Edges::flat_edges ()
|
||||
MutableEdges *
|
||||
Edges::mutable_edges ()
|
||||
{
|
||||
FlatEdges *edges = dynamic_cast<FlatEdges *> (mp_delegate);
|
||||
MutableEdges *edges = dynamic_cast<MutableEdges *> (mp_delegate);
|
||||
if (! edges) {
|
||||
|
||||
edges = new FlatEdges ();
|
||||
if (mp_delegate) {
|
||||
edges->EdgesDelegate::operator= (*mp_delegate);
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@
|
|||
namespace db {
|
||||
|
||||
class EdgeFilterBase;
|
||||
class FlatEdges;
|
||||
class MutableEdges;
|
||||
class EmptyEdges;
|
||||
class DeepShapeStore;
|
||||
|
||||
|
|
@ -1112,10 +1112,7 @@ public:
|
|||
*
|
||||
* This method will turn any edge collection into a flat one.
|
||||
*/
|
||||
void flatten ()
|
||||
{
|
||||
flat_edges ();
|
||||
}
|
||||
void flatten ();
|
||||
|
||||
/**
|
||||
* @brief Returns true, if the edge set has valid edges stored within itself
|
||||
|
|
@ -1208,7 +1205,7 @@ private:
|
|||
EdgesDelegate *mp_delegate;
|
||||
|
||||
void set_delegate (EdgesDelegate *delegate, bool keep_attributes = true);
|
||||
FlatEdges *flat_edges ();
|
||||
MutableEdges *mutable_edges();
|
||||
};
|
||||
|
||||
} // namespace db
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ namespace db
|
|||
// FlatEdgePairs implementation
|
||||
|
||||
FlatEdgePairs::FlatEdgePairs ()
|
||||
: AsIfFlatEdgePairs (), mp_edge_pairs (new db::Shapes (false))
|
||||
: MutableEdgePairs (), mp_edge_pairs (new db::Shapes (false))
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
@ -43,13 +43,13 @@ FlatEdgePairs::~FlatEdgePairs ()
|
|||
}
|
||||
|
||||
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 ..
|
||||
}
|
||||
|
||||
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 ..
|
||||
}
|
||||
|
|
@ -205,23 +205,11 @@ FlatEdgePairs::insert_into (Layout *layout, db::cell_index_type into_cell, unsig
|
|||
}
|
||||
|
||||
void
|
||||
FlatEdgePairs::insert (const db::EdgePair &ep)
|
||||
FlatEdgePairs::do_insert (const db::EdgePair &ep)
|
||||
{
|
||||
mp_edge_pairs->insert (ep);
|
||||
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 "dbAsIfFlatEdgePairs.h"
|
||||
#include "dbMutableEdgePairs.h"
|
||||
#include "dbShapes.h"
|
||||
#include "dbGenericShapeIterator.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
|
||||
*/
|
||||
class DB_PUBLIC FlatEdgePairs
|
||||
: public AsIfFlatEdgePairs
|
||||
: public MutableEdgePairs
|
||||
{
|
||||
public:
|
||||
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_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);
|
||||
void insert (const db::Shape &shape);
|
||||
virtual void do_insert (const db::EdgePair &edge_pair);
|
||||
|
||||
template <class T>
|
||||
void insert (const db::Shape &shape, const T &trans)
|
||||
virtual void do_transform (const db::Trans &t)
|
||||
{
|
||||
if (shape.is_edge_pair ()) {
|
||||
|
||||
db::EdgePair ep;
|
||||
shape.edge_pair (ep);
|
||||
ep.transform (trans);
|
||||
insert (ep);
|
||||
|
||||
}
|
||||
transform_generic (t);
|
||||
}
|
||||
|
||||
template <class Iter>
|
||||
void insert_seq (const Iter &seq)
|
||||
virtual void do_transform (const db::ICplxTrans &t)
|
||||
{
|
||||
for (Iter i = seq; ! i.at_end (); ++i) {
|
||||
insert (*i);
|
||||
}
|
||||
transform_generic (t);
|
||||
}
|
||||
|
||||
template <class Trans>
|
||||
void transform (const Trans &trans)
|
||||
virtual void do_transform (const db::IMatrix2d &t)
|
||||
{
|
||||
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 ();
|
||||
}
|
||||
transform_generic (t);
|
||||
}
|
||||
|
||||
virtual void do_transform (const db::IMatrix3d &t)
|
||||
{
|
||||
transform_generic (t);
|
||||
}
|
||||
|
||||
virtual void flatten () { }
|
||||
|
||||
db::Shapes &raw_edge_pairs () { 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);
|
||||
|
||||
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::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 ();
|
||||
}
|
||||
|
|
@ -44,7 +44,7 @@ FlatEdges::~FlatEdges ()
|
|||
}
|
||||
|
||||
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 ();
|
||||
|
||||
|
|
@ -53,7 +53,7 @@ FlatEdges::FlatEdges (const FlatEdges &other)
|
|||
}
|
||||
|
||||
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 ();
|
||||
|
||||
|
|
@ -61,7 +61,7 @@ FlatEdges::FlatEdges (const db::Shapes &edges, 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 ();
|
||||
|
||||
|
|
@ -320,69 +320,7 @@ const db::RecursiveShapeIterator *FlatEdges::iter () const
|
|||
}
|
||||
|
||||
void
|
||||
FlatEdges::insert (const db::Box &box)
|
||||
{
|
||||
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)
|
||||
FlatEdges::do_insert (const db::Edge &edge)
|
||||
{
|
||||
if (! empty ()) {
|
||||
m_is_merged = false;
|
||||
|
|
@ -392,23 +330,5 @@ FlatEdges::insert (const db::Edge &edge)
|
|||
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 "dbAsIfFlatEdges.h"
|
||||
#include "dbMutableEdges.h"
|
||||
#include "dbShapes.h"
|
||||
#include "dbShapes2.h"
|
||||
#include "dbGenericShapeIterator.h"
|
||||
|
|
@ -43,7 +43,7 @@ typedef generic_shapes_iterator_delegate<db::Edge> FlatEdgesIterator;
|
|||
* @brief A flat, edge-set delegate
|
||||
*/
|
||||
class DB_PUBLIC FlatEdges
|
||||
: public AsIfFlatEdges
|
||||
: public MutableEdges
|
||||
{
|
||||
public:
|
||||
typedef db::Edge value_type;
|
||||
|
|
@ -65,6 +65,7 @@ public:
|
|||
}
|
||||
|
||||
void reserve (size_t);
|
||||
void flatten () { }
|
||||
|
||||
virtual EdgesIteratorDelegate *begin () const;
|
||||
virtual EdgesIteratorDelegate *begin_merged () const;
|
||||
|
|
@ -91,60 +92,26 @@ public:
|
|||
|
||||
virtual const db::RecursiveShapeIterator *iter () const;
|
||||
|
||||
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::Edge &edge);
|
||||
void insert (const db::Shape &shape);
|
||||
void do_insert (const db::Edge &edge);
|
||||
|
||||
template <class T>
|
||||
void insert (const db::Shape &shape, const T &trans)
|
||||
void do_transform (const db::Trans &t)
|
||||
{
|
||||
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);
|
||||
|
||||
}
|
||||
transform_generic (t);
|
||||
}
|
||||
|
||||
template <class Iter>
|
||||
void insert (const Iter &b, const Iter &e)
|
||||
void do_transform (const db::ICplxTrans &t)
|
||||
{
|
||||
reserve (count () + (e - b));
|
||||
for (Iter i = b; i != e; ++i) {
|
||||
insert (*i);
|
||||
}
|
||||
transform_generic (t);
|
||||
}
|
||||
|
||||
template <class Iter>
|
||||
void insert_seq (const Iter &seq)
|
||||
void do_transform (const db::IMatrix2d &t)
|
||||
{
|
||||
for (Iter i = seq; ! i.at_end (); ++i) {
|
||||
insert (*i);
|
||||
}
|
||||
transform_generic (t);
|
||||
}
|
||||
|
||||
template <class Trans>
|
||||
void transform (const Trans &trans)
|
||||
void do_transform (const db::IMatrix3d &t)
|
||||
{
|
||||
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 ();
|
||||
}
|
||||
transform_generic (t);
|
||||
}
|
||||
|
||||
db::Shapes &raw_edges () { return *mp_edges; }
|
||||
|
|
@ -168,6 +135,18 @@ private:
|
|||
|
||||
void init ();
|
||||
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::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 ();
|
||||
}
|
||||
|
|
@ -44,7 +44,7 @@ FlatRegion::~FlatRegion ()
|
|||
}
|
||||
|
||||
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 ();
|
||||
|
||||
|
|
@ -53,7 +53,7 @@ FlatRegion::FlatRegion (const FlatRegion &other)
|
|||
}
|
||||
|
||||
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 ();
|
||||
|
||||
|
|
@ -61,7 +61,7 @@ FlatRegion::FlatRegion (const db::Shapes &polygons, 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 ();
|
||||
|
||||
|
|
@ -410,68 +410,17 @@ void FlatRegion::insert_into (Layout *layout, db::cell_index_type into_cell, uns
|
|||
}
|
||||
|
||||
void
|
||||
FlatRegion::insert (const db::Box &box)
|
||||
{
|
||||
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)
|
||||
FlatRegion::do_insert (const db::Polygon &polygon)
|
||||
{
|
||||
if (polygon.holes () > 0 || polygon.vertices () > 0) {
|
||||
|
||||
bool is_box = (empty () && polygon.is_box ());
|
||||
|
||||
mp_polygons->insert (polygon);
|
||||
m_is_merged = false;
|
||||
invalidate_cache ();
|
||||
}
|
||||
}
|
||||
set_is_merged (is_box);
|
||||
|
||||
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 ();
|
||||
}
|
||||
}
|
||||
|
||||
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 "dbAsIfFlatRegion.h"
|
||||
#include "dbMutableRegion.h"
|
||||
#include "dbShapes.h"
|
||||
#include "dbShapes2.h"
|
||||
#include "tlCopyOnWrite.h"
|
||||
|
|
@ -42,7 +42,7 @@ typedef generic_shapes_iterator_delegate<db::Polygon> FlatRegionIterator;
|
|||
* @brief A flat, polygon-set delegate
|
||||
*/
|
||||
class DB_PUBLIC FlatRegion
|
||||
: public AsIfFlatRegion
|
||||
: public MutableRegion
|
||||
{
|
||||
public:
|
||||
typedef db::Polygon value_type;
|
||||
|
|
@ -62,7 +62,7 @@ public:
|
|||
return new FlatRegion (*this);
|
||||
}
|
||||
|
||||
void reserve (size_t);
|
||||
virtual void reserve (size_t);
|
||||
|
||||
virtual RegionIteratorDelegate *begin () const;
|
||||
virtual RegionIteratorDelegate *begin_merged () const;
|
||||
|
|
@ -97,52 +97,30 @@ public:
|
|||
|
||||
virtual const db::RecursiveShapeIterator *iter () const;
|
||||
|
||||
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);
|
||||
void do_insert (const db::Polygon &polygon);
|
||||
|
||||
template <class T>
|
||||
void insert (const db::Shape &shape, const T &trans)
|
||||
void do_transform (const db::Trans &t)
|
||||
{
|
||||
if (shape.is_polygon () || shape.is_path () || shape.is_box ()) {
|
||||
db::Polygon poly;
|
||||
shape.polygon (poly);
|
||||
poly.transform (trans);
|
||||
insert (poly);
|
||||
}
|
||||
transform_generic (t);
|
||||
}
|
||||
|
||||
template <class Iter>
|
||||
void insert (const Iter &b, const Iter &e)
|
||||
void do_transform (const db::ICplxTrans &t)
|
||||
{
|
||||
reserve (count () + (e - b));
|
||||
for (Iter i = b; i != e; ++i) {
|
||||
insert (*i);
|
||||
}
|
||||
transform_generic (t);
|
||||
}
|
||||
|
||||
template <class Iter>
|
||||
void insert_seq (const Iter &seq)
|
||||
virtual void do_transform (const db::IMatrix2d &t)
|
||||
{
|
||||
for (Iter i = seq; ! i.at_end (); ++i) {
|
||||
insert (*i);
|
||||
}
|
||||
transform_generic (t);
|
||||
}
|
||||
|
||||
template <class Trans>
|
||||
void transform (const Trans &trans)
|
||||
virtual void do_transform (const db::IMatrix3d &t)
|
||||
{
|
||||
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 ();
|
||||
}
|
||||
transform_generic (t);
|
||||
}
|
||||
|
||||
void flatten () { }
|
||||
|
||||
db::Shapes &raw_polygons () { return *mp_polygons; }
|
||||
const db::Shapes &raw_polygons () const { return *mp_polygons; }
|
||||
|
||||
|
|
@ -166,6 +144,18 @@ private:
|
|||
|
||||
void init ();
|
||||
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::FlatTexts ()
|
||||
: AsIfFlatTexts (), mp_texts (new db::Shapes (false))
|
||||
: MutableTexts (), mp_texts (new db::Shapes (false))
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
@ -43,13 +43,13 @@ FlatTexts::~FlatTexts ()
|
|||
}
|
||||
|
||||
FlatTexts::FlatTexts (const FlatTexts &other)
|
||||
: AsIfFlatTexts (other), mp_texts (other.mp_texts)
|
||||
: MutableTexts (other), mp_texts (other.mp_texts)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
FlatTexts::FlatTexts (const db::Shapes &texts)
|
||||
: AsIfFlatTexts (), mp_texts (new db::Shapes (texts))
|
||||
: MutableTexts (), mp_texts (new db::Shapes (texts))
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
@ -207,23 +207,11 @@ FlatTexts::insert_into (Layout *layout, db::cell_index_type into_cell, unsigned
|
|||
}
|
||||
|
||||
void
|
||||
FlatTexts::insert (const db::Text &t)
|
||||
FlatTexts::do_insert (const db::Text &t)
|
||||
{
|
||||
mp_texts->insert (t);
|
||||
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 "dbAsIfFlatTexts.h"
|
||||
#include "dbMutableTexts.h"
|
||||
#include "dbShapes.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
|
||||
*/
|
||||
class DB_PUBLIC FlatTexts
|
||||
: public AsIfFlatTexts
|
||||
: public MutableTexts
|
||||
{
|
||||
public:
|
||||
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_as_polygons (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer, db::Coord enl) const;
|
||||
|
||||
void insert (const db::Text &text);
|
||||
void insert (const db::Shape &shape);
|
||||
virtual void flatten () { }
|
||||
|
||||
template <class T>
|
||||
void insert (const db::Shape &shape, const T &trans)
|
||||
void do_insert (const db::Text &text);
|
||||
|
||||
virtual void do_transform (const db::Trans &t)
|
||||
{
|
||||
if (shape.is_edge_pair ()) {
|
||||
|
||||
db::Text t;
|
||||
shape.text (t);
|
||||
t.transform (trans);
|
||||
insert (t);
|
||||
|
||||
}
|
||||
transform_generic (t);
|
||||
}
|
||||
|
||||
template <class Iter>
|
||||
void insert_seq (const Iter &seq)
|
||||
virtual void do_transform (const db::ICplxTrans &t)
|
||||
{
|
||||
for (Iter i = seq; ! i.at_end (); ++i) {
|
||||
insert (*i);
|
||||
}
|
||||
transform_generic (t);
|
||||
}
|
||||
|
||||
template <class Trans>
|
||||
void transform (const Trans &trans)
|
||||
virtual void do_transform (const db::IMatrix2d &t)
|
||||
{
|
||||
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 ();
|
||||
}
|
||||
transform_generic (t);
|
||||
}
|
||||
|
||||
virtual void do_transform (const db::IMatrix3d &t)
|
||||
{
|
||||
transform_generic (t);
|
||||
}
|
||||
|
||||
db::Shapes &raw_texts () { return *mp_texts; }
|
||||
|
|
@ -132,6 +120,18 @@ private:
|
|||
FlatTexts &operator= (const FlatTexts &other);
|
||||
|
||||
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 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
|
||||
* 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
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ namespace db
|
|||
// the iterator provides the hierarchical selection (enabling/disabling cells etc.)
|
||||
|
||||
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
|
||||
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)
|
||||
: 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)) {
|
||||
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)
|
||||
: 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_dss.reset (mp_internal_dss.get ());
|
||||
|
|
@ -79,7 +79,7 @@ LayoutToNetlist::LayoutToNetlist (const std::string &topcell_name, double dbu)
|
|||
|
||||
LayoutToNetlist::LayoutToNetlist ()
|
||||
: m_iter (), mp_internal_dss (new db::DeepShapeStore ()), mp_dss (mp_internal_dss.get ()), m_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 ();
|
||||
}
|
||||
|
|
@ -310,37 +310,91 @@ size_t LayoutToNetlist::global_net_id (const std::string &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) {
|
||||
throw tl::Exception (tl::to_string (tr ("The netlist has already been extracted")));
|
||||
}
|
||||
ensure_netlist ();
|
||||
|
||||
const db::Layout &layout = dss ().layout (m_layout_index);
|
||||
|
||||
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);
|
||||
for (std::map<std::string, std::string>::const_iterator j = joined_net_names_per_cell.begin (); j != joined_net_names_per_cell.end (); ++j) {
|
||||
tl::GlobPattern pat (j->first);
|
||||
if (pat.is_const ()) {
|
||||
netex.set_joined_net_names (j->first, j->second);
|
||||
std::map<std::string, std::list<tl::GlobPattern> > jp_per_cell;
|
||||
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) {
|
||||
if (j->first.is_const ()) {
|
||||
jp_per_cell [j->first.pattern ()].push_back (j->second);
|
||||
} else {
|
||||
for (db::Layout::const_iterator c = layout.begin (); c != layout.end (); ++c) {
|
||||
if (pat.match (layout.cell_name (c->cell_index ()))) {
|
||||
netex.set_joined_net_names (layout.cell_name (c->cell_index ()), j->second);
|
||||
if (j->first.match (layout.cell_name (c->cell_index ()))) {
|
||||
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);
|
||||
|
||||
m_netlist_extracted = true;
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include "dbCellMapping.h"
|
||||
#include "dbNetlistExtractor.h"
|
||||
#include "dbNetlistDeviceExtractor.h"
|
||||
#include "tlGlobPattern.h"
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
|
@ -423,20 +424,106 @@ public:
|
|||
size_t global_net_id (const std::string &name);
|
||||
|
||||
/**
|
||||
* @brief Runs the netlist extraction
|
||||
* See the class description for more details.
|
||||
* @brief Sets a flag indicating whether to include floating subcircuits
|
||||
*/
|
||||
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
|
||||
* In addition to the previous version, this extraction method allows specification of a per-cell list of
|
||||
* 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.
|
||||
* See the class description for more details.
|
||||
*/
|
||||
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
|
||||
|
|
@ -830,6 +917,11 @@ private:
|
|||
double m_device_scaling;
|
||||
db::DeepLayer m_dummy_layer;
|
||||
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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ matrix_2d<C>::to_string () const
|
|||
|
||||
template <class C>
|
||||
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 s2 = sqrt (m_m12 * m_m12 + m_m22 * m_m22);
|
||||
|
|
@ -65,7 +65,7 @@ template <class C>
|
|||
double
|
||||
matrix_2d<C>::angle () const
|
||||
{
|
||||
std::pair <double, double> m = mag ();
|
||||
std::pair <double, double> m = mag2 ();
|
||||
double u1 = m.first;
|
||||
double u2 = is_mirror () ? -m.second : m.second;
|
||||
double n11 = m_m11 / u1;
|
||||
|
|
@ -98,7 +98,7 @@ template <class C>
|
|||
bool
|
||||
matrix_2d<C>::has_shear () const
|
||||
{
|
||||
std::pair <double, double> m = mag ();
|
||||
std::pair <double, double> m = mag2 ();
|
||||
double u1 = m.first;
|
||||
double u2 = is_mirror () ? -m.second : m.second;
|
||||
double n11 = m_m11 / u1;
|
||||
|
|
@ -114,7 +114,7 @@ template <class C>
|
|||
double
|
||||
matrix_2d<C>::shear_angle () const
|
||||
{
|
||||
std::pair <double, double> m = mag ();
|
||||
std::pair <double, double> m = mag2 ();
|
||||
double u1 = m.first;
|
||||
double u2 = is_mirror () ? -m.second : m.second;
|
||||
double n11 = m_m11 / u1;
|
||||
|
|
|
|||
|
|
@ -309,7 +309,15 @@ public:
|
|||
* 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.
|
||||
*/
|
||||
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
|
||||
|
|
@ -320,7 +328,7 @@ public:
|
|||
*/
|
||||
double mag_x () const
|
||||
{
|
||||
return mag ().first;
|
||||
return mag2 ().first;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -332,7 +340,7 @@ public:
|
|||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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
|
||||
*
|
||||
|
|
@ -759,9 +783,25 @@ public:
|
|||
* 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.
|
||||
*/
|
||||
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
|
||||
{
|
||||
return mag ().first;
|
||||
return mag2 ().first;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -777,7 +817,7 @@ public:
|
|||
*/
|
||||
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 ();
|
||||
}
|
||||
|
||||
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 ()
|
||||
{
|
||||
m_name.clear ();
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ class Circuit;
|
|||
class DeviceTerminalDefinition;
|
||||
class DeviceClass;
|
||||
class Pin;
|
||||
class Netlist;
|
||||
|
||||
/**
|
||||
* @brief A reference to a terminal of a device
|
||||
|
|
@ -418,6 +419,18 @@ public:
|
|||
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
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ namespace db
|
|||
// Netlist class implementation
|
||||
|
||||
Netlist::Netlist (NetlistManipulationCallbacks *callbacks)
|
||||
: mp_callbacks (callbacks),
|
||||
: m_case_sensitive (true), mp_callbacks (callbacks),
|
||||
m_valid_topology (false), m_lock_count (0),
|
||||
m_circuit_by_name (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)
|
||||
: 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_cell_index (this, &Netlist::begin_circuits, &Netlist::end_circuits),
|
||||
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 ();
|
||||
|
||||
set_case_sensitive (other.is_case_sensitive ());
|
||||
|
||||
std::map<const DeviceClass *, DeviceClass *> dct;
|
||||
for (const_device_class_iterator dc = other.begin_device_classes (); dc != other.end_device_classes (); ++dc) {
|
||||
DeviceClass *dc_new = dc->clone ();
|
||||
|
|
@ -100,6 +103,34 @@ Netlist &Netlist::operator= (const Netlist &other)
|
|||
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 ()
|
||||
{
|
||||
m_circuit_by_cell_index.invalidate ();
|
||||
|
|
@ -472,8 +503,10 @@ void Netlist::flatten ()
|
|||
|
||||
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) {
|
||||
if (d->name () == name) {
|
||||
if (d->name () == nn) {
|
||||
return d.operator-> ();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -102,6 +102,19 @@ public:
|
|||
*/
|
||||
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
|
||||
*
|
||||
|
|
@ -225,7 +238,7 @@ public:
|
|||
*/
|
||||
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
|
||||
{
|
||||
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)
|
||||
{
|
||||
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
|
||||
{
|
||||
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 ();
|
||||
|
||||
/**
|
||||
* @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:
|
||||
friend class Circuit;
|
||||
friend class DeviceAbstract;
|
||||
|
||||
bool m_case_sensitive;
|
||||
tl::weak_ptr<db::NetlistManipulationCallbacks> mp_callbacks;
|
||||
circuit_list m_circuits;
|
||||
device_class_list m_device_classes;
|
||||
|
|
|
|||
|
|
@ -48,15 +48,12 @@ struct GlobalCompareOptions
|
|||
debug_netcompare = tl::app_flag ("netlist-compare-debug-netcompare");
|
||||
// $KLAYOUT_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;
|
||||
}
|
||||
}
|
||||
|
||||
bool debug_netcompare;
|
||||
bool debug_netgraph;
|
||||
bool compare_case_sensitive;
|
||||
|
||||
private:
|
||||
bool m_is_initialized;
|
||||
|
|
@ -90,29 +87,19 @@ namespace db
|
|||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// 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?
|
||||
if (options ()->compare_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
|
||||
}
|
||||
bool csa = a ? a->is_case_sensitive () : true;
|
||||
bool csb = b ? b->is_case_sensitive () : true;
|
||||
return csa && csb;
|
||||
}
|
||||
|
||||
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 n;
|
||||
} else {
|
||||
return tl::to_upper_case (n);
|
||||
}
|
||||
return db::Netlist::name_compare (combined_case_sensitive (a->netlist (), b->netlist ()), a->name (), b->name ());
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// DeviceCompare definition and implementation
|
||||
|
||||
|
|
@ -404,11 +391,16 @@ class generic_categorizer
|
|||
{
|
||||
public:
|
||||
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 ..
|
||||
}
|
||||
|
||||
void set_case_sensitive (bool f)
|
||||
{
|
||||
m_case_sensitive = f;
|
||||
}
|
||||
|
||||
void same (const Obj *ca, const Obj *cb)
|
||||
{
|
||||
if (! ca && ! cb) {
|
||||
|
|
@ -471,7 +463,7 @@ public:
|
|||
|
||||
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);
|
||||
if (c != m_cat_by_name.end ()) {
|
||||
|
|
@ -498,6 +490,7 @@ public:
|
|||
std::map<std::string, size_t> m_cat_by_name;
|
||||
size_t m_next_cat;
|
||||
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 ();
|
||||
}
|
||||
|
||||
void set_case_sensitive (bool f)
|
||||
{
|
||||
generic_categorizer::set_case_sensitive (f);
|
||||
}
|
||||
|
||||
private:
|
||||
std::set<size_t> m_strict_device_categories;
|
||||
};
|
||||
|
|
@ -606,6 +604,11 @@ public:
|
|||
{
|
||||
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 &pnb = b->begin_pins ()->pin ()->name ();
|
||||
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;
|
||||
|
|
@ -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 &pnb = b->begin_pins ()->pin ()->name ();
|
||||
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;
|
||||
|
|
@ -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
|
||||
|
||||
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
|
||||
{
|
||||
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 ()) {
|
||||
return false;
|
||||
} 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 ()) {
|
||||
return false;
|
||||
} 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)
|
||||
TentativeNodeMapping tn2unknown;
|
||||
TentativeNodeMapping tn_temp;
|
||||
|
||||
// collect and mark the ambiguity combinations to consider
|
||||
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 ()) {
|
||||
iters1.push_back (i1);
|
||||
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 ()) {
|
||||
iters2.push_back (i2);
|
||||
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 ()) {
|
||||
|
||||
// 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);
|
||||
|
||||
}
|
||||
|
||||
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) + " ";
|
||||
}
|
||||
|
||||
if (depth > data->max_depth) {
|
||||
if (data->max_depth != std::numeric_limits<size_t>::max() && depth > data->max_depth) {
|
||||
if (options ()->debug_netcompare) {
|
||||
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;
|
||||
|
||||
} 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) {
|
||||
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_res_threshold = -1.0; // not set
|
||||
|
||||
m_max_depth = 50;
|
||||
m_max_n_branch = 500;
|
||||
// NOTE: as the backtracking algorithm is recursive, we need to limit the number of steps to follow
|
||||
// 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_dont_consider_net_names = false;
|
||||
m_case_sensitive = false;
|
||||
}
|
||||
|
||||
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.
|
||||
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;
|
||||
|
||||
|
|
@ -2928,11 +2954,16 @@ NetlistComparer::unmatched_circuits (db::Netlist *a, db::Netlist *b, std::vector
|
|||
bool
|
||||
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.
|
||||
db::CircuitCategorizer circuit_categorizer = *mp_circuit_categorizer;
|
||||
db::DeviceCategorizer device_categorizer = *mp_device_categorizer;
|
||||
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;
|
||||
|
||||
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 ();
|
||||
|
||||
|
|
@ -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) {
|
||||
const db::Net *net = c2->net_for_pin (p->id ());
|
||||
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) {
|
||||
const db::Net *net = c1->net_for_pin (p->id ());
|
||||
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;
|
||||
bool m_depth_first;
|
||||
bool m_dont_consider_net_names;
|
||||
mutable bool m_case_sensitive;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,33 +35,44 @@ NetlistExtractor::NetlistExtractor ()
|
|||
// .. 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;
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
m_include_floating_subcircuits = f;
|
||||
}
|
||||
|
||||
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;
|
||||
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::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 (jn_pattern.match (nn)) {
|
||||
prop_by_name [nn].insert (db::prop_id_to_attr (i->first));
|
||||
for (std::list<tl::GlobPattern>::const_iterator jp = jn_pattern.begin (); jp != jn_pattern.end (); ++jp) {
|
||||
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
|
||||
for (size_t gid = 0; gid < conn.global_nets (); ++gid) {
|
||||
const std::string &gn = conn.global_net_name (gid);
|
||||
if (jn_pattern.match (gn)) {
|
||||
prop_by_name [gn].insert (db::global_net_id_to_attr (gid));
|
||||
for (std::list<tl::GlobPattern>::const_iterator jp = jn_pattern.begin (); jp != jn_pattern.end (); ++jp) {
|
||||
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> ());
|
||||
for (db::repository<db::Text>::iterator t = text_repository.begin (); t != text_repository.end (); ++t) {
|
||||
std::string nn = t->string ();
|
||||
if (jn_pattern.match (nn)) {
|
||||
prop_by_name [nn].insert (db::text_ref_to_attr (t.operator-> ()));
|
||||
for (std::list<tl::GlobPattern>::const_iterator jp = jn_pattern.begin (); jp != jn_pattern.end (); ++jp) {
|
||||
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
|
||||
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;
|
||||
if (m_text_annot_name_id.first) {
|
||||
|
||||
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]);
|
||||
}
|
||||
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 ());
|
||||
if (cp.first) {
|
||||
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
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
#include "dbCommon.h"
|
||||
#include "dbHierNetworkProcessor.h"
|
||||
#include "dbNetShape.h"
|
||||
#include "tlGlobPattern.h"
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
|
@ -104,23 +105,30 @@ public:
|
|||
* @brief Sets the joined net names attribute
|
||||
* This is a glob expression rendering net names where partial nets with the
|
||||
* 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
|
||||
* 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.
|
||||
*/
|
||||
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
|
||||
{
|
||||
return m_joined_net_names;
|
||||
}
|
||||
void set_joined_nets (const std::list<std::set<std::string> > &jnn);
|
||||
|
||||
/**
|
||||
* @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
|
||||
|
|
@ -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_device_annot_name_id;
|
||||
std::pair<bool, db::property_names_id_type> m_terminal_annot_name_id;
|
||||
std::string m_joined_net_names;
|
||||
std::list<std::pair<std::string, std::string> > m_joined_net_names_per_cell;
|
||||
std::list<tl::GlobPattern> m_joined_net_names;
|
||||
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 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_circuits_read.clear ();
|
||||
|
||||
// SPICE netlists are case insensitive
|
||||
netlist.set_case_sensitive (false);
|
||||
|
||||
try {
|
||||
|
||||
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)
|
||||
{
|
||||
// TODO: allow configuring Spice reader as case sensitive?
|
||||
// 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
|
||||
return mp_netlist->normalize_name (read_name_with_case (ex));
|
||||
}
|
||||
|
||||
bool NetlistSpiceReader::read_element (tl::Extractor &ex, const std::string &element, const std::string &name)
|
||||
|
|
|
|||
|
|
@ -131,13 +131,13 @@ Region::clear ()
|
|||
void
|
||||
Region::reserve (size_t n)
|
||||
{
|
||||
flat_region ()->reserve (n);
|
||||
mutable_region ()->reserve (n);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
Region &Region::transform (const T &trans)
|
||||
{
|
||||
flat_region ()->transform (trans);
|
||||
mutable_region ()->transform (trans);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
|
@ -151,7 +151,7 @@ template DB_PUBLIC Region &Region::transform (const db::IMatrix3d &);
|
|||
template <class Sh>
|
||||
void Region::insert (const Sh &shape)
|
||||
{
|
||||
flat_region ()->insert (shape);
|
||||
mutable_region ()->insert (shape);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
flat_region ()->insert (shape);
|
||||
mutable_region ()->insert (shape);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
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::Trans &);
|
||||
template DB_PUBLIC void Region::insert (const db::Shape &, const db::Disp &);
|
||||
|
||||
FlatRegion *
|
||||
Region::flat_region ()
|
||||
MutableRegion *
|
||||
Region::mutable_region ()
|
||||
{
|
||||
FlatRegion *region = dynamic_cast<FlatRegion *> (mp_delegate);
|
||||
MutableRegion *region = dynamic_cast<MutableRegion *> (mp_delegate);
|
||||
if (! region) {
|
||||
region = new FlatRegion ();
|
||||
|
||||
FlatRegion *flat_region = new FlatRegion ();
|
||||
region = flat_region;
|
||||
|
||||
if (mp_delegate) {
|
||||
region->RegionDelegate::operator= (*mp_delegate); // copy basic flags
|
||||
region->insert_seq (begin ());
|
||||
region->set_is_merged (mp_delegate->is_merged ());
|
||||
flat_region->RegionDelegate::operator= (*mp_delegate); // copy basic flags
|
||||
flat_region->insert_seq (begin ());
|
||||
flat_region->set_is_merged (mp_delegate->is_merged ());
|
||||
}
|
||||
set_delegate (region);
|
||||
|
||||
set_delegate (flat_region);
|
||||
|
||||
}
|
||||
|
||||
return region;
|
||||
|
|
@ -276,6 +281,13 @@ Region::smoothed (coord_type d, bool keep_hv) const
|
|||
return processed (SmoothingProcessor (d, keep_hv));
|
||||
}
|
||||
|
||||
db::Region &
|
||||
Region::flatten ()
|
||||
{
|
||||
mutable_region ()->flatten ();
|
||||
return *this;
|
||||
}
|
||||
|
||||
void
|
||||
Region::snap (db::Coord gx, db::Coord gy)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@
|
|||
namespace db {
|
||||
|
||||
class EdgeFilterBase;
|
||||
class FlatRegion;
|
||||
class MutableRegion;
|
||||
class EmptyRegion;
|
||||
class DeepShapeStore;
|
||||
class TransformationReducer;
|
||||
|
|
@ -1644,11 +1644,7 @@ public:
|
|||
*
|
||||
* This method will turn any region into a flat shape collection.
|
||||
*/
|
||||
db::Region &flatten ()
|
||||
{
|
||||
flat_region ();
|
||||
return *this;
|
||||
}
|
||||
db::Region &flatten ();
|
||||
|
||||
/**
|
||||
* @brief Returns true, if the region has valid polygons stored within itself
|
||||
|
|
@ -1776,7 +1772,7 @@ private:
|
|||
RegionDelegate *mp_delegate;
|
||||
|
||||
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)
|
||||
{
|
||||
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);
|
||||
return *this;
|
||||
}
|
||||
|
|
@ -708,13 +709,14 @@ public:
|
|||
text<typename Tr::target_coord_type> transformed (const Tr &t) const
|
||||
{
|
||||
typedef typename Tr::target_coord_type target_coord_type;
|
||||
fixpoint_trans<coord_type> fp (t);
|
||||
size_t p = (size_t) mp_ptr;
|
||||
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) {
|
||||
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 {
|
||||
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>
|
||||
void Texts::insert (const Sh &shape)
|
||||
{
|
||||
flat_texts ()->insert (shape);
|
||||
mutable_texts ()->insert (shape);
|
||||
}
|
||||
|
||||
template DB_PUBLIC void Texts::insert (const db::Text &);
|
||||
|
||||
void Texts::insert (const db::Shape &shape)
|
||||
{
|
||||
flat_texts ()->insert (shape);
|
||||
mutable_texts ()->insert (shape);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
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::Trans &);
|
||||
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 ()
|
||||
{
|
||||
|
|
@ -120,13 +122,18 @@ void Texts::clear ()
|
|||
|
||||
void Texts::reserve (size_t n)
|
||||
{
|
||||
flat_texts ()->reserve (n);
|
||||
mutable_texts ()->reserve (n);
|
||||
}
|
||||
|
||||
void Texts::flatten ()
|
||||
{
|
||||
mutable_texts ()->flatten ();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
Texts &Texts::transform (const T &trans)
|
||||
{
|
||||
flat_texts ()->transform (trans);
|
||||
mutable_texts ()->transform (trans);
|
||||
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) {
|
||||
texts = new FlatTexts ();
|
||||
if (mp_delegate) {
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ namespace db
|
|||
{
|
||||
|
||||
class TextFilterBase;
|
||||
class FlatTexts;
|
||||
class MutableTexts;
|
||||
class EmptyTexts;
|
||||
class Edges;
|
||||
class Region;
|
||||
|
|
@ -491,10 +491,7 @@ public:
|
|||
*
|
||||
* This method will turn any edge pair collection into a flat one.
|
||||
*/
|
||||
void flatten ()
|
||||
{
|
||||
flat_texts ();
|
||||
}
|
||||
void flatten ();
|
||||
|
||||
/**
|
||||
* @brief Returns true, if the text set has valid texts stored within itself
|
||||
|
|
@ -616,7 +613,7 @@ private:
|
|||
TextsDelegate *mp_delegate;
|
||||
|
||||
void set_delegate (TextsDelegate *delegate);
|
||||
FlatTexts *flat_texts ();
|
||||
MutableTexts *mutable_texts();
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -376,6 +376,32 @@ public:
|
|||
// .. 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
|
||||
*/
|
||||
|
|
@ -420,7 +446,18 @@ public:
|
|||
// .. 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
|
||||
*/
|
||||
static const int r0 = 0; // No rotation
|
||||
|
|
@ -1651,7 +1688,7 @@ public:
|
|||
{
|
||||
tl_assert (! m.has_shear ());
|
||||
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);
|
||||
double rot = m.angle () * M_PI / 180.0;
|
||||
m_mag = m.is_mirror () ? -mag.first : mag.first;
|
||||
|
|
@ -1674,7 +1711,7 @@ public:
|
|||
: m_u (u)
|
||||
{
|
||||
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);
|
||||
double rot = m.angle () * M_PI / 180.0;
|
||||
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);
|
||||
}
|
||||
|
||||
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",
|
||||
gsi::constructor ("new", &make_l2n, gsi::arg ("iter"),
|
||||
"@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"),
|
||||
"@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"
|
||||
"boolean operations for deriving layers. Other operations are applicable as long as they are\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"),
|
||||
"@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),
|
||||
"@brief Runs the netlist extraction\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"
|
||||
gsi::method ("include_floating_subcircuits=", &db::LayoutToNetlist::set_include_floating_subcircuits, gsi::arg ("flag"),
|
||||
"@brief Sets a flag indicating whether to include floating subcircuits in the netlist.\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"
|
||||
"@li \"\" no 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"
|
||||
"Label matching is case sensitive.\n"
|
||||
"\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 property propagated to their parent instead of appearing as "
|
||||
"additional top circuits.\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_names2, gsi::arg ("cell_pattern"), gsi::arg ("pattern"),
|
||||
"@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"
|
||||
"See the class description for more details.\n"
|
||||
"\n"
|
||||
"The 'include_floating_subcircuits' argument has been introduced in version 0.26.2."
|
||||
) +
|
||||
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."
|
||||
"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_ext ("internal_layout", &l2n_internal_layout,
|
||||
"@brief Gets the internal layout\n"
|
||||
|
|
@ -658,7 +763,13 @@ Class<db::LayoutToNetlist> decl_dbLayoutToNetlist ("db", "LayoutToNetlist",
|
|||
"considered.\n"
|
||||
"\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"
|
||||
"\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"
|
||||
"@/li\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"
|
||||
" 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"
|
||||
|
|
|
|||
|
|
@ -519,6 +519,9 @@ Class<db::NetlistComparer> decl_dbNetlistComparer ("db", "NetlistComparer",
|
|||
"@brief Sets the maximum seach depth\n"
|
||||
"This value limits the search depth of the backtracking algorithm to the\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,
|
||||
"@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"
|
||||
"has been exceeded.\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"
|
||||
"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.transformed (db::Trans (db::Vector (1, 2))).bbox ().to_string (), "(1,2;101,202)");
|
||||
EXPECT_EQ (r.empty (), false);
|
||||
EXPECT_EQ (r.is_merged (), true);
|
||||
EXPECT_EQ (r.is_merged (), false);
|
||||
EXPECT_EQ (r.begin ().at_end (), false);
|
||||
|
||||
db::Edges r1 = r;
|
||||
|
|
|
|||
|
|
@ -3156,7 +3156,7 @@ TEST(12_FlattenCircuitDoesFlattenLayout)
|
|||
db::compare_layouts (_this, ly, au);
|
||||
}
|
||||
|
||||
TEST(13_JoinNets)
|
||||
TEST(13_JoinNetNames)
|
||||
{
|
||||
db::Layout ly;
|
||||
db::LayerMap lmap;
|
||||
|
|
@ -3299,7 +3299,8 @@ TEST(13_JoinNets)
|
|||
l2n.connect_global (*rbulk, "VSS");
|
||||
|
||||
// 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
|
||||
// 201/0 -> Well
|
||||
|
|
@ -3385,3 +3386,249 @@ TEST(13_JoinNets)
|
|||
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 (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 ().mag ().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 ().mag ().second), "7.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 ().mag2 ().second), "17.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 ().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 (false).inverted ().is_mirror ()), "false");
|
||||
EXPECT_EQ (tl::to_string (db::Matrix2d::rotation (25).inverted ().angle ()), "-25");
|
||||
|
|
|
|||
|
|
@ -958,19 +958,38 @@ TEST(3_DeviceAndNetExtractionWithImplicitConnections)
|
|||
|
||||
// extract the nets
|
||||
|
||||
std::list<tl::GlobPattern> gp;
|
||||
|
||||
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);
|
||||
|
||||
EXPECT_EQ (all_net_names_unique (nl2), true);
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
EXPECT_EQ (all_net_names_unique (nl), true);
|
||||
|
|
@ -1233,7 +1252,9 @@ TEST(4_ResAndCapExtraction)
|
|||
|
||||
// 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);
|
||||
|
||||
// Flatten device circuits
|
||||
|
|
@ -1507,7 +1528,9 @@ TEST(5_ResAndCapWithBulkExtraction)
|
|||
|
||||
// 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);
|
||||
|
||||
// Flatten device circuits
|
||||
|
|
@ -1749,7 +1772,9 @@ TEST(6_BJT3TransistorExtraction)
|
|||
|
||||
// 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);
|
||||
|
||||
// Flatten device circuits
|
||||
|
|
@ -1915,7 +1940,9 @@ TEST(7_DiodeExtraction)
|
|||
|
||||
// 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);
|
||||
|
||||
// cleanup + completion
|
||||
|
|
@ -2048,7 +2075,9 @@ TEST(8_DiodeExtractionScaled)
|
|||
|
||||
// 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);
|
||||
|
||||
// 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)
|
||||
# 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%
|
||||
# @name antenna_check
|
||||
# @brief Performs an antenna check
|
||||
|
|
@ -1892,6 +1900,7 @@ CODE
|
|||
connect
|
||||
connect_global
|
||||
connect_implicit
|
||||
connect_explicit
|
||||
device_scaling
|
||||
extract_devices
|
||||
l2n_data
|
||||
|
|
|
|||
|
|
@ -67,6 +67,8 @@ module DRC
|
|||
@netlisted = false
|
||||
@connect_implicit = []
|
||||
@connect_implicit_per_cell = {}
|
||||
@connect_explicit = []
|
||||
@connect_explicit_per_cell = {}
|
||||
@l2n = nil
|
||||
@lnum = 0
|
||||
@device_scaling = 1.0
|
||||
|
|
@ -241,6 +243,8 @@ module DRC
|
|||
@netlisted = false
|
||||
@connect_implicit = []
|
||||
@connect_implicit_per_cell = {}
|
||||
@connect_explicit = []
|
||||
@connect_explicit_per_cell = {}
|
||||
_clear_data
|
||||
end
|
||||
|
||||
|
|
@ -286,6 +290,67 @@ module DRC
|
|||
|
||||
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%
|
||||
# @brief Performs an antenna check
|
||||
# @name antenna_check
|
||||
|
|
@ -481,16 +546,29 @@ module DRC
|
|||
# run extraction in a timed environment
|
||||
if ! @netlisted
|
||||
|
||||
# build a glob expression from the parts
|
||||
expr = _join_glob_pattern(@connect_implicit)
|
||||
|
||||
# build cell-pattern specific glob expressions from the parts
|
||||
per_cell_expr = {}
|
||||
# configure implicit net connections
|
||||
@l2n.clear_join_net_names
|
||||
@connect_implicit.each do |label_pattern|
|
||||
@l2n.join_net_names(label_pattern)
|
||||
end
|
||||
@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
|
||||
|
||||
@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
|
||||
|
||||
end
|
||||
|
|
@ -548,18 +626,6 @@ module DRC
|
|||
end
|
||||
end
|
||||
|
||||
def _join_glob_pattern(exprs)
|
||||
|
||||
if exprs.size > 1
|
||||
expr = "{" + exprs.join(",") + "}"
|
||||
else
|
||||
expr = exprs[0] || ""
|
||||
end
|
||||
|
||||
expr
|
||||
|
||||
end
|
||||
|
||||
def _make_data
|
||||
|
||||
if @engine._dss
|
||||
|
|
|
|||
|
|
@ -312,6 +312,17 @@ l1 = input(1, 0)
|
|||
<p>
|
||||
See <a href="/about/drc_ref_netter.xml#connect">Netter#connect</a> for a description of that function.
|
||||
</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>
|
||||
<keyword name="connect_global"/>
|
||||
<p>Usage:</p>
|
||||
|
|
|
|||
|
|
@ -219,6 +219,50 @@ joins.
|
|||
Connections are accumulated. The connections defined so far
|
||||
can be cleared with <a href="#clear_connections">clear_connections</a>.
|
||||
</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>
|
||||
<keyword name="connect_global"/>
|
||||
<p>Usage:</p>
|
||||
|
|
|
|||
|
|
@ -114,13 +114,15 @@ netter.equivalent_pins("NAND2", 0, 1)
|
|||
</pre>
|
||||
</p><p>
|
||||
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>
|
||||
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>
|
||||
Before this method can be used, a schematic netlist needs to be loaded with
|
||||
<a href="#schematic">schematic</a>.
|
||||
Use this method andwhere in the script before the <a href="#compare">compare</a> call.
|
||||
</p>
|
||||
<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"/>
|
||||
|
|
@ -174,6 +176,12 @@ with inherent ambiguity such as decoders, the complexity
|
|||
can be increased at the expense of potentially larger runtimes.
|
||||
The runtime penality is roughly proportional to the branch
|
||||
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>
|
||||
<a name="max_depth"/><h2>"max_depth" - Configures the maximum search depth for net match deduction</h2>
|
||||
<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
|
||||
smaller values, the algorithm prefers picking nets in a random fashion
|
||||
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>
|
||||
<a name="max_res"/><h2>"max_res" - Ignores resistors with a resistance above a certain value</h2>
|
||||
<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
|
||||
method allows establishing an explicit correspondence.
|
||||
</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
|
||||
other circuit is mapped to "nothing", i.e. ignored.
|
||||
</p><p>
|
||||
Before this method can be used, a schematic netlist needs to be loaded with
|
||||
<a href="#schematic">schematic</a>.
|
||||
Use this method andwhere in the script before the <a href="#compare">compare</a> call.
|
||||
</p>
|
||||
<a name="same_device_classes"/><h2>"same_device_classes" - Establishes an equivalence between the device classes</h2>
|
||||
<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
|
||||
<a href="#schematic">schematic</a>.
|
||||
</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
|
||||
other device class is mapped to "nothing", i.e. ignored.
|
||||
</p><p>
|
||||
|
|
@ -260,7 +279,11 @@ schematic side.
|
|||
</p><p>
|
||||
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")'
|
||||
"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>
|
||||
<a name="same_nets"/><h2>"same_nets" - Establishes an equivalence between the nets</h2>
|
||||
<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
|
||||
resolve otherwise.
|
||||
</p><p>
|
||||
Before this method can be used, a schematic netlist needs to be loaded with
|
||||
<a href="#schematic">schematic</a>.
|
||||
circuit_a and net_a are for the layout netlist, circuit_b and net_b for the schematic netlist.
|
||||
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>
|
||||
<a name="schematic"/><h2>"schematic" - Gets, sets or reads the reference netlist</h2>
|
||||
<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.
|
||||
</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>
|
||||
|
|
|
|||
|
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_connect.xml">doc/manual/lvs_connect.xml</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_transistors.png">doc/manual/inv_transistors.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);
|
||||
}
|
||||
|
||||
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;
|
||||
if (device_classes.first && device_classes.first->terminal_definitions ().size () > terminal_id) {
|
||||
td1 = &device_classes.first->terminal_definitions () [terminal_id];
|
||||
std::vector<std::pair<const db::DeviceTerminalDefinition *, const db::DeviceTerminalDefinition *> > result;
|
||||
|
||||
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) {
|
||||
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 (td1 && devices.first && devices.second) {
|
||||
if (i < n2) {
|
||||
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 ());
|
||||
const db::Net *n2 = model->second_net_for (devices.first->net_for_terminal (terminal_id));
|
||||
if (i < n1) {
|
||||
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) {
|
||||
if (devices.second->net_for_terminal (i) == n2) {
|
||||
second_terminal_id = i;
|
||||
break;
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
std::vector<std::pair<const db::DeviceTerminalDefinition *, const db::Net *> > &nn1 = n->second.first;
|
||||
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
|
||||
|
|
@ -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;
|
||||
|
|
@ -1965,12 +1997,14 @@ CircuitNetDeviceTerminalItemData::do_ensure_children (NetlistBrowserModel *model
|
|||
return;
|
||||
}
|
||||
|
||||
size_t n = std::max (rows_for (m_tp.first), rows_for (m_tp.second));
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
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);
|
||||
IndexedNetlistModel::net_pair nets = nets_from_device_terminals (dp (), termdefs);
|
||||
push_back (new CircuitNetDeviceTerminalOthersItemData (this, nets, termdefs));
|
||||
std::pair<const db::Device *, const db::Device *> devices = dp ();
|
||||
std::pair<const db::DeviceClass *, const db::DeviceClass *> device_classes = device_classes_from_devices (devices);
|
||||
|
||||
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) {
|
||||
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
|
||||
CircuitDeviceItemData::do_ensure_children (NetlistBrowserModel *model)
|
||||
{
|
||||
size_t n = std::max (rows_for (dp ().first), rows_for (dp ().second));
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
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::pair<const db::Device *, const db::Device *> devices = dp ();
|
||||
std::pair<const db::DeviceClass *, const db::DeviceClass *> device_classes = device_classes_from_devices (devices);
|
||||
|
||||
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->parent (inv2Net0TerminalIndex) == inv2Net0Index, true);
|
||||
// .. 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::DisplayRole).toString ()), "G");
|
||||
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, 3, inv2Net0TerminalIndex), Qt::DisplayRole).toString ()), "2 (3)");
|
||||
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 ()), "D");
|
||||
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 ()), "5 (2)");
|
||||
|
||||
// The Pin
|
||||
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
|
||||
# resolve otherwise.
|
||||
#
|
||||
# Before this method can be used, a schematic netlist needs to be loaded with
|
||||
# \schematic.
|
||||
# circuit_a and net_a are for the layout netlist, circuit_b and net_b for the schematic netlist.
|
||||
# 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)
|
||||
|
||||
|
|
@ -373,12 +375,14 @@ module LVS
|
|||
# This method will force an equivalence between the two circuits.
|
||||
# By default, circuits are identified by name. If names are different, this
|
||||
# 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
|
||||
# other circuit is mapped to "nothing", i.e. ignored.
|
||||
#
|
||||
# Before this method can be used, a schematic netlist needs to be loaded with
|
||||
# \schematic.
|
||||
# Use this method andwhere in the script before the \compare call.
|
||||
|
||||
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
|
||||
# \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
|
||||
# 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
|
||||
# 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)
|
||||
|
||||
|
|
@ -468,13 +479,15 @@ module LVS
|
|||
# @/code
|
||||
#
|
||||
# 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.
|
||||
# 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
|
||||
# \schematic.
|
||||
# Use this method andwhere in the script before the \compare call.
|
||||
|
||||
def equivalent_pins(circuit, *pins)
|
||||
|
||||
|
|
@ -603,6 +616,12 @@ module LVS
|
|||
# pursues this "deduction path" in greater depth while with
|
||||
# smaller values, the algorithm prefers picking nets in a random fashion
|
||||
# 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)
|
||||
v = value.to_i
|
||||
|
|
@ -625,6 +644,12 @@ module LVS
|
|||
# can be increased at the expense of potentially larger runtimes.
|
||||
# The runtime penality is roughly proportional to the branch
|
||||
# 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)
|
||||
v = value.to_i
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@
|
|||
#include "lymMacro.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 ();
|
||||
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_l2n = '%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);
|
||||
EXPECT_EQ (config.run (), 0);
|
||||
|
|
@ -108,11 +109,15 @@ TEST(5_simple_same_device_classes)
|
|||
TEST(6_simple_pin_swapping)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
|
|
@ -143,6 +148,8 @@ TEST(12_simple_dmos)
|
|||
TEST(13_simple_ringo_device_subcircuits)
|
||||
{
|
||||
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)
|
||||
|
|
|
|||
|
|
@ -154,3 +154,16 @@ TEST(17_private)
|
|||
test_is_long_runner ();
|
||||
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);
|
||||
|
||||
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) {
|
||||
l2ndb->netlist ()->flatten ();
|
||||
|
|
|
|||
|
|
@ -68,6 +68,30 @@ public:
|
|||
*/
|
||||
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
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ connect_global(bulk, "SUBSTRATE")
|
|||
connect_global(ptie, "SUBSTRATE")
|
||||
|
||||
# Test same_device_classes
|
||||
same_device_classes("PMOS", "XPMOS")
|
||||
same_device_classes("PMOS", $change_case ? "xpMos" : "XPMOS")
|
||||
|
||||
# Compare section
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ target_netlist($lvs_test_target_cir, write_spice, "Extracted by KLayout")
|
|||
schematic("ringo.cir")
|
||||
|
||||
# preempt configuration (see below)
|
||||
same_nets("top", "ENABLE", "RINGO", "ENABLE")
|
||||
same_nets("top", "ENABLE", $change_case ? "Ringo" : "RINGO", $change_case ? "enable" : "ENABLE")
|
||||
|
||||
deep
|
||||
|
||||
|
|
@ -71,8 +71,8 @@ connect_global(ptie, "SUBSTRATE")
|
|||
|
||||
# Compare section
|
||||
|
||||
same_circuits("top", "RINGO")
|
||||
same_circuits("INV", "INVX1")
|
||||
same_circuits("top", $change_case ? "ringo" : "RINGO")
|
||||
same_circuits("INV", $change_case ? "invX1" : "INVX1")
|
||||
same_circuits("DOESNOTEXIST", "DOESNOTEXIST2")
|
||||
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")
|
||||
|
||||
# preempt configuration
|
||||
equivalent_pins("ND2X1", 4, 5)
|
||||
equivalent_pins($change_case ? "nd2X1" : "ND2X1", 4, 5)
|
||||
|
||||
deep
|
||||
|
||||
|
|
|
|||
|
|
@ -179,12 +179,11 @@ class DBEdgePairs_TestClass < TestBase
|
|||
assert_equal(r.is_deep?, true)
|
||||
|
||||
r.flatten
|
||||
assert_equal(r.has_valid_edge_pairs?, true)
|
||||
assert_equal(r[1].to_s, "(0,101;2,103)/(10,111;12,113)")
|
||||
assert_equal(r[100].inspect, "nil")
|
||||
assert_equal(r.has_valid_edge_pairs?, false)
|
||||
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.bbox.to_s, "(0,1;212,113)")
|
||||
|
||||
assert_equal(r.is_deep?, false)
|
||||
assert_equal(r.is_deep?, true)
|
||||
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ class DBEdges_TestClass < TestBase
|
|||
assert_equal(r.count, 4)
|
||||
assert_equal(r.hier_count, 4)
|
||||
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(10, 20).bbox.to_s, "(20,40;110,220)")
|
||||
|
|
@ -615,12 +615,11 @@ class DBEdges_TestClass < TestBase
|
|||
|
||||
r.flatten
|
||||
|
||||
assert_equal(r.is_deep?, false)
|
||||
assert_equal(r.is_deep?, true)
|
||||
|
||||
assert_equal(r.count, 12)
|
||||
assert_equal(r.hier_count, 12)
|
||||
assert_equal(r[1].to_s, "(-10,20;10,20)")
|
||||
assert_equal(r[100].to_s, "")
|
||||
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)...")
|
||||
|
||||
end
|
||||
|
||||
|
|
|
|||