LayoutToNetlist enhancements in the area of the dumper.

This commit is contained in:
Matthias Koefferlein
2019-01-16 22:45:58 +01:00
parent 438f50091f
commit 56bb39a273
10 changed files with 725 additions and 78 deletions
+21
View File
@@ -2029,6 +2029,27 @@ recursive_cluster_shape_iterator<T> &recursive_cluster_shape_iterator<T>::operat
return *this;
}
template <class T>
void recursive_cluster_shape_iterator<T>::skip_cell ()
{
m_shape_iter = typename db::local_cluster<T>::shape_iterator ();
do {
up ();
if (m_conn_iter_stack.empty ()) {
return;
}
++m_conn_iter_stack.back ().first;
} while (m_conn_iter_stack.back ().first == m_conn_iter_stack.back ().second);
while (m_shape_iter.at_end () && ! m_conn_iter_stack.empty ()) {
next_conn ();
}
}
template <class T>
void recursive_cluster_shape_iterator<T>::next_conn ()
{
+5
View File
@@ -882,6 +882,11 @@ public:
*/
recursive_cluster_shape_iterator &operator++ ();
/**
* @brief Skips the current cell and advances to the next cell and shape
*/
void skip_cell ();
private:
typedef typename db::connected_clusters<T>::connections_type connections_type;
+30 -6
View File
@@ -78,28 +78,43 @@ size_t LayoutToNetlist::max_vertex_count () const
return m_dss.max_vertex_count ();
}
db::Region *LayoutToNetlist::make_layer (unsigned int layer_index)
db::Region *LayoutToNetlist::make_layer (unsigned int layer_index, const std::string &n)
{
db::RecursiveShapeIterator si (m_iter);
si.set_layer (layer_index);
si.shape_flags (db::ShapeIterator::All);
return new db::Region (si, m_dss);
db::Region *region = new db::Region (si, m_dss);
if (! n.empty ()) {
name (*region, n);
}
return region;
}
db::Region *LayoutToNetlist::make_text_layer (unsigned int layer_index)
db::Region *LayoutToNetlist::make_text_layer (unsigned int layer_index, const std::string &n)
{
db::RecursiveShapeIterator si (m_iter);
si.set_layer (layer_index);
si.shape_flags (db::ShapeIterator::Texts);
return new db::Region (si, m_dss);
db::Region *region = new db::Region (si, m_dss);
if (! n.empty ()) {
name (*region, n);
}
return region;
}
db::Region *LayoutToNetlist::make_polygon_layer (unsigned int layer_index)
db::Region *LayoutToNetlist::make_polygon_layer (unsigned int layer_index, const std::string &n)
{
db::RecursiveShapeIterator si (m_iter);
si.set_layer (layer_index);
si.shape_flags (db::ShapeIterator::Paths | db::ShapeIterator::Polygons | db::ShapeIterator::Boxes);
return new db::Region (si, m_dss);
db::Region *region = new db::Region (si, m_dss);
if (! n.empty ()) {
name (*region, n);
}
return region;
}
void LayoutToNetlist::extract_devices (db::NetlistDeviceExtractor &extractor, const std::map<std::string, db::Region *> &layers)
@@ -202,6 +217,15 @@ const db::Cell *LayoutToNetlist::internal_top_cell () const
return &m_dss.const_initial_cell ();
}
void LayoutToNetlist::name (const db::Region &region, const std::string &name)
{
unsigned int li = layer_of (region);
db::Layout &ly = m_dss.layout ();
db::LayerProperties lp = ly.get_properties (li);
lp.name = name;
ly.set_properties (li, lp);
}
unsigned int LayoutToNetlist::layer_of (const db::Region &region) const
{
const db::DeepRegion *dr = dynamic_cast<const db::DeepRegion *> (region.delegate ());
+22 -3
View File
@@ -114,6 +114,25 @@ public:
*/
size_t max_vertex_count () const;
/**
* @brief Names a layer
* This is a formal name for the layer. Using a name or layer properties
* (see below) enhances readability of backannotated information
* if layers are involved. Use this method or the other variants to
* attach a name or standard layer properties to a region delivered
* by "make_layer" or derived from other regions through boolean
* operations.
*/
void name (const db::Region &region, const std::string &name);
/**
* @brief Gets the name of the given layer
*/
std::string name (const db::Region &region) const
{
return internal_layout ()->get_properties (layer_of (region)).name;
}
/**
* @brief Creates a new region representing an original layer
* "layer_index" is the layer index of the desired layer in the original layout.
@@ -122,19 +141,19 @@ public:
* A variant not taking texts is "make_polygon_layer". A Variant only taking
* texts is "make_text_layer".
*/
db::Region *make_layer (unsigned int layer_index);
db::Region *make_layer (unsigned int layer_index, const std::string &name = std::string ());
/**
* @brief Creates a new region representing an original layer taking texts only
* See "make_layer" for details.
*/
db::Region *make_text_layer (unsigned int layer_index);
db::Region *make_text_layer (unsigned int layer_index, const std::string &name = std::string ());
/**
* @brief Creates a new region representing an original layer taking polygons and texts
* See "make_layer" for details.
*/
db::Region *make_polygon_layer (unsigned int layer_index);
db::Region *make_polygon_layer (unsigned int layer_index, const std::string &name = std::string ());
/**
* @brief Extracts devices
+104 -41
View File
@@ -52,8 +52,8 @@ namespace db
* connect(<layer1> <name> ...) - connects layer1 with the following layers [short key: C]
* global(<layer> <net> ...) - connects a layer with the given global nets [short key: G]
* circuit(<name> [circuit-def]) - circuit (cell) [short key: X]
* device(<name> <class> [device-footprint-def])
* - device footprint [short key: D]
* device(<name> <class> [device-abstract-def])
* - device abstract [short key: D]
*
* [circuit-def]:
*
@@ -72,7 +72,7 @@ namespace db
* rect(<layer> <left> <bottom> <right> <top>)
* - defines a rectangle [short key: R]
*
* [device-footprint-def]:
* [device-abstract-def]:
*
* terminal(<terminal-name> [geometry-def])
* - specifies the terminal geometry [short key: empty]
@@ -80,7 +80,7 @@ namespace db
* [device-def]:
*
* param(<name> <value>) - defines a parameter [short key P]
* footprint(<name>) - links to a geometrical device footprint on top level [short key F]
* abstract(<name>) - links to a geometrical device abstract on top level [short key A]
* terminal(<terminal-name> <net-name>)
* - specifies connection of the terminal with
* a net (short key: empty)
@@ -110,7 +110,7 @@ static std::string subcircuit_key ("subcircuit");
static std::string polygon_key ("polygon");
static std::string rect_key ("rect");
static std::string terminal_key ("terminal");
static std::string footprint_key ("footprint");
static std::string abstract_key ("abstract");
static std::string label_key ("label");
static std::string param_key ("param");
static std::string location_key ("location");
@@ -140,20 +140,31 @@ static std::string name_for_layer (const db::Layout *layout, unsigned int l)
void LayoutToNetlistStandardWriter::write (const db::LayoutToNetlist *l2n)
{
const int version = 1;
bool any = false;
const int version = 0;
const db::Layout *ly = l2n->internal_layout ();
const db::Netlist *nl = l2n->netlist ();
*mp_stream << "# General" << endl;
*mp_stream << version_key << "(" << version << ")" << endl;
*mp_stream << "# General section" << endl;
*mp_stream << "# Lists general definitions." << endl << endl;
if (version > 0) {
*mp_stream << version_key << "(" << version << ")" << endl;
}
*mp_stream << top_key << "(" << tl::to_word_or_quoted_string (ly->cell_name (l2n->internal_top_cell ()->cell_index ())) << ")" << endl;
*mp_stream << unit_key << "(" << ly->dbu () << ")" << endl;
*mp_stream << endl << "# Layers" << endl;
for (db::Connectivity::layer_iterator l = l2n->connectivity ().begin_layers (); l != l2n->connectivity ().end_layers (); ++l) {
*mp_stream << endl << "# Layer section" << endl;
*mp_stream << "# This section lists the mask layers (drawing or derived) and their connections." << endl;
*mp_stream << endl << "# Mask layers" << endl;
for (db::Connectivity::layer_iterator l = l2n->connectivity ().begin_layers (); l != l2n->connectivity ().end_layers (); ++l) {
*mp_stream << layer_key << "(" << name_for_layer (ly, *l) << ")" << endl;
}
*mp_stream << endl << "# Mask layer connectivity" << endl;
for (db::Connectivity::layer_iterator l = l2n->connectivity ().begin_layers (); l != l2n->connectivity ().end_layers (); ++l) {
db::Connectivity::layer_iterator ce = l2n->connectivity ().end_connected (*l);
db::Connectivity::layer_iterator cb = l2n->connectivity ().begin_connected (*l);
@@ -165,9 +176,18 @@ void LayoutToNetlistStandardWriter::write (const db::LayoutToNetlist *l2n)
*mp_stream << ")" << endl;
}
}
any = false;
for (db::Connectivity::layer_iterator l = l2n->connectivity ().begin_layers (); l != l2n->connectivity ().end_layers (); ++l) {
db::Connectivity::global_nets_iterator ge = l2n->connectivity ().end_global_connections (*l);
db::Connectivity::global_nets_iterator gb = l2n->connectivity ().begin_global_connections (*l);
if (gb != ge) {
if (! any) {
*mp_stream << endl << "# Global nets and connectivity" << endl;
any = true;
}
*mp_stream << global_key << "(" << name_for_layer (ly, *l);
for (db::Connectivity::global_nets_iterator g = gb; g != ge; ++g) {
*mp_stream << " " << tl::to_word_or_quoted_string (l2n->connectivity ().global_net_name (*g));
@@ -177,7 +197,10 @@ void LayoutToNetlistStandardWriter::write (const db::LayoutToNetlist *l2n)
}
*mp_stream << endl << "# Device footprints" << endl;
if (nl->begin_device_models () != nl->end_device_models ()) {
*mp_stream << endl << "# Device abstracts section" << endl;
*mp_stream << "# Device abstracts list the pin shapes of the devices." << endl;
}
for (db::Netlist::const_device_model_iterator m = nl->begin_device_models (); m != nl->end_device_models (); ++m) {
if (m->device_class ()) {
*mp_stream << device_key << "(" << tl::to_word_or_quoted_string (m->name ()) << " " << tl::to_word_or_quoted_string (m->device_class ()->name ()) << endl;
@@ -186,6 +209,8 @@ void LayoutToNetlistStandardWriter::write (const db::LayoutToNetlist *l2n)
}
}
*mp_stream << endl << "# Circuit section" << endl;
*mp_stream << "# Circuits are the hierarchical building blocks of the netlist." << endl;
for (db::Netlist::const_top_down_circuit_iterator i = nl->begin_top_down (); i != nl->end_top_down (); ++i) {
const db::Circuit *x = *i;
*mp_stream << endl << "# Circuit " << x->name () << endl;
@@ -197,24 +222,38 @@ void LayoutToNetlistStandardWriter::write (const db::LayoutToNetlist *l2n)
void LayoutToNetlistStandardWriter::write (const db::LayoutToNetlist *l2n, const db::Circuit &circuit)
{
for (db::Circuit::const_net_iterator n = circuit.begin_nets (); n != circuit.end_nets (); ++n) {
write (l2n, *n);
}
for (db::Circuit::const_pin_iterator p = circuit.begin_pins (); p != circuit.end_pins (); ++p) {
const db::Net *net = circuit.net_for_pin (p->id ());
if (net) {
*mp_stream << indent1 << pin_key << "(" << tl::to_word_or_quoted_string (p->expanded_name ()) << " " << tl::to_word_or_quoted_string (net->expanded_name ()) << ")" << endl;
if (circuit.begin_nets () != circuit.end_nets ()) {
*mp_stream << endl << indent1 << "# Nets with their geometries" << endl;
for (db::Circuit::const_net_iterator n = circuit.begin_nets (); n != circuit.end_nets (); ++n) {
write (l2n, *n);
}
}
for (db::Circuit::const_device_iterator d = circuit.begin_devices (); d != circuit.end_devices (); ++d) {
write (l2n, *d);
if (circuit.begin_pins () != circuit.end_pins ()) {
*mp_stream << endl << indent1 << "# Outgoing pins and their connections to nets" << endl;
for (db::Circuit::const_pin_iterator p = circuit.begin_pins (); p != circuit.end_pins (); ++p) {
const db::Net *net = circuit.net_for_pin (p->id ());
if (net) {
*mp_stream << indent1 << pin_key << "(" << tl::to_word_or_quoted_string (p->expanded_name ()) << " " << tl::to_word_or_quoted_string (net->expanded_name ()) << ")" << endl;
}
}
}
for (db::Circuit::const_subcircuit_iterator x = circuit.begin_subcircuits (); x != circuit.end_subcircuits (); ++x) {
write (l2n, *x);
if (circuit.begin_devices () != circuit.end_devices ()) {
*mp_stream << endl << indent1 << "# Devices and their connections" << endl;
for (db::Circuit::const_device_iterator d = circuit.begin_devices (); d != circuit.end_devices (); ++d) {
write (l2n, *d);
}
}
if (circuit.begin_subcircuits () != circuit.end_subcircuits ()) {
*mp_stream << endl << indent1 << "# Subcircuits and their connections" << endl;
for (db::Circuit::const_subcircuit_iterator x = circuit.begin_subcircuits (); x != circuit.end_subcircuits (); ++x) {
write (l2n, *x);
}
}
*mp_stream << endl;
}
template <class T, class Tr>
@@ -226,12 +265,14 @@ void write_points (tl::OutputStream &stream, const T &poly, const Tr &tr)
}
}
void LayoutToNetlistStandardWriter::write (const db::PolygonRef *s, const std::string &lname)
void LayoutToNetlistStandardWriter::write (const db::PolygonRef *s, const db::ICplxTrans &tr, const std::string &lname)
{
db::ICplxTrans t = tr * db::ICplxTrans (s->trans ());
const db::Polygon &poly = s->obj ();
if (poly.is_box ()) {
db::Box box = s->trans () * poly.box ();
db::Box box = t * poly.box ();
*mp_stream << rect_key << "(" << lname;
*mp_stream << " " << box.left () << " " << box.bottom ();
*mp_stream << " " << box.right () << " " << box.top ();
@@ -242,9 +283,9 @@ void LayoutToNetlistStandardWriter::write (const db::PolygonRef *s, const std::s
*mp_stream << polygon_key << "(" << lname;
if (poly.holes () > 0) {
db::SimplePolygon sp (poly);
write_points (*mp_stream, sp, s->trans ());
write_points (*mp_stream, sp, t);
} else {
write_points (*mp_stream, poly, s->trans ());
write_points (*mp_stream, poly, t);
}
*mp_stream << ")";
@@ -262,18 +303,36 @@ void LayoutToNetlistStandardWriter::write (const db::LayoutToNetlist *l2n, const
for (db::Connectivity::layer_iterator l = conn.begin_layers (); l != conn.end_layers (); ++l) {
const db::local_cluster<db::PolygonRef> &lc = clusters.clusters_per_cell (circuit->cell_index ()).cluster_by_id (net.cluster_id ());
for (db::local_cluster<db::PolygonRef>::shape_iterator s = lc.begin (*l); ! s.at_end (); ++s) {
db::cell_index_type cci = circuit->cell_index ();
db::cell_index_type prev_ci = cci;
for (db::recursive_cluster_shape_iterator<db::PolygonRef> si (clusters, *l, cci, net.cluster_id ()); ! si.at_end (); ) {
// NOTE: we don't recursive into circuits which will later be output. However, as circuits may
// vanish in "purge" but the clusters will still be there we need to recursive into clusters from
// unknown cells.
db::cell_index_type ci = si.cell_index ();
if (ci != prev_ci && ci != cci && l2n->netlist ()->circuit_by_cell_index (ci)) {
si.skip_cell ();
} else {
if (! any) {
*mp_stream << indent1 << net_key << "(" << tl::to_word_or_quoted_string (net.expanded_name ()) << endl;
any = true;
}
*mp_stream << indent2;
write (si.operator-> (), si.trans (), name_for_layer (ly, *l));
*mp_stream << endl;
prev_ci = ci;
++si;
if (! any) {
*mp_stream << indent1 << net_key << "(" << tl::to_word_or_quoted_string (net.expanded_name ()) << endl;
any = true;
}
*mp_stream << indent2;
write (s.operator-> (), name_for_layer (ly, *l));
*mp_stream << endl;
}
}
@@ -341,21 +400,25 @@ void LayoutToNetlistStandardWriter::write (const db::LayoutToNetlist *l2n, const
const db::hier_clusters<db::PolygonRef> &clusters = l2n->net_clusters ();
const db::Connectivity &conn = l2n->connectivity ();
for (db::Connectivity::layer_iterator l = conn.begin_layers (); l != conn.end_layers (); ++l) {
for (std::vector<db::DeviceTerminalDefinition>::const_iterator t = td.begin (); t != td.end (); ++t) {
for (std::vector<db::DeviceTerminalDefinition>::const_iterator t = td.begin (); t != td.end (); ++t) {
*mp_stream << indent1 << terminal_key << "(" << t->name () << endl;
for (db::Connectivity::layer_iterator l = conn.begin_layers (); l != conn.end_layers (); ++l) {
const db::local_cluster<db::PolygonRef> &lc = clusters.clusters_per_cell (device_model.cell_index ()).cluster_by_id (device_model.cluster_id_for_terminal (t->id ()));
for (db::local_cluster<db::PolygonRef>::shape_iterator s = lc.begin (*l); ! s.at_end (); ++s) {
*mp_stream << indent1;
write (s.operator-> (), name_for_layer (ly, *l));
*mp_stream << indent2;
write (s.operator-> (), db::ICplxTrans (), name_for_layer (ly, *l));
*mp_stream << endl;
}
}
*mp_stream << indent1 << ")" << endl;
}
}
@@ -370,7 +433,7 @@ void LayoutToNetlistStandardWriter::write (const db::LayoutToNetlist *l2n, const
*mp_stream << indent2 << location_key << "(" << device.position ().x () / dbu << " " << device.position ().y () / dbu << ")" << endl;
if (device.device_model ()) {
*mp_stream << indent2 << footprint_key << "(" << tl::to_word_or_quoted_string (device.device_model ()->name ()) << ")" << endl;
*mp_stream << indent2 << abstract_key << "(" << tl::to_word_or_quoted_string (device.device_model ()->name ()) << ")" << endl;
}
const std::vector<DeviceParameterDefinition> &pd = device.device_class ()->parameter_definitions ();
+1 -1
View File
@@ -68,7 +68,7 @@ private:
void write (const db::LayoutToNetlist *l2n, const db::SubCircuit &subcircuit);
void write (const db::LayoutToNetlist *l2n, const db::Device &device);
void write (const db::LayoutToNetlist *l2n, const db::DeviceModel &device_model);
void write (const db::PolygonRef *s, const std::string &lname);
void write (const db::PolygonRef *s, const db::ICplxTrans &tr, const std::string &lname);
};
}
+20 -7
View File
@@ -95,21 +95,34 @@ Class<db::LayoutToNetlist> decl_dbLayoutToNetlist ("db", "LayoutToNetlist",
gsi::method ("max_vertex_count", &db::LayoutToNetlist::max_vertex_count,
"See \\max_vertex_count= for details about this attribute."
) +
gsi::method ("make_layer", &db::LayoutToNetlist::make_layer, gsi::arg ("layer_index"),
"@brief Creates a new region representing an original layer\n"
"'layer_index'' is the layer index of the desired layer in the original layout.\n"
"The Region object returned is a new object and must be deleted by the caller.\n"
gsi::method ("name", &db::LayoutToNetlist::name, gsi::arg ("l"),
"@brief Names the given layer\n"
"'l' must be a hierarchical region derived with \\make_layer, \\make_text_layer or \\make_polygon_layer or "
"a region derived from those by boolean operations or other hierarchical operations.\n"
"\n"
"Naming a layer allows the system to indicate the layer in various contexts, i.e. "
"when writing the data to a file.\n"
) +
gsi::method ("make_layer", &db::LayoutToNetlist::make_layer, gsi::arg ("layer_index"), gsi::arg ("name", std::string ()),
"@brief Creates a new hierarchical region representing an original layer\n"
"'layer_index' is the layer index of the desired layer in the original layout.\n"
"This variant produces polygons and takes texts for net name annotation.\n"
"A variant not taking texts is \\make_polygon_layer. A Variant only taking\n"
"texts is \\make_text_layer.\n"""
"texts is \\make_text_layer.\n"
"\n"
"The name is optional. If given, the layer will already be named accordingly (see \\name).\n"
) +
gsi::method ("make_text_layer", &db::LayoutToNetlist::make_text_layer, gsi::arg ("layer_index"),
gsi::method ("make_text_layer", &db::LayoutToNetlist::make_text_layer, gsi::arg ("layer_index"), gsi::arg ("name", std::string ()),
"@brief Creates a new region representing an original layer taking texts only\n"
"See \\make_layer for details.\n"
"\n"
"The name is optional. If given, the layer will already be named accordingly (see \\name).\n"
) +
gsi::method ("make_polygon_layer", &db::LayoutToNetlist::make_polygon_layer, gsi::arg ("layer_index"),
gsi::method ("make_polygon_layer", &db::LayoutToNetlist::make_polygon_layer, gsi::arg ("layer_index"), gsi::arg ("name", std::string ()),
"@brief Creates a new region representing an original layer taking polygons and texts\n"
"See \\make_layer for details.\n"
"\n"
"The name is optional. If given, the layer will already be named accordingly (see \\name).\n"
) +
gsi::method ("extract_devices", &db::LayoutToNetlist::extract_devices, gsi::arg ("extractor"), gsi::arg ("layers"),
"@brief Extracts devices\n"
@@ -702,10 +702,14 @@ static std::string path2string (const db::Layout &ly, db::cell_index_type ci, co
return res;
}
static std::string rcsiter2string (const db::Layout &ly, db::cell_index_type ci, db::recursive_cluster_shape_iterator<db::PolygonRef> si)
static std::string rcsiter2string (const db::Layout &ly, db::cell_index_type ci, db::recursive_cluster_shape_iterator<db::PolygonRef> si, db::cell_index_type ci2skip = std::numeric_limits<db::cell_index_type>::max ())
{
std::string res;
while (! si.at_end ()) {
if (si.cell_index () == ci2skip) {
si.skip_cell ();
continue;
}
db::Polygon poly = si->obj ();
poly.transform (si->trans ());
poly.transform (si.trans ());
@@ -766,6 +770,16 @@ TEST(41_HierClustersRecursiveClusterShapeIterator)
}
EXPECT_EQ (n, 1);
EXPECT_EQ (res, "TOP:(0,0;0,1000;1000,1000;1000,0);TOP/C1:(0,10;0,510;2000,510;2000,10);TOP/C2:(0,30;0,2030;500,2030;500,30);TOP/C2/C1:(0,50;0,550;2000,550;2000,50)");
res.clear ();
n = 0;
cluster = &hc.clusters_per_cell (top.cell_index ());
for (db::connected_clusters<db::PolygonRef>::const_iterator i = cluster->begin (); i != cluster->end (); ++i) {
res = rcsiter2string (ly, top.cell_index (), db::recursive_cluster_shape_iterator<db::PolygonRef> (hc, l1, top.cell_index (), i->id ()), c1.cell_index ());
++n;
}
EXPECT_EQ (n, 1);
EXPECT_EQ (res, "TOP:(0,0;0,1000;1000,1000;1000,0);TOP/C2:(0,30;0,2030;500,2030;500,30)");
}
TEST(41_HierClustersRecursiveClusterIterator)
@@ -72,27 +72,33 @@ TEST(1_WriterBasic)
db::Cell &tc = ly.cell (*ly.begin_top_down ());
db::LayoutToNetlist l2n (db::RecursiveShapeIterator (ly, tc, std::set<unsigned int> ()));
std::auto_ptr<db::Region> rnwell (l2n.make_layer (nwell));
std::auto_ptr<db::Region> ractive (l2n.make_layer (active));
std::auto_ptr<db::Region> rpoly (l2n.make_polygon_layer (poly));
std::auto_ptr<db::Region> rpoly_lbl (l2n.make_text_layer (poly_lbl));
std::auto_ptr<db::Region> rdiff_cont (l2n.make_polygon_layer (diff_cont));
std::auto_ptr<db::Region> rpoly_cont (l2n.make_polygon_layer (poly_cont));
std::auto_ptr<db::Region> rmetal1 (l2n.make_polygon_layer (metal1));
std::auto_ptr<db::Region> rmetal1_lbl (l2n.make_text_layer (metal1_lbl));
std::auto_ptr<db::Region> rvia1 (l2n.make_polygon_layer (via1));
std::auto_ptr<db::Region> rmetal2 (l2n.make_polygon_layer (metal2));
std::auto_ptr<db::Region> rmetal2_lbl (l2n.make_text_layer (metal2_lbl));
std::auto_ptr<db::Region> rnwell (l2n.make_layer (nwell, "nwell"));
std::auto_ptr<db::Region> ractive (l2n.make_layer (active, "active"));
std::auto_ptr<db::Region> rpoly (l2n.make_polygon_layer (poly, "poly"));
std::auto_ptr<db::Region> rpoly_lbl (l2n.make_text_layer (poly_lbl, "poly_lbl"));
std::auto_ptr<db::Region> rdiff_cont (l2n.make_polygon_layer (diff_cont, "diff_cont"));
std::auto_ptr<db::Region> rpoly_cont (l2n.make_polygon_layer (poly_cont, "poly_cont"));
std::auto_ptr<db::Region> rmetal1 (l2n.make_polygon_layer (metal1, "metal1"));
std::auto_ptr<db::Region> rmetal1_lbl (l2n.make_text_layer (metal1_lbl, "metal1_lbl"));
std::auto_ptr<db::Region> rvia1 (l2n.make_polygon_layer (via1, "via1"));
std::auto_ptr<db::Region> rmetal2 (l2n.make_polygon_layer (metal2, "metal2"));
std::auto_ptr<db::Region> rmetal2_lbl (l2n.make_text_layer (metal2_lbl, "metal2_lbl"));
// derived regions
db::Region rpactive = *ractive & *rnwell;
db::Region rpgate = rpactive & *rpoly;
db::Region rpsd = rpactive - rpgate;
l2n.name (rpactive, "pactive");
l2n.name (rpgate, "pgate");
l2n.name (rpsd, "psd");
db::Region rnactive = *ractive - *rnwell;
db::Region rngate = rnactive & *rpoly;
db::Region rnsd = rnactive - rngate;
l2n.name (rnactive, "nactive");
l2n.name (rngate, "ngate");
l2n.name (rnsd, "nsd");
db::NetlistDeviceExtractorMOS3Transistor pmos_ex ("PMOS");
db::NetlistDeviceExtractorMOS3Transistor nmos_ex ("NMOS");
@@ -157,18 +163,23 @@ TEST(1_WriterBasic)
rpoly_lbl.reset (0);
l2n.extract_netlist ();
l2n.netlist ()->purge ();
tl::OutputMemoryStream mem;
std::string path = tmp_file ("tmp_l2nwriter_1.txt");
{
tl::OutputStream stream (mem);
tl::OutputStream stream (path);
db::LayoutToNetlistStandardWriter writer (stream);
writer.write (&l2n);
}
// TODO: too big for inlined text ...
#if 0
EXPECT_EQ (std::string (mem.data (), mem.size ()),
""
);
#endif
std::string au_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "l2n_writer_au.txt");
tl::InputStream is (path);
tl::InputStream is_au (au_path);
if (is.read_all () != is_au.read_all ()) {
_this->raise (tl::sprintf ("Compare failed - see\n actual: %s\n golden: %s",
tl::absolute_file_path (path),
tl::absolute_file_path (au_path)));
}
}