mirror of https://github.com/KLayout/klayout.git
commit
9d8a438d1d
|
|
@ -524,8 +524,8 @@ class DB_PUBLIC hnp_interaction_receiver
|
||||||
public:
|
public:
|
||||||
typedef typename local_cluster<T>::box_type box_type;
|
typedef typename local_cluster<T>::box_type box_type;
|
||||||
|
|
||||||
hnp_interaction_receiver (const Connectivity &conn, const db::ICplxTrans &trans)
|
hnp_interaction_receiver (const Connectivity &conn, const db::ICplxTrans &trans, std::map<unsigned int, std::set<const T *> > *interacting_this, std::map<unsigned int, std::set<const T *> > *interacting_other)
|
||||||
: mp_conn (&conn), m_any (false), m_soft_mode (0), m_trans (trans)
|
: mp_conn (&conn), m_any (false), m_soft_mode (0), m_trans (trans), mp_interacting_this (interacting_this), mp_interacting_other (interacting_other)
|
||||||
{
|
{
|
||||||
// .. nothing yet ..
|
// .. nothing yet ..
|
||||||
}
|
}
|
||||||
|
|
@ -534,6 +534,12 @@ public:
|
||||||
{
|
{
|
||||||
int soft = 0;
|
int soft = 0;
|
||||||
if (mp_conn->interacts (*s1, l1, *s2, l2, m_trans, soft)) {
|
if (mp_conn->interacts (*s1, l1, *s2, l2, m_trans, soft)) {
|
||||||
|
if (mp_interacting_this) {
|
||||||
|
(*mp_interacting_this) [l1].insert (s1);
|
||||||
|
}
|
||||||
|
if (mp_interacting_other) {
|
||||||
|
(*mp_interacting_other) [l2].insert (s2);
|
||||||
|
}
|
||||||
if (soft == 0 || (m_soft_mode != 0 && m_soft_mode != soft)) {
|
if (soft == 0 || (m_soft_mode != 0 && m_soft_mode != soft)) {
|
||||||
m_soft_mode = 0;
|
m_soft_mode = 0;
|
||||||
m_any = true;
|
m_any = true;
|
||||||
|
|
@ -543,9 +549,14 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool any () const
|
||||||
|
{
|
||||||
|
return m_any || m_soft_mode != 0;
|
||||||
|
}
|
||||||
|
|
||||||
bool stop () const
|
bool stop () const
|
||||||
{
|
{
|
||||||
return m_any;
|
return m_any && ! mp_interacting_other && ! mp_interacting_this;
|
||||||
}
|
}
|
||||||
|
|
||||||
int soft_mode () const
|
int soft_mode () const
|
||||||
|
|
@ -558,6 +569,7 @@ private:
|
||||||
bool m_any;
|
bool m_any;
|
||||||
int m_soft_mode;
|
int m_soft_mode;
|
||||||
db::ICplxTrans m_trans;
|
db::ICplxTrans m_trans;
|
||||||
|
std::map<unsigned int, std::set<const T *> > *mp_interacting_this, *mp_interacting_other;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class T, class Trans>
|
template <class T, class Trans>
|
||||||
|
|
@ -619,9 +631,31 @@ local_cluster<T>::interacts (const db::Cell &cell, const db::ICplxTrans &trans,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
static
|
||||||
|
void collect_interactions_in_original_order (const std::map<unsigned int, typename local_cluster<T>::tree_type> &shapes, const std::map<unsigned int, std::set<const T *> > &interacting, std::map<unsigned int, std::vector<const T *> > &interacting_out)
|
||||||
|
{
|
||||||
|
for (typename std::map<unsigned int, std::set<const T *> >::const_iterator i = interacting.begin (); i != interacting.end (); ++i) {
|
||||||
|
|
||||||
|
std::vector<const T *> &t = interacting_out [i->first];
|
||||||
|
auto s = shapes.find (i->first);
|
||||||
|
if (s == shapes.end ()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
t.reserve (t.size () + i->second.size ());
|
||||||
|
for (auto j = s->second.begin (); j != s->second.end (); ++j) {
|
||||||
|
if (i->second.find (j.operator-> ()) != i->second.end ()) {
|
||||||
|
t.push_back (j.operator-> ());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
bool
|
bool
|
||||||
local_cluster<T>::interacts (const local_cluster<T> &other, const db::ICplxTrans &trans, const Connectivity &conn, int &soft) const
|
local_cluster<T>::interacts (const local_cluster<T> &other, const db::ICplxTrans &trans, const Connectivity &conn, int &soft, std::map<unsigned int, std::vector<const T *> > *interacting_this, std::map<unsigned int, std::vector<const T *> > *interacting_other) const
|
||||||
{
|
{
|
||||||
db::box_convert<T> bc;
|
db::box_convert<T> bc;
|
||||||
|
|
||||||
|
|
@ -679,11 +713,26 @@ local_cluster<T>::interacts (const local_cluster<T> &other, const db::ICplxTrans
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hnp_interaction_receiver<T> rec (conn, trans);
|
std::map<unsigned int, std::set<const T *> > is_this, is_other;
|
||||||
|
std::map<unsigned int, std::set<const T *> > *p_is_this = interacting_this ? &is_this : 0;
|
||||||
|
std::map<unsigned int, std::set<const T *> > *p_is_other = interacting_other ? &is_other : 0;
|
||||||
|
|
||||||
|
hnp_interaction_receiver<T> rec (conn, trans, p_is_this, p_is_other);
|
||||||
|
scanner.process (rec, 1 /*==touching*/, bc, bc_t);
|
||||||
|
|
||||||
|
if (rec.any ()) {
|
||||||
|
|
||||||
|
if (p_is_this) {
|
||||||
|
collect_interactions_in_original_order (m_shapes, *p_is_this, *interacting_this);
|
||||||
|
}
|
||||||
|
if (p_is_other) {
|
||||||
|
collect_interactions_in_original_order (other.m_shapes, *p_is_other, *interacting_other);
|
||||||
|
}
|
||||||
|
|
||||||
if (! scanner.process (rec, 1 /*==touching*/, bc, bc_t) || rec.soft_mode () != 0) {
|
|
||||||
soft = rec.soft_mode ();
|
soft = rec.soft_mode ();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -326,8 +326,10 @@ public:
|
||||||
*
|
*
|
||||||
* "trans" is the transformation which is applied to the other cluster before
|
* "trans" is the transformation which is applied to the other cluster before
|
||||||
* the test.
|
* the test.
|
||||||
|
* If non-null "interacting_this" will receive all interacting shapes from *this in case of success.
|
||||||
|
* If non-null "interacting_other" will receive all interacting shapes from other in case of success.
|
||||||
*/
|
*/
|
||||||
bool interacts (const local_cluster<T> &other, const db::ICplxTrans &trans, const Connectivity &conn, int &soft) const;
|
bool interacts (const local_cluster<T> &other, const db::ICplxTrans &trans, const Connectivity &conn, int &soft, std::map<unsigned int, std::vector<const T *> > *interacting_this = 0, std::map<unsigned int, std::vector<const T *> > *interacting_other = 0) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Tests whether this cluster interacts with the given cell
|
* @brief Tests whether this cluster interacts with the given cell
|
||||||
|
|
|
||||||
|
|
@ -1308,6 +1308,102 @@ static bool deliver_shapes_of_net (bool recursive, const db::Netlist *nl, const
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
LayoutToNetlist::collect_shapes_of_pin (const local_cluster<db::NetShape> &c, const db::Net *other_net, const db::ICplxTrans &sc_trans, const db::ICplxTrans &trans, std::map<unsigned int, db::Region> &result) const
|
||||||
|
{
|
||||||
|
if (! other_net || ! other_net->circuit ()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto cc_other = m_net_clusters.clusters_per_cell (other_net->circuit ()->cell_index ());
|
||||||
|
auto c_other = cc_other.cluster_by_id (other_net->cluster_id ());
|
||||||
|
|
||||||
|
std::map<unsigned int, std::vector<const db::NetShape *> > interacting;
|
||||||
|
int soft = 0;
|
||||||
|
if (c.interacts (c_other, sc_trans, m_conn, soft, 0, &interacting)) {
|
||||||
|
|
||||||
|
auto t = trans * sc_trans;
|
||||||
|
|
||||||
|
for (auto i = interacting.begin (); i != interacting.end (); ++i) {
|
||||||
|
db::Region &r = result [i->first];
|
||||||
|
for (auto s = i->second.begin (); s != i->second.end (); ++s) {
|
||||||
|
deliver_shape (**s, r, t, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
double dbu = internal_layout ()->dbu ();
|
||||||
|
|
||||||
|
for (auto p = other_net->begin_subcircuit_pins (); p != other_net->end_subcircuit_pins (); ++p) {
|
||||||
|
|
||||||
|
db::ICplxTrans sc_trans2 = sc_trans * db::CplxTrans (dbu).inverted () * p->subcircuit ()->trans () * db::CplxTrans (dbu);
|
||||||
|
const db::Net *other_net2 = p->subcircuit ()->circuit_ref ()->net_for_pin (p->pin_id ());
|
||||||
|
|
||||||
|
collect_shapes_of_pin (c, other_net2, sc_trans2, trans, result);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::map<unsigned int, db::Region>
|
||||||
|
LayoutToNetlist::shapes_of_pin (const db::NetSubcircuitPinRef &pin, const db::ICplxTrans &trans) const
|
||||||
|
{
|
||||||
|
std::map<unsigned int, db::Region> result;
|
||||||
|
|
||||||
|
const db::Net *net = pin.net ();
|
||||||
|
if (! net || ! net->circuit () || ! pin.subcircuit () || ! pin.subcircuit ()->circuit_ref ()) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto cc = m_net_clusters.clusters_per_cell (net->circuit ()->cell_index ());
|
||||||
|
auto c = cc.cluster_by_id (net->cluster_id ());
|
||||||
|
|
||||||
|
double dbu = internal_layout ()->dbu ();
|
||||||
|
db::ICplxTrans sc_trans = db::CplxTrans (dbu).inverted () * pin.subcircuit ()->trans () * db::CplxTrans (dbu);
|
||||||
|
const db::Net *other_net = pin.subcircuit ()->circuit_ref ()->net_for_pin (pin.pin_id ());
|
||||||
|
|
||||||
|
collect_shapes_of_pin (c, other_net, sc_trans, trans, result);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::map<unsigned int, db::Region>
|
||||||
|
LayoutToNetlist::shapes_of_terminal (const db::NetTerminalRef &terminal, const db::ICplxTrans &trans) const
|
||||||
|
{
|
||||||
|
std::map<unsigned int, db::Region> result;
|
||||||
|
|
||||||
|
const db::Net *net = terminal.net ();
|
||||||
|
if (! net || ! net->circuit () || ! terminal.device () || ! terminal.device ()->device_abstract ()) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto cc = m_net_clusters.clusters_per_cell (net->circuit ()->cell_index ());
|
||||||
|
auto c = cc.cluster_by_id (net->cluster_id ());
|
||||||
|
|
||||||
|
double dbu = internal_layout ()->dbu ();
|
||||||
|
db::ICplxTrans d_trans = db::CplxTrans (dbu).inverted () * terminal.device ()->trans () * db::CplxTrans (dbu);
|
||||||
|
|
||||||
|
auto cc_other = m_net_clusters.clusters_per_cell (terminal.device ()->device_abstract ()->cell_index ());
|
||||||
|
auto c_other = cc_other.cluster_by_id (terminal.device ()->device_abstract ()->cluster_id_for_terminal (terminal.terminal_id ()));
|
||||||
|
|
||||||
|
std::map<unsigned int, std::vector<const db::NetShape *> > interacting;
|
||||||
|
int soft = 0;
|
||||||
|
if (c.interacts (c_other, d_trans, m_conn, soft, 0, &interacting)) {
|
||||||
|
|
||||||
|
auto t = trans * d_trans;
|
||||||
|
|
||||||
|
for (auto i = interacting.begin (); i != interacting.end (); ++i) {
|
||||||
|
db::Region &r = result [i->first];
|
||||||
|
for (auto s = i->second.begin (); s != i->second.end (); ++s) {
|
||||||
|
deliver_shape (**s, r, t, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
void LayoutToNetlist::shapes_of_net (const db::Net &net, const db::Region &of_layer, bool recursive, db::Shapes &to, db::properties_id_type propid, const ICplxTrans &trans) const
|
void LayoutToNetlist::shapes_of_net (const db::Net &net, const db::Region &of_layer, bool recursive, db::Shapes &to, db::properties_id_type propid, const ICplxTrans &trans) const
|
||||||
{
|
{
|
||||||
unsigned int lid = layer_of (of_layer);
|
unsigned int lid = layer_of (of_layer);
|
||||||
|
|
|
||||||
|
|
@ -828,6 +828,32 @@ public:
|
||||||
return m_net_clusters;
|
return m_net_clusters;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the shapes that make the subcircuit pin
|
||||||
|
*
|
||||||
|
* This method looks up all shapes from the subcircuit that interact with the shapes of the net
|
||||||
|
* the subcircuit pin lives in. It will return a map of layer index vs. Region with these
|
||||||
|
* shapes, transformed into the coordinate space of the net.
|
||||||
|
*
|
||||||
|
* Note that this method only considers top-down interactions between the shapes of the net
|
||||||
|
* and subcircuits on any level below, but not between subcircuits.
|
||||||
|
* It is useful only for certain topologies - i.e. digital nets connecting gate cells.
|
||||||
|
*/
|
||||||
|
std::map<unsigned int, db::Region> shapes_of_pin (const db::NetSubcircuitPinRef &pin, const db::ICplxTrans &trans = db::ICplxTrans ()) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the shapes that make the device terminal
|
||||||
|
*
|
||||||
|
* This method looks up all shapes from the device terminals that interact with the shapes of the net
|
||||||
|
* the device terminal lives in. It will return a map of layer index vs. Region with these
|
||||||
|
* shapes, transformed into the coordinate space of the net.
|
||||||
|
*
|
||||||
|
* Note that this method only considers top-down interactions between the shapes of the net
|
||||||
|
* and subcircuits on any level below, but not between subcircuits and devices.
|
||||||
|
* It is useful for flat-extracted netlists for example.
|
||||||
|
*/
|
||||||
|
std::map<unsigned int, db::Region> shapes_of_terminal (const db::NetTerminalRef &terminal, const db::ICplxTrans &trans = db::ICplxTrans ()) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns all shapes of a specific net and layer.
|
* @brief Returns all shapes of a specific net and layer.
|
||||||
*
|
*
|
||||||
|
|
@ -1099,6 +1125,7 @@ private:
|
||||||
void ensure_layout () const;
|
void ensure_layout () const;
|
||||||
std::string make_new_name (const std::string &stem = std::string ());
|
std::string make_new_name (const std::string &stem = std::string ());
|
||||||
db::CellMapping make_cell_mapping_into (db::Layout &layout, db::Cell &cell, const std::vector<const db::Net *> *nets, bool with_device_cells);
|
db::CellMapping make_cell_mapping_into (db::Layout &layout, db::Cell &cell, const std::vector<const db::Net *> *nets, bool with_device_cells);
|
||||||
|
void collect_shapes_of_pin (const local_cluster<db::NetShape> &c, const db::Net *other_net, const db::ICplxTrans &sc_trans, const db::ICplxTrans &trans, std::map<unsigned int, db::Region> &result) const;
|
||||||
void connect_impl (const db::ShapeCollection &a, const db::ShapeCollection &b);
|
void connect_impl (const db::ShapeCollection &a, const db::ShapeCollection &b);
|
||||||
size_t connect_global_impl (const db::ShapeCollection &l, const std::string &gn);
|
size_t connect_global_impl (const db::ShapeCollection &l, const std::string &gn);
|
||||||
void soft_connect_impl (const db::ShapeCollection &a, const db::ShapeCollection &b);
|
void soft_connect_impl (const db::ShapeCollection &a, const db::ShapeCollection &b);
|
||||||
|
|
|
||||||
|
|
@ -191,16 +191,22 @@ gsi::ClassExt<db::LoadLayoutOptions> common_reader_options (
|
||||||
gsi::EnumIn<db::LoadLayoutOptions, db::CellConflictResolution> decl_dbCommonReader_CellConflictResolution ("db", "CellConflictResolution",
|
gsi::EnumIn<db::LoadLayoutOptions, db::CellConflictResolution> decl_dbCommonReader_CellConflictResolution ("db", "CellConflictResolution",
|
||||||
gsi::enum_const ("AddToCell", db::AddToCell,
|
gsi::enum_const ("AddToCell", db::AddToCell,
|
||||||
"@brief Add content to existing cell\n"
|
"@brief Add content to existing cell\n"
|
||||||
"This is the mode use in before version 0.27. Content of new cells is simply added to existing cells with the same name."
|
"This is the mode use in before version 0.27. Content of new cells is simply added to existing cells with the same name.\n"
|
||||||
|
"Before version 0.29.2, this mode also merged instances, rendering it difficult to merge two identical cell hierarchies.\n"
|
||||||
|
"Since version 0.29.2, no instance duplicates are generated. Instead only new instances are added to existing cells.\n"
|
||||||
|
"With this feature in place, it is safe to merge two identical cell hierarchies stored in different files using AddToCell mode.\n"
|
||||||
|
"In that application, the shapes and layers of the layouts are combined, but the cell hierarchy stays identical."
|
||||||
) +
|
) +
|
||||||
gsi::enum_const ("OverwriteCell", db::OverwriteCell,
|
gsi::enum_const ("OverwriteCell", db::OverwriteCell,
|
||||||
"@brief The old cell is overwritten entirely (including child cells which are not used otherwise)\n"
|
"@brief The old cell is overwritten entirely (including child cells which are not used otherwise).\n"
|
||||||
) +
|
) +
|
||||||
gsi::enum_const ("SkipNewCell", db::SkipNewCell,
|
gsi::enum_const ("SkipNewCell", db::SkipNewCell,
|
||||||
"@brief The new cell is skipped entirely (including child cells which are not used otherwise)\n"
|
"@brief The new cell is skipped entirely (including child cells which are not used otherwise).\n"
|
||||||
) +
|
) +
|
||||||
gsi::enum_const ("RenameCell", db::RenameCell,
|
gsi::enum_const ("RenameCell", db::RenameCell,
|
||||||
"@brief The new cell will be renamed to become unique\n"
|
"@brief The new cell will be renamed to become unique.\n"
|
||||||
|
"In this mode, two files are are combined rendering independent cell hierarchies coming from the original files.\n"
|
||||||
|
"Cells may be renamed however. Also, new top cells will appear after merging a file into the layout using RenameCell mode.\n"
|
||||||
),
|
),
|
||||||
"@brief This enum specifies how cell conflicts are handled if a layout read into another layout and a cell name conflict arises.\n"
|
"@brief This enum specifies how cell conflicts are handled if a layout read into another layout and a cell name conflict arises.\n"
|
||||||
"Until version 0.26.8 and before, the mode was always 'AddToCell'. On reading, a cell was 'reopened' when encountering a cell name "
|
"Until version 0.26.8 and before, the mode was always 'AddToCell'. On reading, a cell was 'reopened' when encountering a cell name "
|
||||||
|
|
|
||||||
|
|
@ -678,6 +678,44 @@ Class<db::LayoutToNetlist> decl_dbLayoutToNetlist ("db", "LayoutToNetlist",
|
||||||
gsi::method ("netlist", &db::LayoutToNetlist::netlist,
|
gsi::method ("netlist", &db::LayoutToNetlist::netlist,
|
||||||
"@brief gets the netlist extracted (0 if no extraction happened yet)\n"
|
"@brief gets the netlist extracted (0 if no extraction happened yet)\n"
|
||||||
) +
|
) +
|
||||||
|
gsi::method ("shapes_of_pin", &db::LayoutToNetlist::shapes_of_pin, gsi::arg ("pin"), gsi::arg ("trans", db::ICplxTrans (), "unity"),
|
||||||
|
"@brief Returns all shapes of the given subcircuit pin that make a connection to the net the pin lives in.\n"
|
||||||
|
"This will return all shapes from the subcircuit attached by the given pin that interact with the net the pin lives in.\n"
|
||||||
|
"This method returns a \\Region object with the shapes per layer where interactions are found.\n"
|
||||||
|
"The layers are given as layer indexes.\n"
|
||||||
|
"\n"
|
||||||
|
"The returned shapes are already transformed into the coordinate system of the net (see \\shapes_of_net for example).\n"
|
||||||
|
"An additional transformation can be applied using the optional \\trans argument.\n"
|
||||||
|
"\n"
|
||||||
|
"Note, that this method only considers interations between net shapes and subcircuits on every level below, "
|
||||||
|
"but not between subcircuits.\n"
|
||||||
|
"It can be used for example for digital nets connecting gate cells. In the general case however, nets may be formed\n"
|
||||||
|
"also by touching subcircuits. In that case, the nets do not have shapes of their own and this function cannot detect\n"
|
||||||
|
"the pin shapes.\n"
|
||||||
|
"\n"
|
||||||
|
"The call of this method may not be cheap, specificially if large nets are involved.\n"
|
||||||
|
"\n"
|
||||||
|
"This method has been introduced in version 0.29.2."
|
||||||
|
) +
|
||||||
|
gsi::method ("shapes_of_terminal", &db::LayoutToNetlist::shapes_of_terminal, gsi::arg ("terminal"), gsi::arg ("trans", db::ICplxTrans (), "unity"),
|
||||||
|
"@brief Returns all shapes of the given device terminal that make a connection to the net the terminal lives in.\n"
|
||||||
|
"This will return all shapes from the device attached by the given terminal that interact with the net the terminal lives in.\n"
|
||||||
|
"This method returns a \\Region object with the shapes per layer where interactions are found.\n"
|
||||||
|
"The layers are given as layer indexes.\n"
|
||||||
|
"\n"
|
||||||
|
"The returned shapes are already transformed into the coordinate system of the net (see \\shapes_of_net for example).\n"
|
||||||
|
"An additional transformation can be applied using the optional \\trans argument.\n"
|
||||||
|
"\n"
|
||||||
|
"Note, that this method only considers interations between net shapes and the device connected by the terminal, "
|
||||||
|
"but not between subcircuits on the net and the device.\n"
|
||||||
|
"It can be used for example for flat-extracted, transistor-level netlists. In the general case however, nets may be formed\n"
|
||||||
|
"also by subcircuits touching devices. In that case, the nets do not have shapes of their own and this function cannot detect\n"
|
||||||
|
"the terminal shapes.\n"
|
||||||
|
"\n"
|
||||||
|
"The call of this method may not be cheap, specificially if large nets are involved.\n"
|
||||||
|
"\n"
|
||||||
|
"This method has been introduced in version 0.29.2."
|
||||||
|
) +
|
||||||
gsi::factory ("shapes_of_net", (db::Region *(db::LayoutToNetlist::*) (const db::Net &, const db::Region &, bool, const db::ICplxTrans &) const) &db::LayoutToNetlist::shapes_of_net, gsi::arg ("net"), gsi::arg ("of_layer"), gsi::arg ("recursive", true), gsi::arg ("trans", db::ICplxTrans (), "unity"),
|
gsi::factory ("shapes_of_net", (db::Region *(db::LayoutToNetlist::*) (const db::Net &, const db::Region &, bool, const db::ICplxTrans &) const) &db::LayoutToNetlist::shapes_of_net, gsi::arg ("net"), gsi::arg ("of_layer"), gsi::arg ("recursive", true), gsi::arg ("trans", db::ICplxTrans (), "unity"),
|
||||||
"@brief Returns all shapes of a specific net and layer.\n"
|
"@brief Returns all shapes of a specific net and layer.\n"
|
||||||
"If 'recursive'' is true, the returned region will contain the shapes of\n"
|
"If 'recursive'' is true, the returned region will contain the shapes of\n"
|
||||||
|
|
|
||||||
|
|
@ -1827,3 +1827,87 @@ TEST(112_Waiving)
|
||||||
compare_text_files (report, au_report);
|
compare_text_files (report, au_report);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST(120_ShapesOfPin)
|
||||||
|
{
|
||||||
|
std::string rs = tl::testdata ();
|
||||||
|
rs += "/drc/drcSimpleTests_120.drc";
|
||||||
|
|
||||||
|
// apart from that it's a variant of 14b ...
|
||||||
|
|
||||||
|
std::string input = tl::testdata ();
|
||||||
|
input += "/drc/drcSimpleTests_120.gds";
|
||||||
|
|
||||||
|
std::string au = tl::testdata ();
|
||||||
|
au += "/drc/drcSimpleTests_au120.gds";
|
||||||
|
|
||||||
|
std::string output = this->tmp_file ("tmp.gds");
|
||||||
|
|
||||||
|
{
|
||||||
|
// Set some variables
|
||||||
|
lym::Macro config;
|
||||||
|
config.set_text (tl::sprintf (
|
||||||
|
"$drc_test_source = '%s'\n"
|
||||||
|
"$drc_test_target = '%s'\n"
|
||||||
|
, input, output)
|
||||||
|
);
|
||||||
|
config.set_interpreter (lym::Macro::Ruby);
|
||||||
|
EXPECT_EQ (config.run (), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
lym::Macro drc;
|
||||||
|
drc.load_from (rs);
|
||||||
|
EXPECT_EQ (drc.run (), 0);
|
||||||
|
|
||||||
|
db::Layout layout;
|
||||||
|
|
||||||
|
{
|
||||||
|
tl::InputStream stream (output);
|
||||||
|
db::Reader reader (stream);
|
||||||
|
reader.read (layout);
|
||||||
|
}
|
||||||
|
|
||||||
|
db::compare_layouts (_this, layout, au, db::NoNormalization);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(121_ShapesOfTerminal)
|
||||||
|
{
|
||||||
|
std::string rs = tl::testdata ();
|
||||||
|
rs += "/drc/drcSimpleTests_121.drc";
|
||||||
|
|
||||||
|
// apart from that it's a variant of 14b ...
|
||||||
|
|
||||||
|
std::string input = tl::testdata ();
|
||||||
|
input += "/drc/drcSimpleTests_121.gds";
|
||||||
|
|
||||||
|
std::string au = tl::testdata ();
|
||||||
|
au += "/drc/drcSimpleTests_au121.gds";
|
||||||
|
|
||||||
|
std::string output = this->tmp_file ("tmp.gds");
|
||||||
|
|
||||||
|
{
|
||||||
|
// Set some variables
|
||||||
|
lym::Macro config;
|
||||||
|
config.set_text (tl::sprintf (
|
||||||
|
"$drc_test_source = '%s'\n"
|
||||||
|
"$drc_test_target = '%s'\n"
|
||||||
|
, input, output)
|
||||||
|
);
|
||||||
|
config.set_interpreter (lym::Macro::Ruby);
|
||||||
|
EXPECT_EQ (config.run (), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
lym::Macro drc;
|
||||||
|
drc.load_from (rs);
|
||||||
|
EXPECT_EQ (drc.run (), 0);
|
||||||
|
|
||||||
|
db::Layout layout;
|
||||||
|
|
||||||
|
{
|
||||||
|
tl::InputStream stream (output);
|
||||||
|
db::Reader reader (stream);
|
||||||
|
reader.read (layout);
|
||||||
|
}
|
||||||
|
|
||||||
|
db::compare_layouts (_this, layout, au, db::NoNormalization);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
|
||||||
|
source $drc_test_source
|
||||||
|
target $drc_test_target
|
||||||
|
|
||||||
|
deep
|
||||||
|
|
||||||
|
l1 = input(1, 0)
|
||||||
|
l2 = input(2, 0)
|
||||||
|
l3 = input(3, 0)
|
||||||
|
|
||||||
|
name(l1, "l1")
|
||||||
|
name(l2, "l2")
|
||||||
|
name(l3, "l3")
|
||||||
|
|
||||||
|
connect(l1, l2)
|
||||||
|
connect(l2, l3)
|
||||||
|
|
||||||
|
netlist
|
||||||
|
|
||||||
|
l1_out = polygons
|
||||||
|
l2_out = polygons
|
||||||
|
l3_out = polygons
|
||||||
|
|
||||||
|
output_layers = {
|
||||||
|
"l1" => l1_out,
|
||||||
|
"l2" => l2_out,
|
||||||
|
"l3" => l3_out
|
||||||
|
}
|
||||||
|
|
||||||
|
[ "A", "B", "C" ].each do |n|
|
||||||
|
|
||||||
|
net = l2n_data.netlist.circuit_by_name("TOP").net_by_name(n)
|
||||||
|
if net
|
||||||
|
|
||||||
|
net.each_subcircuit_pin do |pin|
|
||||||
|
shapes = l2n_data.shapes_of_pin(pin, RBA::Trans::new(RBA::Vector::new(100, 200)))
|
||||||
|
shapes.keys.each do |li|
|
||||||
|
output_layers[l2n_data.layer_name(li)].data.insert(shapes[li])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
l1.output(1, 0)
|
||||||
|
l2.output(2, 0)
|
||||||
|
l3.output(3, 0)
|
||||||
|
l1_out.output(101, 0)
|
||||||
|
l2_out.output(102, 0)
|
||||||
|
l3_out.output(103, 0)
|
||||||
|
|
||||||
Binary file not shown.
|
|
@ -0,0 +1,89 @@
|
||||||
|
|
||||||
|
source $drc_test_source
|
||||||
|
target $drc_test_target
|
||||||
|
|
||||||
|
# only works flat:
|
||||||
|
# deep
|
||||||
|
|
||||||
|
l1 = input(1, 0)
|
||||||
|
l2 = input(2, 0)
|
||||||
|
l3 = input(3, 0)
|
||||||
|
|
||||||
|
active = input(10, 0)
|
||||||
|
poly = input(11, 0)
|
||||||
|
contact = input(12, 0)
|
||||||
|
|
||||||
|
sd = active - poly
|
||||||
|
gate = active & poly
|
||||||
|
|
||||||
|
name(l1, "l1")
|
||||||
|
name(l2, "l2")
|
||||||
|
name(l3, "l3")
|
||||||
|
name(sd, "sd")
|
||||||
|
name(poly, "poly")
|
||||||
|
name(gate, "gate")
|
||||||
|
name(contact, "contact")
|
||||||
|
|
||||||
|
mos_ex = RBA::DeviceExtractorMOS3Transistor::new("MOS")
|
||||||
|
extract_devices(mos_ex, { "SD" => sd, "G" => gate, "P" => poly })
|
||||||
|
|
||||||
|
connect(contact, poly)
|
||||||
|
connect(contact, sd)
|
||||||
|
connect(l1, contact)
|
||||||
|
connect(l1, l2)
|
||||||
|
connect(l2, l3)
|
||||||
|
|
||||||
|
netlist
|
||||||
|
|
||||||
|
l1_out = polygons
|
||||||
|
l2_out = polygons
|
||||||
|
l3_out = polygons
|
||||||
|
contact_out = polygons
|
||||||
|
sd_out = polygons
|
||||||
|
gate_out = polygons
|
||||||
|
poly_out = polygons
|
||||||
|
|
||||||
|
output_layers = {
|
||||||
|
"l1" => l1_out,
|
||||||
|
"l2" => l2_out,
|
||||||
|
"l3" => l3_out,
|
||||||
|
"contact" => contact_out,
|
||||||
|
"poly" => poly_out,
|
||||||
|
"gate" => gate_out,
|
||||||
|
"sd" => sd_out
|
||||||
|
}
|
||||||
|
|
||||||
|
[ "A", "B", "C" ].each do |n|
|
||||||
|
|
||||||
|
net = l2n_data.netlist.circuit_by_name("TOP").net_by_name(n)
|
||||||
|
if net
|
||||||
|
|
||||||
|
net.each_terminal do |terminal|
|
||||||
|
shapes = l2n_data.shapes_of_terminal(terminal, RBA::Trans::new(RBA::Vector::new(100, 200)))
|
||||||
|
shapes.keys.each do |li|
|
||||||
|
output_layers[l2n_data.layer_name(li)].data.insert(shapes[li])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
l1.output(1, 0)
|
||||||
|
l2.output(2, 0)
|
||||||
|
l3.output(3, 0)
|
||||||
|
|
||||||
|
sd.output(10, 0)
|
||||||
|
poly.output(11, 0)
|
||||||
|
contact.output(12, 0)
|
||||||
|
gate.output(13, 0)
|
||||||
|
|
||||||
|
l1_out.output(101, 0)
|
||||||
|
l2_out.output(102, 0)
|
||||||
|
l3_out.output(103, 0)
|
||||||
|
|
||||||
|
sd_out.output(110, 0)
|
||||||
|
poly_out.output(111, 0)
|
||||||
|
contact_out.output(112, 0)
|
||||||
|
gate_out.output(113, 0)
|
||||||
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue