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

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 ()
{

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;

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 ());

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

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 ();

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);
};
}

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"

View File

@ -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)

View File

@ -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)));
}
}

477
testdata/algo/l2n_writer_au.txt vendored Normal file
View File

@ -0,0 +1,477 @@
# General section
# Lists general definitions.
top(RINGO)
unit(0.001)
# Layer section
# This section lists the mask layers (drawing or derived) and their connections.
# Mask layers
layer(poly)
layer(poly_lbl)
layer(diff_cont)
layer(poly_cont)
layer(metal1)
layer(metal1_lbl)
layer(via1)
layer(metal2)
layer(metal2_lbl)
layer(psd)
layer(nsd)
# Mask layer connectivity
connect(poly poly poly_lbl poly_cont)
connect(poly_lbl poly)
connect(diff_cont diff_cont metal1 psd nsd)
connect(poly_cont poly poly_cont metal1)
connect(metal1 diff_cont poly_cont metal1 metal1_lbl via1)
connect(metal1_lbl metal1)
connect(via1 metal1 via1 metal2)
connect(metal2 via1 metal2 metal2_lbl)
connect(metal2_lbl metal2)
connect(psd diff_cont psd)
connect(nsd diff_cont nsd)
# Device abstracts section
# Device abstracts list the pin shapes of the devices.
device(D$PMOS PMOS
terminal(S
rect(poly -125 -475 125 475)
)
terminal(G
rect(psd -650 -475 -125 475)
)
terminal(D
rect(psd 125 -475 675 475)
)
)
device(D$PMOS$1 PMOS
terminal(S
rect(poly -125 -475 125 475)
)
terminal(G
rect(psd -675 -475 -125 475)
)
terminal(D
rect(psd 125 -475 650 475)
)
)
device(D$NMOS NMOS
terminal(S
rect(poly -125 -475 125 475)
)
terminal(G
rect(nsd -650 -475 -125 475)
)
terminal(D
rect(nsd 125 -475 675 475)
)
)
device(D$NMOS$1 NMOS
terminal(S
rect(poly -125 -475 125 475)
)
terminal(G
rect(nsd -675 -475 -125 475)
)
terminal(D
rect(nsd 125 -475 650 475)
)
)
# Circuit section
# Circuits are the hierarchical building blocks of the netlist.
# Circuit RINGO
circuit(RINGO
# Nets with their geometries
net(FB
rect(diff_cont 22850 2490 23070 2710)
rect(diff_cont 22850 2890 23070 3110)
rect(diff_cont 22850 -310 23070 -90)
rect(diff_cont 22850 90 23070 310)
rect(metal1 -1700 1620 -1340 1980)
rect(via1 -1645 1675 -1395 1925)
rect(via1 22835 1675 23085 1925)
rect(metal2 -1720 1600 23160 2000)
rect(metal2_lbl -1 1799 1 1801)
)
net(VSS
rect(diff_cont 2530 -310 2750 -90)
rect(diff_cont 2530 90 2750 310)
rect(diff_cont 2530 90 2750 310)
rect(diff_cont 2530 -310 2750 -90)
rect(diff_cont -110 -310 110 -90)
rect(diff_cont -110 90 110 310)
rect(diff_cont -110 90 110 310)
rect(diff_cont -110 -310 110 -90)
rect(diff_cont 5170 -310 5390 -90)
rect(diff_cont 5170 90 5390 310)
rect(diff_cont 5170 90 5390 310)
rect(diff_cont 5170 -310 5390 -90)
rect(diff_cont 7810 -310 8030 -90)
rect(diff_cont 7810 90 8030 310)
rect(diff_cont 7810 90 8030 310)
rect(diff_cont 7810 -310 8030 -90)
rect(diff_cont 10450 -310 10670 -90)
rect(diff_cont 10450 90 10670 310)
rect(diff_cont 10450 90 10670 310)
rect(diff_cont 10450 -310 10670 -90)
rect(diff_cont 13090 -310 13310 -90)
rect(diff_cont 13090 90 13310 310)
rect(diff_cont 13090 90 13310 310)
rect(diff_cont 13090 -310 13310 -90)
rect(diff_cont 15730 -310 15950 -90)
rect(diff_cont 15730 90 15950 310)
rect(diff_cont 15730 90 15950 310)
rect(diff_cont 15730 -310 15950 -90)
rect(diff_cont 18370 -310 18590 -90)
rect(diff_cont 18370 90 18590 310)
rect(diff_cont 18370 90 18590 310)
rect(diff_cont 18370 -310 18590 -90)
rect(diff_cont 21010 -310 21230 -90)
rect(diff_cont 21010 90 21230 310)
rect(diff_cont 21010 90 21230 310)
rect(diff_cont 21010 -310 21230 -90)
rect(diff_cont 23650 -310 23870 -90)
rect(diff_cont 23650 90 23870 310)
rect(diff_cont 23650 90 23870 310)
rect(diff_cont 23650 -310 23870 -90)
rect(metal1 2460 -380 2820 380)
rect(metal1 2460 -380 2820 380)
rect(metal1 -180 -380 180 380)
rect(metal1 -180 -380 180 380)
rect(metal1 5100 -380 5460 380)
rect(metal1 5100 -380 5460 380)
rect(metal1 7740 -380 8100 380)
rect(metal1 7740 -380 8100 380)
rect(metal1 10380 -380 10740 380)
rect(metal1 10380 -380 10740 380)
rect(metal1 13020 -380 13380 380)
rect(metal1 13020 -380 13380 380)
rect(metal1 15660 -380 16020 380)
rect(metal1 15660 -380 16020 380)
rect(metal1 18300 -380 18660 380)
rect(metal1 18300 -380 18660 380)
rect(metal1 20940 -380 21300 380)
rect(metal1 20940 -380 21300 380)
rect(metal1 23580 -380 23940 380)
rect(metal1 23580 -380 23940 380)
rect(metal2_lbl -1 -1 1 1)
)
net(VDD
rect(diff_cont 2530 2490 2750 2710)
rect(diff_cont 2530 2890 2750 3110)
rect(diff_cont 2530 2890 2750 3110)
rect(diff_cont 2530 2490 2750 2710)
rect(diff_cont -110 2490 110 2710)
rect(diff_cont -110 2890 110 3110)
rect(diff_cont -110 2890 110 3110)
rect(diff_cont -110 2490 110 2710)
rect(diff_cont 5170 2490 5390 2710)
rect(diff_cont 5170 2890 5390 3110)
rect(diff_cont 5170 2890 5390 3110)
rect(diff_cont 5170 2490 5390 2710)
rect(diff_cont 7810 2490 8030 2710)
rect(diff_cont 7810 2890 8030 3110)
rect(diff_cont 7810 2890 8030 3110)
rect(diff_cont 7810 2490 8030 2710)
rect(diff_cont 10450 2490 10670 2710)
rect(diff_cont 10450 2890 10670 3110)
rect(diff_cont 10450 2890 10670 3110)
rect(diff_cont 10450 2490 10670 2710)
rect(diff_cont 13090 2490 13310 2710)
rect(diff_cont 13090 2890 13310 3110)
rect(diff_cont 13090 2890 13310 3110)
rect(diff_cont 13090 2490 13310 2710)
rect(diff_cont 15730 2490 15950 2710)
rect(diff_cont 15730 2890 15950 3110)
rect(diff_cont 15730 2890 15950 3110)
rect(diff_cont 15730 2490 15950 2710)
rect(diff_cont 18370 2490 18590 2710)
rect(diff_cont 18370 2890 18590 3110)
rect(diff_cont 18370 2890 18590 3110)
rect(diff_cont 18370 2490 18590 2710)
rect(diff_cont 21010 2490 21230 2710)
rect(diff_cont 21010 2890 21230 3110)
rect(diff_cont 21010 2890 21230 3110)
rect(diff_cont 21010 2490 21230 2710)
rect(diff_cont 23650 2490 23870 2710)
rect(diff_cont 23650 2890 23870 3110)
rect(diff_cont 23650 2890 23870 3110)
rect(diff_cont 23650 2490 23870 2710)
rect(metal1 2460 2420 2820 3180)
rect(metal1 2460 2420 2820 3180)
rect(metal1 -180 2420 180 3180)
rect(metal1 -180 2420 180 3180)
rect(metal1 5100 2420 5460 3180)
rect(metal1 5100 2420 5460 3180)
rect(metal1 7740 2420 8100 3180)
rect(metal1 7740 2420 8100 3180)
rect(metal1 10380 2420 10740 3180)
rect(metal1 10380 2420 10740 3180)
rect(metal1 13020 2420 13380 3180)
rect(metal1 13020 2420 13380 3180)
rect(metal1 15660 2420 16020 3180)
rect(metal1 15660 2420 16020 3180)
rect(metal1 18300 2420 18660 3180)
rect(metal1 18300 2420 18660 3180)
rect(metal1 20940 2420 21300 3180)
rect(metal1 20940 2420 21300 3180)
rect(metal1 23580 2420 23940 3180)
rect(metal1 23580 2420 23940 3180)
rect(metal2_lbl -1 2799 1 2801)
)
net($I19
rect(diff_cont 690 2890 910 3110)
rect(diff_cont 690 2490 910 2710)
rect(diff_cont 690 90 910 310)
rect(diff_cont 690 -310 910 -90)
)
net($I8
rect(diff_cont 21810 2890 22030 3110)
rect(diff_cont 21810 2490 22030 2710)
rect(diff_cont 21810 90 22030 310)
rect(diff_cont 21810 -310 22030 -90)
)
net($I7
rect(diff_cont 19170 2890 19390 3110)
rect(diff_cont 19170 2490 19390 2710)
rect(diff_cont 19170 90 19390 310)
rect(diff_cont 19170 -310 19390 -90)
)
net($I6
rect(diff_cont 16530 2890 16750 3110)
rect(diff_cont 16530 2490 16750 2710)
rect(diff_cont 16530 90 16750 310)
rect(diff_cont 16530 -310 16750 -90)
)
net($I5
rect(diff_cont 13890 2890 14110 3110)
rect(diff_cont 13890 2490 14110 2710)
rect(diff_cont 13890 90 14110 310)
rect(diff_cont 13890 -310 14110 -90)
)
net($I4
rect(diff_cont 11250 2890 11470 3110)
rect(diff_cont 11250 2490 11470 2710)
rect(diff_cont 11250 90 11470 310)
rect(diff_cont 11250 -310 11470 -90)
)
net($I3
rect(diff_cont 8610 2890 8830 3110)
rect(diff_cont 8610 2490 8830 2710)
rect(diff_cont 8610 90 8830 310)
rect(diff_cont 8610 -310 8830 -90)
)
net($I2
rect(diff_cont 5970 2890 6190 3110)
rect(diff_cont 5970 2490 6190 2710)
rect(diff_cont 5970 90 6190 310)
rect(diff_cont 5970 -310 6190 -90)
)
net($I1
rect(diff_cont 3330 2890 3550 3110)
rect(diff_cont 3330 2490 3550 2710)
rect(diff_cont 3330 90 3550 310)
rect(diff_cont 3330 -310 3550 -90)
)
# Subcircuits and their connections
subcircuit($1 location(23760 0)
pin(IN $I8)
pin($1 FB)
pin($3 VSS)
pin($4 VDD)
)
subcircuit($2 location(0 0)
pin(IN FB)
pin(OUT $I19)
pin($3 VSS)
pin($4 VDD)
)
subcircuit($3 location(2640 0)
pin(IN $I19)
pin(OUT $I1)
pin($3 VSS)
pin($4 VDD)
)
subcircuit($4 location(5280 0)
pin(IN $I1)
pin(OUT $I2)
pin($3 VSS)
pin($4 VDD)
)
subcircuit($5 location(7920 0)
pin(IN $I2)
pin(OUT $I3)
pin($3 VSS)
pin($4 VDD)
)
subcircuit($6 location(10560 0)
pin(IN $I3)
pin(OUT $I4)
pin($3 VSS)
pin($4 VDD)
)
subcircuit($7 location(13200 0)
pin(IN $I4)
pin(OUT $I5)
pin($3 VSS)
pin($4 VDD)
)
subcircuit($8 location(15840 0)
pin(IN $I5)
pin(OUT $I6)
pin($3 VSS)
pin($4 VDD)
)
subcircuit($9 location(18480 0)
pin(IN $I6)
pin(OUT $I7)
pin($3 VSS)
pin($4 VDD)
)
subcircuit($10 location(21120 0)
pin(IN $I7)
pin(OUT $I8)
pin($3 VSS)
pin($4 VDD)
)
)
# Circuit INV2
circuit(INV2
# Nets with their geometries
net(IN
rect(poly -525 -250 -275 2250)
rect(poly -1700 1620 -400 1980)
rect(poly -525 -800 -275 800)
rect(poly -525 -475 -275 475)
rect(poly -525 2000 -275 3600)
rect(poly -525 2325 -275 3275)
rect(poly_lbl -801 1799 -799 1801)
rect(poly_cont -1630 1690 -1410 1910)
)
net($2
rect(poly 275 -250 525 2250)
rect(poly 220 820 580 1180)
rect(poly 275 2000 525 3600)
rect(poly 275 2325 525 3275)
rect(poly 275 -800 525 800)
rect(poly 275 -475 525 475)
rect(diff_cont -910 2490 -690 2710)
rect(diff_cont -910 2890 -690 3110)
rect(diff_cont -910 -310 -690 -90)
rect(diff_cont -910 90 -690 310)
rect(poly_cont 290 890 510 1110)
rect(metal1 -800 820 580 1180)
rect(metal1 -980 -420 -620 2420)
rect(metal1 -980 2420 -620 3180)
rect(metal1 -980 -380 -620 380)
rect(psd -1050 2325 -525 3275)
rect(psd -1050 2325 -525 3275)
rect(nsd -1050 -475 -525 475)
rect(nsd -1050 -475 -525 475)
)
net(OUT
rect(diff_cont 690 2890 910 3110)
rect(diff_cont 690 2490 910 2710)
rect(diff_cont 690 90 910 310)
rect(diff_cont 690 -310 910 -90)
polygon(metal1 800 20 800 380 940 380 940 1620 620 1620 620 2420 980 2420 980 1980 1300 1980 1300 20)
rect(metal1 620 2420 980 3180)
rect(metal1 620 -380 980 380)
rect(metal1_lbl 799 1799 801 1801)
rect(psd 525 2325 1050 3275)
rect(psd 525 2325 1050 3275)
rect(nsd 525 -475 1050 475)
rect(nsd 525 -475 1050 475)
)
net($4
rect(diff_cont -110 -310 110 -90)
rect(diff_cont -110 90 110 310)
rect(diff_cont -110 90 110 310)
rect(diff_cont -110 -310 110 -90)
rect(metal1 -180 -380 180 380)
rect(metal1 -180 -380 180 380)
rect(via1 -125 -325 125 -75)
rect(via1 -125 75 125 325)
rect(metal2 -1400 -450 1400 450)
rect(nsd -275 -475 275 475)
rect(nsd -275 -475 275 475)
rect(nsd -275 -475 275 475)
)
net($5
rect(diff_cont -110 2490 110 2710)
rect(diff_cont -110 2890 110 3110)
rect(diff_cont -110 2890 110 3110)
rect(diff_cont -110 2490 110 2710)
rect(metal1 -180 2420 180 3180)
rect(metal1 -180 2420 180 3180)
rect(via1 -125 2475 125 2725)
rect(via1 -125 2875 125 3125)
rect(metal2 -1400 2350 1400 3250)
rect(psd -275 2325 275 3275)
rect(psd -275 2325 275 3275)
rect(psd -275 2325 275 3275)
)
# Outgoing pins and their connections to nets
pin(IN IN)
pin($1 $2)
pin(OUT OUT)
pin($3 $4)
pin($4 $5)
# Devices and their connections
device($1 PMOS
location(-400 2800)
abstract(D$PMOS)
param(L 0.25)
param(W 0.95)
param(AS 0.49875)
param(AD 0.26125)
terminal(S $2)
terminal(G IN)
terminal(D $5)
)
device($2 PMOS
location(400 2800)
abstract(D$PMOS$1)
param(L 0.25)
param(W 0.95)
param(AS 0.26125)
param(AD 0.49875)
terminal(S $5)
terminal(G $2)
terminal(D OUT)
)
device($3 NMOS
location(-400 0)
abstract(D$NMOS)
param(L 0.25)
param(W 0.95)
param(AS 0.49875)
param(AD 0.26125)
terminal(S $2)
terminal(G IN)
terminal(D $4)
)
device($4 NMOS
location(400 0)
abstract(D$NMOS$1)
param(L 0.25)
param(W 0.95)
param(AS 0.26125)
param(AD 0.49875)
terminal(S $4)
terminal(G $2)
terminal(D OUT)
)
)