mirror of https://github.com/KLayout/klayout.git
commit
9d8a438d1d
|
|
@ -524,8 +524,8 @@ class DB_PUBLIC hnp_interaction_receiver
|
|||
public:
|
||||
typedef typename local_cluster<T>::box_type box_type;
|
||||
|
||||
hnp_interaction_receiver (const Connectivity &conn, const db::ICplxTrans &trans)
|
||||
: mp_conn (&conn), m_any (false), m_soft_mode (0), m_trans (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_interacting_this (interacting_this), mp_interacting_other (interacting_other)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
@ -534,6 +534,12 @@ public:
|
|||
{
|
||||
int soft = 0;
|
||||
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)) {
|
||||
m_soft_mode = 0;
|
||||
m_any = true;
|
||||
|
|
@ -543,9 +549,14 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
bool any () const
|
||||
{
|
||||
return m_any || m_soft_mode != 0;
|
||||
}
|
||||
|
||||
bool stop () const
|
||||
{
|
||||
return m_any;
|
||||
return m_any && ! mp_interacting_other && ! mp_interacting_this;
|
||||
}
|
||||
|
||||
int soft_mode () const
|
||||
|
|
@ -558,6 +569,7 @@ private:
|
|||
bool m_any;
|
||||
int m_soft_mode;
|
||||
db::ICplxTrans m_trans;
|
||||
std::map<unsigned int, std::set<const T *> > *mp_interacting_this, *mp_interacting_other;
|
||||
};
|
||||
|
||||
template <class T, class Trans>
|
||||
|
|
@ -619,9 +631,31 @@ local_cluster<T>::interacts (const db::Cell &cell, const db::ICplxTrans &trans,
|
|||
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>
|
||||
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;
|
||||
|
||||
|
|
@ -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 ();
|
||||
|
||||
return true;
|
||||
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -326,8 +326,10 @@ public:
|
|||
*
|
||||
* "trans" is the transformation which is applied to the other cluster before
|
||||
* 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
|
||||
|
|
|
|||
|
|
@ -1308,6 +1308,102 @@ static bool deliver_shapes_of_net (bool recursive, const db::Netlist *nl, const
|
|||
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
|
||||
{
|
||||
unsigned int lid = layer_of (of_layer);
|
||||
|
|
|
|||
|
|
@ -828,6 +828,32 @@ public:
|
|||
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.
|
||||
*
|
||||
|
|
@ -1099,6 +1125,7 @@ private:
|
|||
void ensure_layout () const;
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -191,16 +191,22 @@ gsi::ClassExt<db::LoadLayoutOptions> common_reader_options (
|
|||
gsi::EnumIn<db::LoadLayoutOptions, db::CellConflictResolution> decl_dbCommonReader_CellConflictResolution ("db", "CellConflictResolution",
|
||||
gsi::enum_const ("AddToCell", db::AddToCell,
|
||||
"@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,
|
||||
"@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,
|
||||
"@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,
|
||||
"@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"
|
||||
"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,
|
||||
"@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"),
|
||||
"@brief Returns all shapes of a specific net and layer.\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);
|
||||
}
|
||||
|
||||
|
||||
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