mirror of https://github.com/KLayout/klayout.git
WIP: l2n reader implementation, some bug fixes, refactoring.
This commit is contained in:
parent
56bb39a273
commit
8213e71a79
|
|
@ -161,7 +161,8 @@ SOURCES = \
|
|||
dbPin.cc \
|
||||
dbLayoutToNetlistReader.cc \
|
||||
dbLayoutToNetlistWriter.cc \
|
||||
dbDeviceModel.cc
|
||||
dbDeviceModel.cc \
|
||||
dbLayoutToNetlistFormatDefs.cc
|
||||
|
||||
HEADERS = \
|
||||
dbArray.h \
|
||||
|
|
@ -287,7 +288,8 @@ HEADERS = \
|
|||
dbSubCircuit.h \
|
||||
dbLayoutToNetlistReader.h \
|
||||
dbLayoutToNetlistWriter.h \
|
||||
dbDeviceModel.h
|
||||
dbDeviceModel.h \
|
||||
dbLayoutToNetlistFormatDefs.h
|
||||
|
||||
!equals(HAVE_QT, "0") {
|
||||
|
||||
|
|
|
|||
|
|
@ -1664,11 +1664,6 @@ template <class T>
|
|||
void
|
||||
hier_clusters<T>::build_local_cluster (const db::Layout &layout, const db::Cell &cell, db::ShapeIterator::flags_type shape_flags, const db::Connectivity &conn)
|
||||
{
|
||||
if (m_per_cell_clusters.find (cell.cell_index ()) != m_per_cell_clusters.end ()) {
|
||||
// skip pre-build clusters (from devices)
|
||||
return;
|
||||
}
|
||||
|
||||
std::string msg = tl::to_string (tr ("Computing local clusters for cell: ")) + std::string (layout.cell_name (cell.cell_index ()));
|
||||
if (tl::verbosity () >= 40) {
|
||||
tl::log << msg;
|
||||
|
|
|
|||
|
|
@ -78,6 +78,18 @@ size_t LayoutToNetlist::max_vertex_count () const
|
|||
return m_dss.max_vertex_count ();
|
||||
}
|
||||
|
||||
db::Region *LayoutToNetlist::make_layer (const std::string &n)
|
||||
{
|
||||
db::RecursiveShapeIterator si (m_iter);
|
||||
si.shape_flags (db::ShapeIterator::Nothing);
|
||||
|
||||
db::Region *region = new db::Region (si, m_dss);
|
||||
if (! n.empty ()) {
|
||||
name (*region, n);
|
||||
}
|
||||
return region;
|
||||
}
|
||||
|
||||
db::Region *LayoutToNetlist::make_layer (unsigned int layer_index, const std::string &n)
|
||||
{
|
||||
db::RecursiveShapeIterator si (m_iter);
|
||||
|
|
@ -199,8 +211,6 @@ void LayoutToNetlist::extract_netlist ()
|
|||
mp_netlist.reset (new db::Netlist ());
|
||||
}
|
||||
|
||||
m_net_clusters.clear ();
|
||||
|
||||
db::NetlistExtractor netex;
|
||||
netex.extract_nets(m_dss, m_conn, *mp_netlist, m_net_clusters);
|
||||
|
||||
|
|
@ -217,6 +227,16 @@ const db::Cell *LayoutToNetlist::internal_top_cell () const
|
|||
return &m_dss.const_initial_cell ();
|
||||
}
|
||||
|
||||
db::Layout *LayoutToNetlist::internal_layout ()
|
||||
{
|
||||
return &m_dss.layout ();
|
||||
}
|
||||
|
||||
db::Cell *LayoutToNetlist::internal_top_cell ()
|
||||
{
|
||||
return &m_dss.initial_cell ();
|
||||
}
|
||||
|
||||
void LayoutToNetlist::name (const db::Region ®ion, const std::string &name)
|
||||
{
|
||||
unsigned int li = layer_of (region);
|
||||
|
|
@ -269,6 +289,15 @@ db::Netlist *LayoutToNetlist::netlist () const
|
|||
return mp_netlist.get ();
|
||||
}
|
||||
|
||||
db::Netlist *LayoutToNetlist::make_netlist ()
|
||||
{
|
||||
if (! mp_netlist.get ()) {
|
||||
mp_netlist.reset (new db::Netlist ());
|
||||
}
|
||||
return mp_netlist.get ();
|
||||
}
|
||||
|
||||
|
||||
template <class Tr>
|
||||
static void deliver_shape (const db::PolygonRef &pr, db::Region ®ion, const Tr &tr)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -133,6 +133,11 @@ public:
|
|||
return internal_layout ()->get_properties (layer_of (region)).name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Creates a new empty region
|
||||
*/
|
||||
db::Region *make_layer (const std::string &n);
|
||||
|
||||
/**
|
||||
* @brief Creates a new region representing an original layer
|
||||
* "layer_index" is the layer index of the desired layer in the original layout.
|
||||
|
|
@ -216,6 +221,16 @@ public:
|
|||
*/
|
||||
const db::Cell *internal_top_cell () const;
|
||||
|
||||
/**
|
||||
* @brief Gets the internal layout (non-const version)
|
||||
*/
|
||||
db::Layout *internal_layout ();
|
||||
|
||||
/**
|
||||
* @brief Gets the internal top cell (non-const version)
|
||||
*/
|
||||
db::Cell *internal_top_cell ();
|
||||
|
||||
/**
|
||||
* @brief Gets the connectivity object
|
||||
*/
|
||||
|
|
@ -251,6 +266,11 @@ public:
|
|||
*/
|
||||
db::Netlist *netlist () const;
|
||||
|
||||
/**
|
||||
* @brief gets the netlist extracted or make on if none exists yet.
|
||||
*/
|
||||
db::Netlist *make_netlist ();
|
||||
|
||||
/**
|
||||
* @brief Gets the hierarchical shape clusters derived in the net extraction.
|
||||
* NOTE: the layer and cell indexes used inside this structure refer to the
|
||||
|
|
@ -261,6 +281,14 @@ public:
|
|||
return m_net_clusters;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the hierarchical shape clusters derived in the net extraction (non-conver version)
|
||||
*/
|
||||
db::hier_clusters<db::PolygonRef> &net_clusters ()
|
||||
{
|
||||
return m_net_clusters;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns all shapes of a specific net and layer.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -0,0 +1,73 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2019 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#include "dbLayoutToNetlistFormatDefs.h"
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
namespace l2n_std_format
|
||||
{
|
||||
template<> DB_PUBLIC const std::string keys<false>::version_key ("version");
|
||||
template<> DB_PUBLIC const std::string keys<false>::description_key ("description");
|
||||
template<> DB_PUBLIC const std::string keys<false>::top_key ("top");
|
||||
template<> DB_PUBLIC const std::string keys<false>::unit_key ("unit");
|
||||
template<> DB_PUBLIC const std::string keys<false>::layer_key ("layer");
|
||||
template<> DB_PUBLIC const std::string keys<false>::connect_key ("connect");
|
||||
template<> DB_PUBLIC const std::string keys<false>::global_key ("global");
|
||||
template<> DB_PUBLIC const std::string keys<false>::circuit_key ("circuit");
|
||||
template<> DB_PUBLIC const std::string keys<false>::net_key ("net");
|
||||
template<> DB_PUBLIC const std::string keys<false>::device_key ("device");
|
||||
template<> DB_PUBLIC const std::string keys<false>::polygon_key ("polygon");
|
||||
template<> DB_PUBLIC const std::string keys<false>::rect_key ("rect");
|
||||
template<> DB_PUBLIC const std::string keys<false>::terminal_key ("terminal");
|
||||
template<> DB_PUBLIC const std::string keys<false>::abstract_key ("abstract");
|
||||
template<> DB_PUBLIC const std::string keys<false>::param_key ("param");
|
||||
template<> DB_PUBLIC const std::string keys<false>::location_key ("location");
|
||||
template<> DB_PUBLIC const std::string keys<false>::rotation_key ("rotation");
|
||||
template<> DB_PUBLIC const std::string keys<false>::mirror_key ("mirror");
|
||||
template<> DB_PUBLIC const std::string keys<false>::scale_key ("scale");
|
||||
template<> DB_PUBLIC const std::string keys<false>::pin_key ("pin");
|
||||
|
||||
template<> DB_PUBLIC const std::string keys<true>::version_key ("V");
|
||||
template<> DB_PUBLIC const std::string keys<true>::description_key ("B");
|
||||
template<> DB_PUBLIC const std::string keys<true>::top_key ("W");
|
||||
template<> DB_PUBLIC const std::string keys<true>::unit_key ("U");
|
||||
template<> DB_PUBLIC const std::string keys<true>::layer_key ("L");
|
||||
template<> DB_PUBLIC const std::string keys<true>::connect_key ("C");
|
||||
template<> DB_PUBLIC const std::string keys<true>::global_key ("G");
|
||||
template<> DB_PUBLIC const std::string keys<true>::circuit_key ("X");
|
||||
template<> DB_PUBLIC const std::string keys<true>::net_key ("N");
|
||||
template<> DB_PUBLIC const std::string keys<true>::device_key ("D");
|
||||
template<> DB_PUBLIC const std::string keys<true>::polygon_key ("Q");
|
||||
template<> DB_PUBLIC const std::string keys<true>::rect_key ("R");
|
||||
template<> DB_PUBLIC const std::string keys<true>::terminal_key ("T");
|
||||
template<> DB_PUBLIC const std::string keys<true>::abstract_key ("A");
|
||||
template<> DB_PUBLIC const std::string keys<true>::param_key ("E");
|
||||
template<> DB_PUBLIC const std::string keys<true>::location_key ("Y");
|
||||
template<> DB_PUBLIC const std::string keys<true>::rotation_key ("O");
|
||||
template<> DB_PUBLIC const std::string keys<true>::mirror_key ("M");
|
||||
template<> DB_PUBLIC const std::string keys<true>::scale_key ("S");
|
||||
template<> DB_PUBLIC const std::string keys<true>::pin_key ("P");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,118 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2019 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#ifndef HDR_dbLayoutToNetlistFormatDefs
|
||||
#define HDR_dbLayoutToNetlistFormatDefs
|
||||
|
||||
#include "dbCommon.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
/**
|
||||
* This is the internal persistency format for LayoutToNetlist
|
||||
*
|
||||
* It's intentionally *not* XML to keep the overhead low.
|
||||
*
|
||||
* Comments are introduced by hash: # ...
|
||||
* Names are words (alphanumerical plus "$", "_", ".") or enclosed in single or double quotes.
|
||||
* Escape character is backslash.
|
||||
* Separator is either , or whitespace. Keywords and names are case sensitive.
|
||||
* Short keys are provided for compacter representation. Short keys can be
|
||||
* non-alpha (e.g. "*") or empty.
|
||||
* Single-valued attributes can be given without brackets.
|
||||
* All dimensions are in units of database unit.
|
||||
* The file follows the declaration-before-use principle
|
||||
* (circuits before subcircuits, nets before use ...)
|
||||
*
|
||||
* Global statements:
|
||||
*
|
||||
* version(<number>) - file format version [short key: V]
|
||||
* description(<text>) - an arbitrary description text [short key: B]
|
||||
* unit(<unit>) - specifies the database unit [short key: U]
|
||||
* top(<circuit>) - specifies the name of the top circuit [short key: W]
|
||||
* layer(<name>) - define a layer [short key: L]
|
||||
* 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-abstract-def])
|
||||
* - device abstract [short key: D]
|
||||
*
|
||||
* [circuit-def]:
|
||||
*
|
||||
* net(<name> [geometry-def]) - net geometry [short key: N]
|
||||
* A net declaration shall be there also if no geometry
|
||||
* is present
|
||||
* pin(<name> <net-name>) - outgoing pin connection [short key: P]
|
||||
* device(<name> <abstract> [device-def])
|
||||
* - device with connections [short key: D]
|
||||
* circuit(<name> [circuit-def]) - subcircuit with connections [short key: X]
|
||||
*
|
||||
* [geometry-def]:
|
||||
*
|
||||
* polygon(<layer> <x> <y> ...) - defines a polygon [short key: Q]
|
||||
* rect(<layer> <left> <bottom> <right> <top>)
|
||||
* - defines a rectangle [short key: R]
|
||||
*
|
||||
* [device-abstract-def]:
|
||||
*
|
||||
* terminal(<terminal-name> [geometry-def])
|
||||
* - specifies the terminal geometry [short key: T]
|
||||
*
|
||||
* [device-def]:
|
||||
*
|
||||
* location(<x> <y>) - location of the device [short key Y]
|
||||
* must be before terminal
|
||||
* param(<name> <value>) - defines a parameter [short key E]
|
||||
* terminal(<terminal-name> <net-name>)
|
||||
* - specifies connection of the terminal with
|
||||
* a net (short key: T)
|
||||
*
|
||||
* [subcircuit-def]:
|
||||
*
|
||||
* location(<x> <y>) - location of the subcircuit [short key Y]
|
||||
* rotation(<angle>) - rotation angle (in degree, default is 0) [short key O]
|
||||
* mirror - if specified, the instance is mirrored before rotation [short key M]
|
||||
* scale(<mag>) - magnification (default is 1) [short key S]
|
||||
* pin(<pin-name> <net-name>) - specifies connection of the pin with a net [short key: P]
|
||||
*/
|
||||
|
||||
namespace l2n_std_format
|
||||
{
|
||||
template <bool Short>
|
||||
struct DB_PUBLIC keys
|
||||
{
|
||||
static const std::string version_key, description_key, top_key, unit_key,
|
||||
layer_key, connect_key, global_key,
|
||||
circuit_key, net_key, device_key, subcircuit_key,
|
||||
polygon_key, rect_key, terminal_key, abstract_key,
|
||||
param_key, location_key, rotation_key,
|
||||
mirror_key, scale_key, pin_key,
|
||||
indent1, indent2;
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -21,10 +21,698 @@
|
|||
*/
|
||||
|
||||
#include "dbLayoutToNetlistReader.h"
|
||||
#include "dbLayoutToNetlistFormatDefs.h"
|
||||
#include "dbLayoutToNetlist.h"
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
namespace l2n_std_reader {
|
||||
|
||||
class Layers
|
||||
{
|
||||
public:
|
||||
Layers () { }
|
||||
|
||||
~Layers ()
|
||||
{
|
||||
for (std::map<std::string, db::Region *>::const_iterator i = m_layers.begin (); i != m_layers.end (); ++i) {
|
||||
delete i->second;
|
||||
}
|
||||
m_layers.clear ();
|
||||
}
|
||||
|
||||
void add (const std::string &name, db::Region *region)
|
||||
{
|
||||
if (m_layers.find (name) != m_layers.end ()) {
|
||||
delete region;
|
||||
throw tl::Exception (tl::to_string (tr ("Duplicate layer name: ")) + name);
|
||||
}
|
||||
m_layers.insert (std::make_pair (name, region));
|
||||
}
|
||||
|
||||
db::Region &layer (const std::string &name)
|
||||
{
|
||||
std::map<std::string, db::Region *>::const_iterator l = m_layers.find (name);
|
||||
if (l == m_layers.end ()) {
|
||||
throw tl::Exception (tl::to_string (tr ("Not a valid layer name: ")) + name);
|
||||
}
|
||||
return *l->second;
|
||||
}
|
||||
|
||||
private:
|
||||
std::map<std::string, db::Region *> m_layers;
|
||||
};
|
||||
|
||||
class Brace
|
||||
{
|
||||
public:
|
||||
Brace (LayoutToNetlistStandardReader *reader) : mp_reader (reader), m_checked (false)
|
||||
{
|
||||
m_has_brace = reader->test ("(");
|
||||
}
|
||||
|
||||
operator bool ()
|
||||
{
|
||||
if (! m_has_brace) {
|
||||
m_checked = true;
|
||||
return false;
|
||||
} else if (mp_reader->test (")")) {
|
||||
m_checked = true;
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void done ()
|
||||
{
|
||||
if (m_has_brace && ! m_checked) {
|
||||
mp_reader->expect (")");
|
||||
m_checked = true;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
LayoutToNetlistStandardReader *mp_reader;
|
||||
bool m_checked;
|
||||
bool m_has_brace;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
typedef l2n_std_format::keys<true> skeys;
|
||||
typedef l2n_std_format::keys<false> lkeys;
|
||||
|
||||
LayoutToNetlistStandardReader::LayoutToNetlistStandardReader (tl::InputStream &stream)
|
||||
: m_stream (stream), m_path (stream.absolute_path ())
|
||||
{
|
||||
skip ();
|
||||
}
|
||||
|
||||
bool
|
||||
LayoutToNetlistStandardReader::test (const std::string &token)
|
||||
{
|
||||
skip ();
|
||||
return ! at_end () && m_ex.test (token.c_str ());
|
||||
}
|
||||
|
||||
void
|
||||
LayoutToNetlistStandardReader::expect (const std::string &token)
|
||||
{
|
||||
m_ex.expect (token.c_str ());
|
||||
}
|
||||
|
||||
void
|
||||
LayoutToNetlistStandardReader::read_word_or_quoted (std::string &s)
|
||||
{
|
||||
m_ex.read_word_or_quoted (s);
|
||||
}
|
||||
|
||||
int
|
||||
LayoutToNetlistStandardReader::read_int ()
|
||||
{
|
||||
int i = 0;
|
||||
m_ex.read (i);
|
||||
return i;
|
||||
}
|
||||
|
||||
db::Coord
|
||||
LayoutToNetlistStandardReader::read_coord ()
|
||||
{
|
||||
db::Coord i = 0;
|
||||
m_ex.read (i);
|
||||
return i;
|
||||
}
|
||||
|
||||
double
|
||||
LayoutToNetlistStandardReader::read_double ()
|
||||
{
|
||||
double d = 0;
|
||||
m_ex.read (d);
|
||||
return d;
|
||||
}
|
||||
|
||||
bool
|
||||
LayoutToNetlistStandardReader::at_end ()
|
||||
{
|
||||
return (m_ex.at_end () && m_stream.at_end ());
|
||||
}
|
||||
|
||||
void
|
||||
LayoutToNetlistStandardReader::skip ()
|
||||
{
|
||||
while (m_ex.at_end () || *m_ex.skip () == '#') {
|
||||
if (m_stream.at_end ()) {
|
||||
return;
|
||||
}
|
||||
m_line = m_stream.get_line ();
|
||||
m_ex = tl::Extractor (m_line.c_str ());
|
||||
}
|
||||
}
|
||||
|
||||
void LayoutToNetlistStandardReader::read (db::LayoutToNetlist *l2n)
|
||||
{
|
||||
try {
|
||||
do_read (l2n);
|
||||
} catch (tl::Exception &ex) {
|
||||
throw tl::Exception (tl::sprintf (tl::to_string (tr ("%s in line: %d of %s")), ex.msg (), m_stream.line_number (), m_path));
|
||||
}
|
||||
}
|
||||
|
||||
void LayoutToNetlistStandardReader::do_read (db::LayoutToNetlist *l2n)
|
||||
{
|
||||
int version = 0;
|
||||
std::string description;
|
||||
|
||||
// TODO: there probably is a more efficient way to force the layout inside l2n to be made
|
||||
l2n->make_layer (std::string ());
|
||||
tl_assert (l2n->internal_layout ());
|
||||
|
||||
l2n->make_netlist ();
|
||||
|
||||
Layers layers;
|
||||
|
||||
while (! at_end ()) {
|
||||
|
||||
if (test (skeys::version_key) || test (lkeys::version_key)) {
|
||||
|
||||
Brace br (this);
|
||||
version = read_int ();
|
||||
br.done ();
|
||||
|
||||
} else if (test (skeys::description_key) || test (lkeys::description_key)) {
|
||||
|
||||
Brace br (this);
|
||||
read_word_or_quoted (description);
|
||||
br.done ();
|
||||
|
||||
} else if (test (skeys::unit_key) || test (lkeys::unit_key)) {
|
||||
|
||||
Brace br (this);
|
||||
double dbu = read_double ();
|
||||
l2n->internal_layout ()->dbu (dbu);
|
||||
br.done ();
|
||||
|
||||
} else if (test (skeys::top_key) || test (lkeys::top_key)) {
|
||||
|
||||
Brace br (this);
|
||||
std::string top;
|
||||
read_word_or_quoted (top);
|
||||
l2n->internal_layout ()->rename_cell (l2n->internal_top_cell ()->cell_index (), top.c_str ());
|
||||
br.done ();
|
||||
|
||||
} else if (test (skeys::layer_key) || test (lkeys::layer_key)) {
|
||||
|
||||
Brace br (this);
|
||||
std::string layer;
|
||||
read_word_or_quoted (layer);
|
||||
layers.add (layer, l2n->make_layer (layer));
|
||||
br.done ();
|
||||
|
||||
} else if (test (skeys::connect_key) || test (lkeys::connect_key)) {
|
||||
|
||||
Brace br (this);
|
||||
std::string l1;
|
||||
read_word_or_quoted (l1);
|
||||
while (br) {
|
||||
std::string l2;
|
||||
read_word_or_quoted (l2);
|
||||
l2n->connect (layers.layer (l1), layers.layer (l2));
|
||||
}
|
||||
br.done ();
|
||||
|
||||
} else if (test (skeys::global_key) || test (lkeys::global_key)) {
|
||||
|
||||
Brace br (this);
|
||||
std::string l1;
|
||||
read_word_or_quoted (l1);
|
||||
while (br) {
|
||||
std::string g;
|
||||
read_word_or_quoted (g);
|
||||
l2n->connect_global (layers.layer (l1), g);
|
||||
}
|
||||
br.done ();
|
||||
|
||||
} else if (test (skeys::circuit_key) || test (lkeys::circuit_key)) {
|
||||
|
||||
Brace br (this);
|
||||
std::string name;
|
||||
read_word_or_quoted (name);
|
||||
|
||||
db::Circuit *circuit = new db::Circuit ();
|
||||
circuit->set_name (name);
|
||||
l2n->netlist ()->add_circuit (circuit);
|
||||
|
||||
db::Layout *ly = l2n->internal_layout ();
|
||||
db::cell_index_type ci = ly->add_cell (name.c_str ());
|
||||
circuit->set_cell_index (ci);
|
||||
|
||||
std::map<db::CellInstArray, std::list<Connections> > connections;
|
||||
|
||||
while (br) {
|
||||
|
||||
if (test (skeys::net_key) || test (lkeys::net_key)) {
|
||||
read_net (l2n, circuit, layers);
|
||||
} else if (test (skeys::pin_key) || test (lkeys::pin_key)) {
|
||||
read_pin (l2n, circuit);
|
||||
} else if (test (skeys::device_key) || test (lkeys::device_key)) {
|
||||
std::list<Connections> conn;
|
||||
db::CellInstArray ia = read_device (l2n, circuit, conn);
|
||||
connections[ia] = conn;
|
||||
} else if (test (skeys::circuit_key) || test (lkeys::circuit_key)) {
|
||||
std::list<Connections> conn;
|
||||
db::CellInstArray ia = read_subcircuit (l2n, circuit, conn);
|
||||
connections[ia] = conn;
|
||||
} else {
|
||||
throw tl::Exception (tl::to_string (tr ("Invalid keyword inside circuit definition (net, pin, device or circuit expected)")));
|
||||
}
|
||||
|
||||
}
|
||||
br.done ();
|
||||
|
||||
db::Cell &ccell = ly->cell (ci);
|
||||
|
||||
// connections needs to be made after the instances (because in a readonly Instances container
|
||||
// the Instance pointers will invalidate when new instances are added)
|
||||
for (db::Cell::const_iterator i = ccell.begin (); ! i.at_end (); ++i) {
|
||||
std::map<db::CellInstArray, std::list<Connections> >::const_iterator c = connections.find (i->cell_inst ());
|
||||
if (c != connections.end ()) {
|
||||
for (std::list<Connections>::const_iterator j = c->second.begin (); j != c->second.end (); ++j) {
|
||||
l2n->net_clusters ().clusters_per_cell (ci).add_connection (j->from_cluster, db::ClusterInstance (j->to_cluster, *i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else if (test (skeys::device_key) || test (lkeys::device_key)) {
|
||||
|
||||
Brace br (this);
|
||||
std::string name;
|
||||
read_word_or_quoted (name);
|
||||
|
||||
db::DeviceModel *dm = new db::DeviceModel ();
|
||||
dm->set_name (name);
|
||||
l2n->netlist ()->add_device_model (dm);
|
||||
|
||||
db::cell_index_type ci = l2n->internal_layout ()->add_cell (name.c_str ());
|
||||
dm->set_cell_index (ci);
|
||||
|
||||
std::string cls;
|
||||
read_word_or_quoted (cls);
|
||||
|
||||
db::DeviceClass *dc = 0;
|
||||
for (db::Netlist::device_class_iterator i = l2n->netlist ()->begin_device_classes (); i != l2n->netlist ()->end_device_classes (); ++i) {
|
||||
if (i->name () == cls) {
|
||||
dc = i.operator-> ();
|
||||
}
|
||||
}
|
||||
|
||||
// use a generic device class unless the right one is registered already.
|
||||
bool gen_dc = (dc == 0);
|
||||
if (gen_dc) {
|
||||
dc = new db::DeviceClass ();
|
||||
dc->set_name (cls);
|
||||
l2n->netlist ()->add_device_class (dc);
|
||||
}
|
||||
|
||||
dm->set_device_class (dc);
|
||||
|
||||
while (br) {
|
||||
|
||||
if (test (skeys::terminal_key) || test (lkeys::terminal_key)) {
|
||||
read_abstract_terminal (l2n, dm, gen_dc ? dc : 0, layers);
|
||||
} else {
|
||||
throw tl::Exception (tl::to_string (tr ("Invalid keyword inside device abstract definition (terminal expected)")));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
br.done ();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<unsigned int, db::PolygonRef>
|
||||
LayoutToNetlistStandardReader::read_geometry (db::LayoutToNetlist *l2n, Layers &layers)
|
||||
{
|
||||
std::string lname;
|
||||
|
||||
if (test (skeys::rect_key) || test (lkeys::rect_key)) {
|
||||
|
||||
Brace br (this);
|
||||
|
||||
read_word_or_quoted (lname);
|
||||
unsigned int lid = l2n->layer_of (layers.layer (lname));
|
||||
|
||||
db::Coord l = read_coord ();
|
||||
db::Coord b = read_coord ();
|
||||
db::Coord r = read_coord ();
|
||||
db::Coord t = read_coord ();
|
||||
db::Box box (l, b, r, t);
|
||||
|
||||
br.done ();
|
||||
|
||||
return std::make_pair (lid, db::PolygonRef (db::Polygon (box), l2n->internal_layout ()->shape_repository ()));
|
||||
|
||||
} else if (test (skeys::polygon_key) || test (lkeys::polygon_key)) {
|
||||
|
||||
Brace br (this);
|
||||
|
||||
read_word_or_quoted (lname);
|
||||
unsigned int lid = l2n->layer_of (layers.layer (lname));
|
||||
|
||||
std::vector<db::Point> pt;
|
||||
|
||||
while (br) {
|
||||
db::Coord x = read_coord ();
|
||||
db::Coord y = read_coord ();
|
||||
pt.push_back (db::Point (x, y));
|
||||
}
|
||||
|
||||
br.done ();
|
||||
|
||||
db::Polygon poly;
|
||||
poly.assign_hull (pt.begin (), pt.end ());
|
||||
return std::make_pair (lid, db::PolygonRef (poly, l2n->internal_layout ()->shape_repository ()));
|
||||
|
||||
} else {
|
||||
throw tl::Exception (tl::to_string (tr ("Invalid keyword inside net or terminal definition (polygon or rect expected)")));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
LayoutToNetlistStandardReader::read_net (db::LayoutToNetlist *l2n, db::Circuit *circuit, Layers &layers)
|
||||
{
|
||||
Brace br (this);
|
||||
|
||||
std::string name;
|
||||
read_word_or_quoted (name);
|
||||
|
||||
db::Net *net = new db::Net ();
|
||||
net->set_name (name);
|
||||
circuit->add_net (net);
|
||||
|
||||
db::connected_clusters<db::PolygonRef> &cc = l2n->net_clusters ().clusters_per_cell (circuit->cell_index ());
|
||||
db::local_cluster<db::PolygonRef> &lc = *cc.insert ();
|
||||
net->set_cluster_id (lc.id ());
|
||||
|
||||
db::Cell &cell = l2n->internal_layout ()->cell (circuit->cell_index ());
|
||||
|
||||
while (br) {
|
||||
std::pair<unsigned int, db::PolygonRef> pr = read_geometry (l2n, layers);
|
||||
lc.add (pr.second, pr.first);
|
||||
cell.shapes (pr.first).insert (pr.second);
|
||||
}
|
||||
|
||||
br.done ();
|
||||
}
|
||||
|
||||
void
|
||||
LayoutToNetlistStandardReader::read_pin (db::LayoutToNetlist * /*l2n*/, db::Circuit *circuit)
|
||||
{
|
||||
Brace br (this);
|
||||
std::string name;
|
||||
read_word_or_quoted (name);
|
||||
std::string netname;
|
||||
read_word_or_quoted (netname);
|
||||
br.done ();
|
||||
|
||||
const db::Pin &pin = circuit->add_pin (name);
|
||||
|
||||
db::Net *net = circuit->net_by_name (netname);
|
||||
if (!net) {
|
||||
throw tl::Exception (tl::to_string (tr ("Not a valid net name: ")) + netname);
|
||||
}
|
||||
|
||||
circuit->connect_pin (pin.id (), net);
|
||||
}
|
||||
|
||||
db::CellInstArray
|
||||
LayoutToNetlistStandardReader::read_device (db::LayoutToNetlist *l2n, db::Circuit *circuit, std::list<Connections> &refs)
|
||||
{
|
||||
Brace br (this);
|
||||
|
||||
std::string name;
|
||||
read_word_or_quoted (name);
|
||||
|
||||
std::string dmname;
|
||||
read_word_or_quoted (dmname);
|
||||
|
||||
db::DeviceModel *dm = 0;
|
||||
for (db::Netlist::device_model_iterator i = l2n->netlist ()->begin_device_models (); i != l2n->netlist ()->end_device_models (); ++i) {
|
||||
if (i->name () == dmname) {
|
||||
dm = i.operator-> ();
|
||||
}
|
||||
}
|
||||
|
||||
if (! dm) {
|
||||
throw tl::Exception (tl::to_string (tr ("Not a valid device model name: ")) + dmname);
|
||||
}
|
||||
|
||||
db::Device *device = new db::Device ();
|
||||
device->set_device_class (const_cast<db::DeviceClass *> (dm->device_class ()));
|
||||
device->set_device_model (dm);
|
||||
device->set_name (name);
|
||||
circuit->add_device (device);
|
||||
|
||||
db::Coord x = 0, y = 0;
|
||||
|
||||
while (br) {
|
||||
|
||||
if (test (skeys::location_key) || test (lkeys::location_key)) {
|
||||
|
||||
Brace br2 (this);
|
||||
x = read_coord ();
|
||||
y = read_coord ();
|
||||
br2.done ();
|
||||
|
||||
} else if (test (skeys::terminal_key) || test (lkeys::terminal_key)) {
|
||||
|
||||
Brace br2 (this);
|
||||
std::string tname;
|
||||
read_word_or_quoted (tname);
|
||||
std::string netname;
|
||||
read_word_or_quoted (netname);
|
||||
br2.done ();
|
||||
|
||||
size_t tid = std::numeric_limits<size_t>::max ();
|
||||
const std::vector<db::DeviceTerminalDefinition> &td = dm->device_class ()->terminal_definitions ();
|
||||
for (std::vector<db::DeviceTerminalDefinition>::const_iterator t = td.begin (); t != td.end (); ++t) {
|
||||
if (t->name () == tname) {
|
||||
tid = t->id ();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (tid == std::numeric_limits<size_t>::max ()) {
|
||||
throw tl::Exception (tl::to_string (tr ("Not a valid terminal name: ")) + tname + tl::to_string (tr (" for device class: ")) + dm->device_class ()->name ());
|
||||
}
|
||||
|
||||
db::Net *net = circuit->net_by_name (netname);
|
||||
if (!net) {
|
||||
throw tl::Exception (tl::to_string (tr ("Not a valid net name: ")) + netname);
|
||||
}
|
||||
|
||||
device->connect_terminal (tid, net);
|
||||
refs.push_back (Connections (net->cluster_id (), dm->cluster_id_for_terminal (tid)));
|
||||
|
||||
} else if (test (skeys::param_key) || test (lkeys::param_key)) {
|
||||
|
||||
Brace br2 (this);
|
||||
std::string pname;
|
||||
read_word_or_quoted (pname);
|
||||
double value = read_double ();
|
||||
br2.done ();
|
||||
|
||||
size_t pid = std::numeric_limits<size_t>::max ();
|
||||
const std::vector<db::DeviceParameterDefinition> &pd = dm->device_class ()->parameter_definitions ();
|
||||
for (std::vector<db::DeviceParameterDefinition>::const_iterator p = pd.begin (); p != pd.end (); ++p) {
|
||||
if (p->name () == pname) {
|
||||
pid = p->id ();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// if no parameter with this name exists, create one
|
||||
if (pid == std::numeric_limits<size_t>::max ()) {
|
||||
// TODO: this should only happen for generic devices
|
||||
db::DeviceClass *dc = const_cast<db::DeviceClass *> (dm->device_class ());
|
||||
pid = dc->add_parameter_definition (db::DeviceParameterDefinition (pname, std::string ())).id ();
|
||||
}
|
||||
|
||||
device->set_parameter_value (pid, value);
|
||||
|
||||
} else {
|
||||
throw tl::Exception (tl::to_string (tr ("Invalid keyword inside device definition (location, param or terminal expected)")));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
double dbu = l2n->internal_layout ()->dbu ();
|
||||
device->set_position (db::DPoint (dbu * x, dbu * y));
|
||||
|
||||
br.done ();
|
||||
|
||||
// make device cell instance
|
||||
db::CellInstArray inst (db::CellInst (dm->cell_index ()), db::Trans (db::Vector (x, y)));
|
||||
db::Cell &ccell = l2n->internal_layout ()->cell (circuit->cell_index ());
|
||||
ccell.insert (inst);
|
||||
|
||||
return inst;
|
||||
}
|
||||
|
||||
db::CellInstArray
|
||||
LayoutToNetlistStandardReader::read_subcircuit (db::LayoutToNetlist *l2n, db::Circuit *circuit, std::list<Connections> &refs)
|
||||
{
|
||||
Brace br (this);
|
||||
|
||||
std::string name;
|
||||
read_word_or_quoted (name);
|
||||
|
||||
std::string xname;
|
||||
read_word_or_quoted (xname);
|
||||
|
||||
db::Circuit *circuit_ref = l2n->netlist ()->circuit_by_name (xname);
|
||||
if (! circuit_ref) {
|
||||
throw tl::Exception (tl::to_string (tr ("Not a valid device circuit name: ")) + xname);
|
||||
}
|
||||
|
||||
db::SubCircuit *subcircuit = new db::SubCircuit (circuit_ref);
|
||||
subcircuit->set_name (name);
|
||||
circuit->add_subcircuit (subcircuit);
|
||||
|
||||
db::Coord x = 0, y = 0;
|
||||
bool mirror = false;
|
||||
double angle = 0;
|
||||
double mag = 1.0;
|
||||
|
||||
db::InstElement ie;
|
||||
bool inst_made = false;
|
||||
|
||||
while (br) {
|
||||
|
||||
if (test (skeys::location_key) || test (lkeys::location_key)) {
|
||||
|
||||
Brace br2 (this);
|
||||
x = read_coord ();
|
||||
y = read_coord ();
|
||||
br2.done ();
|
||||
|
||||
if (inst_made) {
|
||||
throw tl::Exception (tl::to_string (tr ("location key must come before pin key in subcircuit definition")));
|
||||
}
|
||||
|
||||
} else if (test (skeys::rotation_key) || test (lkeys::rotation_key)) {
|
||||
|
||||
Brace br2 (this);
|
||||
angle = read_double ();
|
||||
br2.done ();
|
||||
|
||||
if (inst_made) {
|
||||
throw tl::Exception (tl::to_string (tr ("rotation key must come before pin key in subcircuit definition")));
|
||||
}
|
||||
|
||||
} else if (test (skeys::mirror_key) || test (lkeys::mirror_key)) {
|
||||
|
||||
mirror = true;
|
||||
if (inst_made) {
|
||||
throw tl::Exception (tl::to_string (tr ("mirror key must come before pin key in subcircuit definition")));
|
||||
}
|
||||
|
||||
} else if (test (skeys::scale_key) || test (lkeys::scale_key)) {
|
||||
|
||||
Brace br2 (this);
|
||||
mag = read_double ();
|
||||
br2.done ();
|
||||
|
||||
if (inst_made) {
|
||||
throw tl::Exception (tl::to_string (tr ("scale key must come before pin key in subcircuit definition")));
|
||||
}
|
||||
|
||||
} else if (test (skeys::pin_key) || test (lkeys::pin_key)) {
|
||||
|
||||
Brace br2 (this);
|
||||
std::string pname;
|
||||
read_word_or_quoted (pname);
|
||||
std::string netname;
|
||||
read_word_or_quoted (netname);
|
||||
br2.done ();
|
||||
|
||||
const db::Pin *sc_pin = circuit_ref->pin_by_name (pname);
|
||||
if (! sc_pin) {
|
||||
throw tl::Exception (tl::to_string (tr ("Not a valid pin name: ")) + pname + tl::to_string (tr (" for circuit: ")) + circuit_ref->name ());
|
||||
}
|
||||
|
||||
db::Net *net = circuit->net_by_name (netname);
|
||||
if (!net) {
|
||||
throw tl::Exception (tl::to_string (tr ("Not a valid net name: ")) + netname);
|
||||
}
|
||||
|
||||
subcircuit->connect_pin (sc_pin->id (), net);
|
||||
db::Net *sc_net = circuit_ref->net_for_pin (sc_pin->id ());
|
||||
if (sc_net) {
|
||||
refs.push_back (Connections (net->cluster_id (), sc_net->cluster_id ()));
|
||||
}
|
||||
|
||||
} else {
|
||||
throw tl::Exception (tl::to_string (tr ("Invalid keyword inside subcircuit definition (location, rotation, mirror, scale or pin expected)")));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
br.done ();
|
||||
|
||||
double dbu = l2n->internal_layout ()->dbu ();
|
||||
subcircuit->set_trans (db::DCplxTrans (mag, angle, mirror, db::DVector (dbu * x, dbu * y)));
|
||||
|
||||
db::CellInstArray inst (db::CellInst (circuit_ref->cell_index ()), db::ICplxTrans (mag, angle, mirror, db::Vector (x, y)));
|
||||
db::Cell &ccell = l2n->internal_layout ()->cell (circuit->cell_index ());
|
||||
ccell.insert (inst);
|
||||
|
||||
return inst;
|
||||
}
|
||||
|
||||
void
|
||||
LayoutToNetlistStandardReader::read_abstract_terminal (db::LayoutToNetlist *l2n, db::DeviceModel *dm, db::DeviceClass *dc, Layers &layers)
|
||||
{
|
||||
Brace br (this);
|
||||
|
||||
std::string name;
|
||||
read_word_or_quoted (name);
|
||||
|
||||
size_t tid = std::numeric_limits<size_t>::max ();
|
||||
const std::vector<db::DeviceTerminalDefinition> &td = dm->device_class ()->terminal_definitions ();
|
||||
for (std::vector<db::DeviceTerminalDefinition>::const_iterator t = td.begin (); t != td.end (); ++t) {
|
||||
if (t->name () == name) {
|
||||
tid = t->id ();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// create a terminal unless one with this name already exists
|
||||
if (tid == std::numeric_limits<size_t>::max ()) {
|
||||
if (! dc) {
|
||||
throw tl::Exception (tl::to_string (tr ("Not a valid terminal name: ")) + name + tl::to_string (tr (" for device class: ")) + dm->device_class ()->name ());
|
||||
}
|
||||
db::DeviceTerminalDefinition new_td (name, std::string ());
|
||||
tid = dc->add_terminal_definition (new_td).id ();
|
||||
}
|
||||
|
||||
db::connected_clusters<db::PolygonRef> &cc = l2n->net_clusters ().clusters_per_cell (dm->cell_index ());
|
||||
db::local_cluster<db::PolygonRef> &lc = *cc.insert ();
|
||||
dm->set_cluster_id_for_terminal (tid, lc.id ());
|
||||
|
||||
db::Cell &cell = l2n->internal_layout ()->cell (dm->cell_index ());
|
||||
|
||||
while (br) {
|
||||
std::pair<unsigned int, db::PolygonRef> pr = read_geometry (l2n, layers);
|
||||
lc.add (pr.second, pr.first);
|
||||
cell.shapes (pr.first).insert (pr.second);
|
||||
}
|
||||
|
||||
br.done ();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,10 +24,83 @@
|
|||
#define HDR_dbLayoutToNetlistReader
|
||||
|
||||
#include "dbCommon.h"
|
||||
#include "dbPolygon.h"
|
||||
#include "dbCell.h"
|
||||
#include "tlStream.h"
|
||||
|
||||
namespace db {
|
||||
|
||||
// ...
|
||||
namespace l2n_std_reader {
|
||||
class Layers;
|
||||
class Brace;
|
||||
}
|
||||
|
||||
class LayoutToNetlist;
|
||||
class Circuit;
|
||||
class Cell;
|
||||
class DeviceModel;
|
||||
class DeviceClass;
|
||||
|
||||
/**
|
||||
* @brief The base class for a LayoutToNetlist writer
|
||||
*/
|
||||
class DB_PUBLIC LayoutToNetlistReaderBase
|
||||
{
|
||||
public:
|
||||
LayoutToNetlistReaderBase () { }
|
||||
virtual ~LayoutToNetlistReaderBase () { }
|
||||
|
||||
virtual void read (db::LayoutToNetlist *l2n) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The standard writer
|
||||
*/
|
||||
class DB_PUBLIC LayoutToNetlistStandardReader
|
||||
: public LayoutToNetlistReaderBase
|
||||
{
|
||||
public:
|
||||
LayoutToNetlistStandardReader (tl::InputStream &stream);
|
||||
|
||||
void read (db::LayoutToNetlist *l2n);
|
||||
|
||||
private:
|
||||
friend class l2n_std_reader::Brace;
|
||||
typedef l2n_std_reader::Brace Brace;
|
||||
typedef l2n_std_reader::Layers Layers;
|
||||
|
||||
struct Connections
|
||||
{
|
||||
Connections (size_t _from_cluster, size_t _to_cluster)
|
||||
: from_cluster (_from_cluster), to_cluster (_to_cluster)
|
||||
{ }
|
||||
|
||||
size_t from_cluster, to_cluster;
|
||||
};
|
||||
|
||||
tl::TextInputStream m_stream;
|
||||
std::string m_path;
|
||||
std::string m_line;
|
||||
tl::Extractor m_ex;
|
||||
|
||||
void do_read (db::LayoutToNetlist *l2n);
|
||||
|
||||
bool test (const std::string &token);
|
||||
void expect (const std::string &token);
|
||||
void read_word_or_quoted(std::string &s);
|
||||
int read_int ();
|
||||
db::Coord read_coord ();
|
||||
double read_double ();
|
||||
bool at_end ();
|
||||
void skip ();
|
||||
|
||||
void read_net (db::LayoutToNetlist *l2n, db::Circuit *circuit, Layers &layers);
|
||||
void read_pin (db::LayoutToNetlist *l2n, db::Circuit *circuit);
|
||||
db::CellInstArray read_device (db::LayoutToNetlist *l2n, db::Circuit *circuit, std::list<Connections> &refs);
|
||||
db::CellInstArray read_subcircuit (db::LayoutToNetlist *l2n, db::Circuit *circuit, std::list<Connections> &refs);
|
||||
void read_abstract_terminal (db::LayoutToNetlist *l2n, db::DeviceModel *dm, db::DeviceClass *dc, Layers &layers);
|
||||
std::pair<unsigned int, db::PolygonRef> read_geometry (db::LayoutToNetlist *l2n, Layers &layers);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,107 +22,42 @@
|
|||
|
||||
#include "dbLayoutToNetlistWriter.h"
|
||||
#include "dbLayoutToNetlist.h"
|
||||
#include "dbLayoutToNetlistFormatDefs.h"
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
namespace l2n_std_format
|
||||
{
|
||||
|
||||
// -------------------------------------------------------------------------------------------
|
||||
// LayoutToNetlistStandardWriter implementation
|
||||
// std_writer_impl<Keys> implementation
|
||||
|
||||
/**
|
||||
* Comments are introduced by hash: # ...
|
||||
* Names are words (alphanumerical plus "$", "_", ".") or enclosed in single or double quotes.
|
||||
* Escape character is backslash.
|
||||
* Separator is either , or whitespace. Keywords and names are case sensitive.
|
||||
* Short keys are provided for compacter representation. Short keys can be
|
||||
* non-alpha (e.g. "*") or empty.
|
||||
* Single-valued attributes can be given without brackets.
|
||||
* All dimensions are in units of database unit.
|
||||
* The file follows the declaration-before-use principle
|
||||
* (circuits before subcircuits, nets before use ...)
|
||||
*
|
||||
* Global statements:
|
||||
*
|
||||
* version(<number>) - file format version
|
||||
* description(<text>) - an arbitrary description text
|
||||
* unit(<unit>) - specifies the database unit [short key: U]
|
||||
* top(<circuit>) - specifies the name of the top circuit [short key: T]
|
||||
* layer(<name>) - define a layer [short key: L]
|
||||
* 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-abstract-def])
|
||||
* - device abstract [short key: D]
|
||||
*
|
||||
* [circuit-def]:
|
||||
*
|
||||
* net(<name> [geometry-def]) - net geometry [short key: N]
|
||||
* A net declaration shall be there also if no geometry
|
||||
* is present
|
||||
* pin(<name> <net-name>) - outgoing pin connection [short key: P]
|
||||
* device(<name> <class> [device-def])
|
||||
* - device with connections [short key: D]
|
||||
* subcircuit(<name> [subcircuit-def])
|
||||
* - subcircuit with connections [short key: X]
|
||||
*
|
||||
* [geometry-def]:
|
||||
*
|
||||
* polygon(<layer> <x> <y> ...) - defines a polygon [short key: P]
|
||||
* rect(<layer> <left> <bottom> <right> <top>)
|
||||
* - defines a rectangle [short key: R]
|
||||
*
|
||||
* [device-abstract-def]:
|
||||
*
|
||||
* terminal(<terminal-name> [geometry-def])
|
||||
* - specifies the terminal geometry [short key: empty]
|
||||
*
|
||||
* [device-def]:
|
||||
*
|
||||
* param(<name> <value>) - defines a parameter [short key P]
|
||||
* 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)
|
||||
* location(<x> <y>) - location of the device [short key L]
|
||||
*
|
||||
* [subcircuit-def]:
|
||||
*
|
||||
* location(<x> <y>) - location of the subcircuit [short key L]
|
||||
* rotation(<angle>) - rotation angle [short key O]
|
||||
* mirror - if specified, the instance is mirrored before rotation [short key M]
|
||||
* scale(<mag>) - magnification [short key *]
|
||||
* pin(<pin-name> <net-name>) - specifies connection of the pin with a net [short key: P]
|
||||
*/
|
||||
template <class Keys>
|
||||
class std_writer_impl
|
||||
{
|
||||
public:
|
||||
std_writer_impl (tl::OutputStream &stream);
|
||||
|
||||
static std::string version_key ("version");
|
||||
static std::string description_key ("description");
|
||||
static std::string top_key ("top");
|
||||
static std::string unit_key ("unit");
|
||||
static std::string layer_key ("layer");
|
||||
static std::string text_key ("text");
|
||||
static std::string connect_key ("connect");
|
||||
static std::string global_key ("global");
|
||||
static std::string circuit_key ("circuit");
|
||||
static std::string net_key ("net");
|
||||
static std::string device_key ("device");
|
||||
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 abstract_key ("abstract");
|
||||
static std::string label_key ("label");
|
||||
static std::string param_key ("param");
|
||||
static std::string location_key ("location");
|
||||
static std::string rotation_key ("rotation");
|
||||
static std::string mirror_key ("mirror");
|
||||
static std::string scale_key ("scale");
|
||||
static std::string pin_key ("pin");
|
||||
static std::string indent1 (" ");
|
||||
static std::string indent2 (" ");
|
||||
static std::string endl ("\n");
|
||||
void write (const db::LayoutToNetlist *l2n);
|
||||
|
||||
LayoutToNetlistStandardWriter::LayoutToNetlistStandardWriter (tl::OutputStream &stream)
|
||||
private:
|
||||
tl::OutputStream *mp_stream;
|
||||
|
||||
void write (const db::LayoutToNetlist *l2n, const db::Circuit &circuit);
|
||||
void write (const db::LayoutToNetlist *l2n, const db::Net &net);
|
||||
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 db::ICplxTrans &tr, const std::string &lname);
|
||||
};
|
||||
|
||||
static const std::string endl ("\n");
|
||||
static const std::string indent1 (" ");
|
||||
static const std::string indent2 (" ");
|
||||
|
||||
template <class Keys>
|
||||
std_writer_impl<Keys>::std_writer_impl (tl::OutputStream &stream)
|
||||
: mp_stream (&stream)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
|
|
@ -138,7 +73,8 @@ static std::string name_for_layer (const db::Layout *layout, unsigned int l)
|
|||
}
|
||||
}
|
||||
|
||||
void LayoutToNetlistStandardWriter::write (const db::LayoutToNetlist *l2n)
|
||||
template <class Keys>
|
||||
void std_writer_impl<Keys>::write (const db::LayoutToNetlist *l2n)
|
||||
{
|
||||
bool any = false;
|
||||
|
||||
|
|
@ -150,17 +86,17 @@ void LayoutToNetlistStandardWriter::write (const db::LayoutToNetlist *l2n)
|
|||
*mp_stream << "# General section" << endl;
|
||||
*mp_stream << "# Lists general definitions." << endl << endl;
|
||||
if (version > 0) {
|
||||
*mp_stream << version_key << "(" << version << ")" << endl;
|
||||
*mp_stream << Keys::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 << Keys::top_key << "(" << tl::to_word_or_quoted_string (ly->cell_name (l2n->internal_top_cell ()->cell_index ())) << ")" << endl;
|
||||
*mp_stream << Keys::unit_key << "(" << ly->dbu () << ")" << endl;
|
||||
|
||||
*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 << Keys::layer_key << "(" << name_for_layer (ly, *l) << ")" << endl;
|
||||
}
|
||||
|
||||
*mp_stream << endl << "# Mask layer connectivity" << endl;
|
||||
|
|
@ -169,7 +105,7 @@ void LayoutToNetlistStandardWriter::write (const db::LayoutToNetlist *l2n)
|
|||
db::Connectivity::layer_iterator ce = l2n->connectivity ().end_connected (*l);
|
||||
db::Connectivity::layer_iterator cb = l2n->connectivity ().begin_connected (*l);
|
||||
if (cb != ce) {
|
||||
*mp_stream << connect_key << "(" << name_for_layer (ly, *l);
|
||||
*mp_stream << Keys::connect_key << "(" << name_for_layer (ly, *l);
|
||||
for (db::Connectivity::layer_iterator c = l2n->connectivity ().begin_connected (*l); c != ce; ++c) {
|
||||
*mp_stream << " " << name_for_layer (ly, *c);
|
||||
}
|
||||
|
|
@ -188,7 +124,7 @@ void LayoutToNetlistStandardWriter::write (const db::LayoutToNetlist *l2n)
|
|||
*mp_stream << endl << "# Global nets and connectivity" << endl;
|
||||
any = true;
|
||||
}
|
||||
*mp_stream << global_key << "(" << name_for_layer (ly, *l);
|
||||
*mp_stream << Keys::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));
|
||||
}
|
||||
|
|
@ -203,7 +139,7 @@ void LayoutToNetlistStandardWriter::write (const db::LayoutToNetlist *l2n)
|
|||
}
|
||||
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;
|
||||
*mp_stream << Keys::device_key << "(" << tl::to_word_or_quoted_string (m->name ()) << " " << tl::to_word_or_quoted_string (m->device_class ()->name ()) << endl;
|
||||
write (l2n, *m);
|
||||
*mp_stream << ")" << endl;
|
||||
}
|
||||
|
|
@ -211,16 +147,17 @@ 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) {
|
||||
for (db::Netlist::const_bottom_up_circuit_iterator i = nl->begin_bottom_up (); i != nl->end_bottom_up (); ++i) {
|
||||
const db::Circuit *x = *i;
|
||||
*mp_stream << endl << "# Circuit " << x->name () << endl;
|
||||
*mp_stream << circuit_key << "(" << tl::to_word_or_quoted_string (x->name ()) << endl;
|
||||
*mp_stream << Keys::circuit_key << "(" << tl::to_word_or_quoted_string (x->name ()) << endl;
|
||||
write (l2n, *x);
|
||||
*mp_stream << ")" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
void LayoutToNetlistStandardWriter::write (const db::LayoutToNetlist *l2n, const db::Circuit &circuit)
|
||||
template <class Keys>
|
||||
void std_writer_impl<Keys>::write (const db::LayoutToNetlist *l2n, const db::Circuit &circuit)
|
||||
{
|
||||
if (circuit.begin_nets () != circuit.end_nets ()) {
|
||||
*mp_stream << endl << indent1 << "# Nets with their geometries" << endl;
|
||||
|
|
@ -234,7 +171,7 @@ void LayoutToNetlistStandardWriter::write (const db::LayoutToNetlist *l2n, const
|
|||
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;
|
||||
*mp_stream << indent1 << Keys::pin_key << "(" << tl::to_word_or_quoted_string (p->expanded_name ()) << " " << tl::to_word_or_quoted_string (net->expanded_name ()) << ")" << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -265,7 +202,8 @@ void write_points (tl::OutputStream &stream, const T &poly, const Tr &tr)
|
|||
}
|
||||
}
|
||||
|
||||
void LayoutToNetlistStandardWriter::write (const db::PolygonRef *s, const db::ICplxTrans &tr, const std::string &lname)
|
||||
template <class Keys>
|
||||
void std_writer_impl<Keys>::write (const db::PolygonRef *s, const db::ICplxTrans &tr, const std::string &lname)
|
||||
{
|
||||
db::ICplxTrans t = tr * db::ICplxTrans (s->trans ());
|
||||
|
||||
|
|
@ -273,14 +211,14 @@ void LayoutToNetlistStandardWriter::write (const db::PolygonRef *s, const db::IC
|
|||
if (poly.is_box ()) {
|
||||
|
||||
db::Box box = t * poly.box ();
|
||||
*mp_stream << rect_key << "(" << lname;
|
||||
*mp_stream << Keys::rect_key << "(" << lname;
|
||||
*mp_stream << " " << box.left () << " " << box.bottom ();
|
||||
*mp_stream << " " << box.right () << " " << box.top ();
|
||||
*mp_stream << ")";
|
||||
|
||||
} else {
|
||||
|
||||
*mp_stream << polygon_key << "(" << lname;
|
||||
*mp_stream << Keys::polygon_key << "(" << lname;
|
||||
if (poly.holes () > 0) {
|
||||
db::SimplePolygon sp (poly);
|
||||
write_points (*mp_stream, sp, t);
|
||||
|
|
@ -292,7 +230,8 @@ void LayoutToNetlistStandardWriter::write (const db::PolygonRef *s, const db::IC
|
|||
}
|
||||
}
|
||||
|
||||
void LayoutToNetlistStandardWriter::write (const db::LayoutToNetlist *l2n, const db::Net &net)
|
||||
template <class Keys>
|
||||
void std_writer_impl<Keys>::write (const db::LayoutToNetlist *l2n, const db::Net &net)
|
||||
{
|
||||
const db::Layout *ly = l2n->internal_layout ();
|
||||
const db::hier_clusters<db::PolygonRef> &clusters = l2n->net_clusters ();
|
||||
|
|
@ -319,7 +258,7 @@ void LayoutToNetlistStandardWriter::write (const db::LayoutToNetlist *l2n, const
|
|||
} else {
|
||||
|
||||
if (! any) {
|
||||
*mp_stream << indent1 << net_key << "(" << tl::to_word_or_quoted_string (net.expanded_name ()) << endl;
|
||||
*mp_stream << indent1 << Keys::net_key << "(" << tl::to_word_or_quoted_string (net.expanded_name ()) << endl;
|
||||
any = true;
|
||||
}
|
||||
|
||||
|
|
@ -340,28 +279,30 @@ void LayoutToNetlistStandardWriter::write (const db::LayoutToNetlist *l2n, const
|
|||
if (any) {
|
||||
*mp_stream << indent1 << ")" << endl;
|
||||
} else {
|
||||
*mp_stream << indent1 << net_key << "(" << tl::to_word_or_quoted_string (net.expanded_name ()) << ")" << endl;
|
||||
*mp_stream << indent1 << Keys::net_key << "(" << tl::to_word_or_quoted_string (net.expanded_name ()) << ")" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
void LayoutToNetlistStandardWriter::write (const db::LayoutToNetlist *l2n, const db::SubCircuit &subcircuit)
|
||||
template <class Keys>
|
||||
void std_writer_impl<Keys>::write (const db::LayoutToNetlist *l2n, const db::SubCircuit &subcircuit)
|
||||
{
|
||||
const db::Layout *ly = l2n->internal_layout ();
|
||||
double dbu = ly->dbu ();
|
||||
|
||||
*mp_stream << indent1 << subcircuit_key << "(" << tl::to_word_or_quoted_string (subcircuit.expanded_name ());
|
||||
*mp_stream << indent1 << Keys::circuit_key << "(" << tl::to_word_or_quoted_string (subcircuit.expanded_name ());
|
||||
*mp_stream << " " << tl::to_word_or_quoted_string (subcircuit.circuit_ref ()->name ());
|
||||
|
||||
const db::DCplxTrans &tr = subcircuit.trans ();
|
||||
if (tr.is_mag ()) {
|
||||
*mp_stream << " " << scale_key << "(" << tr.mag () << ")";
|
||||
*mp_stream << " " << Keys::scale_key << "(" << tr.mag () << ")";
|
||||
}
|
||||
if (tr.is_mirror ()) {
|
||||
*mp_stream << " " << mirror_key;
|
||||
*mp_stream << " " << Keys::mirror_key;
|
||||
}
|
||||
if (fabs (tr.angle ()) > 1e-6) {
|
||||
*mp_stream << " " << rotation_key << "(" << tr.angle () << ")";
|
||||
*mp_stream << " " << Keys::rotation_key << "(" << tr.angle () << ")";
|
||||
}
|
||||
*mp_stream << " " << location_key << "(" << tr.disp ().x () / dbu << " " << tr.disp ().y () / dbu << ")";
|
||||
*mp_stream << " " << Keys::location_key << "(" << tr.disp ().x () / dbu << " " << tr.disp ().y () / dbu << ")";
|
||||
|
||||
// each pin in one line for more than a few pins
|
||||
bool separate_lines = (subcircuit.circuit_ref ()->pin_count () > 1);
|
||||
|
|
@ -378,7 +319,7 @@ void LayoutToNetlistStandardWriter::write (const db::LayoutToNetlist *l2n, const
|
|||
} else {
|
||||
*mp_stream << " ";
|
||||
}
|
||||
*mp_stream << pin_key << "(" << tl::to_word_or_quoted_string (p->expanded_name ()) << " " << tl::to_word_or_quoted_string (net->expanded_name ()) << ")";
|
||||
*mp_stream << Keys::pin_key << "(" << tl::to_word_or_quoted_string (p->expanded_name ()) << " " << tl::to_word_or_quoted_string (net->expanded_name ()) << ")";
|
||||
if (separate_lines) {
|
||||
*mp_stream << endl;
|
||||
}
|
||||
|
|
@ -392,7 +333,8 @@ void LayoutToNetlistStandardWriter::write (const db::LayoutToNetlist *l2n, const
|
|||
*mp_stream << ")" << endl;
|
||||
}
|
||||
|
||||
void LayoutToNetlistStandardWriter::write (const db::LayoutToNetlist *l2n, const db::DeviceModel &device_model)
|
||||
template <class Keys>
|
||||
void std_writer_impl<Keys>::write (const db::LayoutToNetlist *l2n, const db::DeviceModel &device_model)
|
||||
{
|
||||
const std::vector<db::DeviceTerminalDefinition> &td = device_model.device_class ()->terminal_definitions ();
|
||||
|
||||
|
|
@ -402,7 +344,7 @@ void LayoutToNetlistStandardWriter::write (const db::LayoutToNetlist *l2n, const
|
|||
|
||||
for (std::vector<db::DeviceTerminalDefinition>::const_iterator t = td.begin (); t != td.end (); ++t) {
|
||||
|
||||
*mp_stream << indent1 << terminal_key << "(" << t->name () << endl;
|
||||
*mp_stream << indent1 << Keys::terminal_key << "(" << t->name () << endl;
|
||||
|
||||
for (db::Connectivity::layer_iterator l = conn.begin_layers (); l != conn.end_layers (); ++l) {
|
||||
|
||||
|
|
@ -422,31 +364,55 @@ void LayoutToNetlistStandardWriter::write (const db::LayoutToNetlist *l2n, const
|
|||
}
|
||||
}
|
||||
|
||||
void LayoutToNetlistStandardWriter::write (const db::LayoutToNetlist *l2n, const db::Device &device)
|
||||
template <class Keys>
|
||||
void std_writer_impl<Keys>::write (const db::LayoutToNetlist *l2n, const db::Device &device)
|
||||
{
|
||||
const db::Layout *ly = l2n->internal_layout ();
|
||||
double dbu = ly->dbu ();
|
||||
|
||||
*mp_stream << indent1 << device_key << "(" << tl::to_word_or_quoted_string (device.expanded_name ());
|
||||
*mp_stream << " " << tl::to_word_or_quoted_string (device.device_class ()->name ()) << endl;
|
||||
*mp_stream << indent1 << Keys::device_key << "(" << tl::to_word_or_quoted_string (device.expanded_name ());
|
||||
|
||||
*mp_stream << indent2 << location_key << "(" << device.position ().x () / dbu << " " << device.position ().y () / dbu << ")" << endl;
|
||||
tl_assert (device.device_model () != 0);
|
||||
*mp_stream << " " << tl::to_word_or_quoted_string (device.device_model ()->name ()) << endl;
|
||||
|
||||
if (device.device_model ()) {
|
||||
*mp_stream << indent2 << abstract_key << "(" << tl::to_word_or_quoted_string (device.device_model ()->name ()) << ")" << endl;
|
||||
}
|
||||
*mp_stream << indent2 << Keys::location_key << "(" << device.position ().x () / dbu << " " << device.position ().y () / dbu << ")" << endl;
|
||||
|
||||
const std::vector<DeviceParameterDefinition> &pd = device.device_class ()->parameter_definitions ();
|
||||
for (std::vector<DeviceParameterDefinition>::const_iterator i = pd.begin (); i != pd.end (); ++i) {
|
||||
*mp_stream << indent2 << param_key << "(" << tl::to_word_or_quoted_string (i->name ()) << " " << device.parameter_value (i->id ()) << ")" << endl;
|
||||
*mp_stream << indent2 << Keys::param_key << "(" << tl::to_word_or_quoted_string (i->name ()) << " " << device.parameter_value (i->id ()) << ")" << endl;
|
||||
}
|
||||
|
||||
const std::vector<DeviceTerminalDefinition> &td = device.device_class ()->terminal_definitions ();
|
||||
for (std::vector<DeviceTerminalDefinition>::const_iterator i = td.begin (); i != td.end (); ++i) {
|
||||
*mp_stream << indent2 << terminal_key << "(" << tl::to_word_or_quoted_string (i->name ()) << " " << tl::to_word_or_quoted_string (device.net_for_terminal (i->id ())->expanded_name ()) << ")" << endl;
|
||||
const db::Net *net = device.net_for_terminal (i->id ());
|
||||
if (net) {
|
||||
*mp_stream << indent2 << Keys::terminal_key << "(" << tl::to_word_or_quoted_string (i->name ()) << " " << tl::to_word_or_quoted_string (net->expanded_name ()) << ")" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
*mp_stream << indent1 << ")" << endl;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------
|
||||
// LayoutToNetlistStandardWriter implementation
|
||||
|
||||
LayoutToNetlistStandardWriter::LayoutToNetlistStandardWriter (tl::OutputStream &stream, bool short_version)
|
||||
: mp_stream (&stream), m_short_version (short_version)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void LayoutToNetlistStandardWriter::write (const db::LayoutToNetlist *l2n)
|
||||
{
|
||||
if (m_short_version) {
|
||||
l2n_std_format::std_writer_impl<l2n_std_format::keys<true> > writer (*mp_stream);
|
||||
writer.write (l2n);
|
||||
} else {
|
||||
l2n_std_format::std_writer_impl<l2n_std_format::keys<false> > writer (*mp_stream);
|
||||
writer.write (l2n);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,18 +24,12 @@
|
|||
#define HDR_dbLayoutToNetlistWriter
|
||||
|
||||
#include "dbCommon.h"
|
||||
#include "dbPolygon.h"
|
||||
#include "tlStream.h"
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
class LayoutToNetlist;
|
||||
class Net;
|
||||
class Circuit;
|
||||
class SubCircuit;
|
||||
class Device;
|
||||
class DeviceModel;
|
||||
|
||||
/**
|
||||
* @brief The base class for a LayoutToNetlist writer
|
||||
|
|
@ -56,19 +50,13 @@ class DB_PUBLIC LayoutToNetlistStandardWriter
|
|||
: public LayoutToNetlistWriterBase
|
||||
{
|
||||
public:
|
||||
LayoutToNetlistStandardWriter (tl::OutputStream &stream);
|
||||
LayoutToNetlistStandardWriter (tl::OutputStream &stream, bool short_version);
|
||||
|
||||
void write (const db::LayoutToNetlist *l2n);
|
||||
|
||||
private:
|
||||
tl::OutputStream *mp_stream;
|
||||
|
||||
void write (const db::LayoutToNetlist *l2n, const db::Circuit &circuit);
|
||||
void write (const db::LayoutToNetlist *l2n, const db::Net &net);
|
||||
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 db::ICplxTrans &tr, const std::string &lname);
|
||||
bool m_short_version;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -307,20 +307,16 @@ void NetlistDeviceExtractor::push_new_devices ()
|
|||
ps.insert (std::make_pair (m_terminal_id_propname_id, tl::Variant (t->first)));
|
||||
db::properties_id_type pi = mp_layout->properties_repository ().properties_id (ps);
|
||||
|
||||
// initialize the local cluster (will not be extracted)
|
||||
db::local_cluster<db::PolygonRef> *lc = cc.insert ();
|
||||
lc->add_attr (pi);
|
||||
dm->set_cluster_id_for_terminal (t->first, lc->id ());
|
||||
|
||||
// build the cell shapes and local cluster
|
||||
// build the cell shapes
|
||||
for (geometry_per_layer_type::const_iterator l = t->second.begin (); l != t->second.end (); ++l) {
|
||||
|
||||
db::Shapes &shapes = device_cell.shapes (l->first);
|
||||
for (std::vector<db::PolygonRef>::const_iterator s = l->second.begin (); s != l->second.end (); ++s) {
|
||||
db::PolygonRef pr = *s;
|
||||
pr.transform (db::PolygonRef::trans_type (-disp));
|
||||
shapes.insert (db::PolygonRefWithProperties (pr, pi));
|
||||
lc->add (*s, l->first);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,18 +63,44 @@ NetlistExtractor::extract_nets (const db::DeepShapeStore &dss, const db::Connect
|
|||
circuits.insert (std::make_pair (c->cell_index (), c.operator-> ()));
|
||||
}
|
||||
|
||||
// reverse lookup for DeviceModel vs. cell index
|
||||
std::map<db::cell_index_type, db::DeviceModel *> device_models;
|
||||
for (db::Netlist::device_model_iterator dm = nl.begin_device_models (); dm != nl.end_device_models (); ++dm) {
|
||||
device_models.insert (std::make_pair (dm->cell_index (), dm.operator-> ()));
|
||||
}
|
||||
|
||||
std::map<db::cell_index_type, std::map<size_t, size_t> > pins_per_cluster_per_cell;
|
||||
for (db::Layout::bottom_up_const_iterator cid = mp_layout->begin_bottom_up (); cid != mp_layout->end_bottom_up (); ++cid) {
|
||||
|
||||
if (db::NetlistDeviceExtractor::is_device_cell (*mp_layout, *cid)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const connected_clusters_type &clusters = mp_clusters->clusters_per_cell (*cid);
|
||||
if (clusters.empty ()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::map<db::cell_index_type, db::DeviceModel *>::const_iterator dmc = device_models.find (*cid);
|
||||
if (dmc != device_models.end ()) {
|
||||
|
||||
// make the terminal to cluster ID connections for the device model from the device cells
|
||||
|
||||
if (m_terminal_annot_name_id.first) {
|
||||
|
||||
for (connected_clusters_type::const_iterator dc = clusters.begin (); dc != clusters.end (); ++dc) {
|
||||
for (local_cluster_type::attr_iterator a = dc->begin_attr (); a != dc->end_attr (); ++a) {
|
||||
const db::PropertiesRepository::properties_set &ps = mp_layout->properties_repository ().properties (*a);
|
||||
for (db::PropertiesRepository::properties_set::const_iterator j = ps.begin (); j != ps.end (); ++j) {
|
||||
if (j->first == m_terminal_annot_name_id.second) {
|
||||
dmc->second->set_cluster_id_for_terminal (j->second.to<size_t> (), dc->id ());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
// a cell makes a new circuit (or uses an existing one)
|
||||
|
||||
db::Circuit *circuit = 0;
|
||||
|
|
|
|||
|
|
@ -60,10 +60,10 @@ static void build_all_nets (const db::LayoutToNetlist *l2n, const db::CellMappin
|
|||
l2n->build_all_nets (cmap, target, lmap, net_cell_name_prefix.is_nil () ? 0 : np.c_str (), circuit_cell_name_prefix.is_nil () ? 0 : cp.c_str (), device_cell_name_prefix.is_nil () ? 0 : dp.c_str ());
|
||||
}
|
||||
|
||||
static void write_l2n (const db::LayoutToNetlist *l2n, const std::string &path)
|
||||
static void write_l2n (const db::LayoutToNetlist *l2n, const std::string &path, bool short_format)
|
||||
{
|
||||
tl::OutputStream stream (path);
|
||||
db::LayoutToNetlistStandardWriter writer (stream);
|
||||
db::LayoutToNetlistStandardWriter writer (stream, short_format);
|
||||
writer.write (l2n);
|
||||
}
|
||||
|
||||
|
|
@ -277,7 +277,7 @@ Class<db::LayoutToNetlist> decl_dbLayoutToNetlist ("db", "LayoutToNetlist",
|
|||
"This variant accepts a database-unit location. The location is given in the\n"
|
||||
"coordinate space of the initial cell.\n"
|
||||
) +
|
||||
gsi::method_ext ("write", &write_l2n, gsi::arg ("path"),
|
||||
gsi::method_ext ("write", &write_l2n, gsi::arg ("path"), gsi::arg ("short_format", false),
|
||||
"@brief Writes the extracted netlist to a file.\n"
|
||||
"This method employs the native format of KLayout.\n"
|
||||
),
|
||||
|
|
|
|||
|
|
@ -0,0 +1,66 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2019 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#include "dbLayoutToNetlist.h"
|
||||
#include "dbLayoutToNetlistReader.h"
|
||||
#include "dbLayoutToNetlistWriter.h"
|
||||
#include "dbStream.h"
|
||||
#include "dbCommonReader.h"
|
||||
#include "dbNetlistDeviceExtractorClasses.h"
|
||||
|
||||
#include "tlUnitTest.h"
|
||||
#include "tlStream.h"
|
||||
#include "tlFileUtils.h"
|
||||
|
||||
TEST(1_ReaderBasic)
|
||||
{
|
||||
db::Layout ly;
|
||||
|
||||
db::Cell &tc = ly.cell (ly.add_cell ("TOP"));
|
||||
db::LayoutToNetlist l2n (db::RecursiveShapeIterator (ly, tc, std::set<unsigned int> ()));
|
||||
|
||||
std::string in_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "l2n_writer_au.txt");
|
||||
tl::InputStream is_in (in_path);
|
||||
|
||||
db::LayoutToNetlistStandardReader reader (is_in);
|
||||
reader.read (&l2n);
|
||||
|
||||
// verify against the input
|
||||
|
||||
std::string path = tmp_file ("tmp_l2nreader_1.txt");
|
||||
{
|
||||
tl::OutputStream stream (path);
|
||||
db::LayoutToNetlistStandardWriter writer (stream, false);
|
||||
writer.write (&l2n);
|
||||
}
|
||||
|
||||
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)));
|
||||
}
|
||||
}
|
||||
|
|
@ -168,7 +168,7 @@ TEST(1_WriterBasic)
|
|||
std::string path = tmp_file ("tmp_l2nwriter_1.txt");
|
||||
{
|
||||
tl::OutputStream stream (path);
|
||||
db::LayoutToNetlistStandardWriter writer (stream);
|
||||
db::LayoutToNetlistStandardWriter writer (stream, false);
|
||||
writer.write (&l2n);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -64,7 +64,8 @@ SOURCES = \
|
|||
dbNetlistDeviceExtractorTests.cc \
|
||||
dbNetlistDeviceClassesTests.cc \
|
||||
dbLayoutToNetlistTests.cc \
|
||||
dbLayoutToNetlistWriterTests.cc
|
||||
dbLayoutToNetlistWriterTests.cc \
|
||||
dbLayoutToNetlistReaderTests.cc
|
||||
|
||||
INCLUDEPATH += $$TL_INC $$DB_INC $$GSI_INC
|
||||
DEPENDPATH += $$TL_INC $$DB_INC $$GSI_INC
|
||||
|
|
|
|||
|
|
@ -37,10 +37,10 @@ connect(nsd diff_cont nsd)
|
|||
# Device abstracts list the pin shapes of the devices.
|
||||
device(D$PMOS PMOS
|
||||
terminal(S
|
||||
rect(poly -125 -475 125 475)
|
||||
rect(psd -650 -475 -125 475)
|
||||
)
|
||||
terminal(G
|
||||
rect(psd -650 -475 -125 475)
|
||||
rect(poly -125 -475 125 475)
|
||||
)
|
||||
terminal(D
|
||||
rect(psd 125 -475 675 475)
|
||||
|
|
@ -48,10 +48,10 @@ device(D$PMOS PMOS
|
|||
)
|
||||
device(D$PMOS$1 PMOS
|
||||
terminal(S
|
||||
rect(poly -125 -475 125 475)
|
||||
rect(psd -675 -475 -125 475)
|
||||
)
|
||||
terminal(G
|
||||
rect(psd -675 -475 -125 475)
|
||||
rect(poly -125 -475 125 475)
|
||||
)
|
||||
terminal(D
|
||||
rect(psd 125 -475 650 475)
|
||||
|
|
@ -59,10 +59,10 @@ device(D$PMOS$1 PMOS
|
|||
)
|
||||
device(D$NMOS NMOS
|
||||
terminal(S
|
||||
rect(poly -125 -475 125 475)
|
||||
rect(nsd -650 -475 -125 475)
|
||||
)
|
||||
terminal(G
|
||||
rect(nsd -650 -475 -125 475)
|
||||
rect(poly -125 -475 125 475)
|
||||
)
|
||||
terminal(D
|
||||
rect(nsd 125 -475 675 475)
|
||||
|
|
@ -70,10 +70,10 @@ device(D$NMOS NMOS
|
|||
)
|
||||
device(D$NMOS$1 NMOS
|
||||
terminal(S
|
||||
rect(poly -125 -475 125 475)
|
||||
rect(nsd -675 -475 -125 475)
|
||||
)
|
||||
terminal(G
|
||||
rect(nsd -675 -475 -125 475)
|
||||
rect(poly -125 -475 125 475)
|
||||
)
|
||||
terminal(D
|
||||
rect(nsd 125 -475 650 475)
|
||||
|
|
@ -83,6 +83,135 @@ device(D$NMOS$1 NMOS
|
|||
# Circuit section
|
||||
# Circuits are the hierarchical building blocks of the netlist.
|
||||
|
||||
# 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 D$PMOS
|
||||
location(-400 2800)
|
||||
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 D$PMOS$1
|
||||
location(400 2800)
|
||||
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 D$NMOS
|
||||
location(-400 0)
|
||||
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 D$NMOS$1
|
||||
location(400 0)
|
||||
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)
|
||||
)
|
||||
|
||||
)
|
||||
|
||||
# Circuit RINGO
|
||||
circuit(RINGO
|
||||
|
||||
|
|
@ -280,61 +409,61 @@ circuit(RINGO
|
|||
)
|
||||
|
||||
# Subcircuits and their connections
|
||||
subcircuit($1 location(23760 0)
|
||||
circuit($1 INV2 location(23760 0)
|
||||
pin(IN $I8)
|
||||
pin($1 FB)
|
||||
pin($3 VSS)
|
||||
pin($4 VDD)
|
||||
)
|
||||
subcircuit($2 location(0 0)
|
||||
circuit($2 INV2 location(0 0)
|
||||
pin(IN FB)
|
||||
pin(OUT $I19)
|
||||
pin($3 VSS)
|
||||
pin($4 VDD)
|
||||
)
|
||||
subcircuit($3 location(2640 0)
|
||||
circuit($3 INV2 location(2640 0)
|
||||
pin(IN $I19)
|
||||
pin(OUT $I1)
|
||||
pin($3 VSS)
|
||||
pin($4 VDD)
|
||||
)
|
||||
subcircuit($4 location(5280 0)
|
||||
circuit($4 INV2 location(5280 0)
|
||||
pin(IN $I1)
|
||||
pin(OUT $I2)
|
||||
pin($3 VSS)
|
||||
pin($4 VDD)
|
||||
)
|
||||
subcircuit($5 location(7920 0)
|
||||
circuit($5 INV2 location(7920 0)
|
||||
pin(IN $I2)
|
||||
pin(OUT $I3)
|
||||
pin($3 VSS)
|
||||
pin($4 VDD)
|
||||
)
|
||||
subcircuit($6 location(10560 0)
|
||||
circuit($6 INV2 location(10560 0)
|
||||
pin(IN $I3)
|
||||
pin(OUT $I4)
|
||||
pin($3 VSS)
|
||||
pin($4 VDD)
|
||||
)
|
||||
subcircuit($7 location(13200 0)
|
||||
circuit($7 INV2 location(13200 0)
|
||||
pin(IN $I4)
|
||||
pin(OUT $I5)
|
||||
pin($3 VSS)
|
||||
pin($4 VDD)
|
||||
)
|
||||
subcircuit($8 location(15840 0)
|
||||
circuit($8 INV2 location(15840 0)
|
||||
pin(IN $I5)
|
||||
pin(OUT $I6)
|
||||
pin($3 VSS)
|
||||
pin($4 VDD)
|
||||
)
|
||||
subcircuit($9 location(18480 0)
|
||||
circuit($9 INV2 location(18480 0)
|
||||
pin(IN $I6)
|
||||
pin(OUT $I7)
|
||||
pin($3 VSS)
|
||||
pin($4 VDD)
|
||||
)
|
||||
subcircuit($10 location(21120 0)
|
||||
circuit($10 INV2 location(21120 0)
|
||||
pin(IN $I7)
|
||||
pin(OUT $I8)
|
||||
pin($3 VSS)
|
||||
|
|
@ -342,136 +471,3 @@ circuit(RINGO
|
|||
)
|
||||
|
||||
)
|
||||
|
||||
# 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)
|
||||
)
|
||||
|
||||
)
|
||||
|
|
|
|||
Loading…
Reference in New Issue