mirror of https://github.com/KLayout/klayout.git
Flattening of layout with circuit flattening.
Technically, the layout isn't flattened, but connections are made which allow regenerating the layout even after the circuit has been flattened.
This commit is contained in:
parent
198b5bb5e4
commit
b4fa4b1bae
|
|
@ -88,9 +88,7 @@ Circuit::~Circuit ()
|
|||
|
||||
// the default destructor will make the nets access "this" to unregister the
|
||||
// objects - hence we have to do this explicitly.
|
||||
m_nets.clear ();
|
||||
m_subcircuits.clear ();
|
||||
m_devices.clear ();
|
||||
clear ();
|
||||
}
|
||||
|
||||
Circuit &Circuit::operator= (const Circuit &other)
|
||||
|
|
@ -376,14 +374,22 @@ void Circuit::flatten_subcircuit (SubCircuit *subcircuit)
|
|||
db::Net *outside_net = 0;
|
||||
|
||||
if (n->pin_count () > 0) {
|
||||
|
||||
size_t pin_id = n->begin_pins ()->pin_id ();
|
||||
outside_net = subcircuit->net_for_pin (pin_id);
|
||||
|
||||
} else {
|
||||
|
||||
outside_net = new db::Net ();
|
||||
if (! n->name ().empty ()) {
|
||||
outside_net->set_name (subcircuit->expanded_name () + "." + n->name ());
|
||||
}
|
||||
add_net (outside_net);
|
||||
|
||||
if (netlist ()->callbacks ()) {
|
||||
outside_net->set_cluster_id (netlist ()->callbacks ()->link_net_to_parent_circuit (n.operator-> (), this, subcircuit->trans ()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
net2net.insert (std::make_pair (n.operator-> (), outside_net));
|
||||
|
|
|
|||
|
|
@ -41,6 +41,25 @@
|
|||
namespace db
|
||||
{
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
template <class Container, class Shape, class Trans> void insert_transformed (db::Layout &layout, Container &shapes, const Shape &s, const Trans &t);
|
||||
|
||||
template <class Container, class Trans> void insert_transformed (db::Layout &layout, Container &shapes, const db::PolygonRef &s, const Trans &t)
|
||||
{
|
||||
db::Polygon poly = s.obj ();
|
||||
poly.transform (s.trans ());
|
||||
if (! t.is_unity ()) {
|
||||
poly.transform (t);
|
||||
}
|
||||
shapes.insert (db::PolygonRef (poly, layout.shape_repository ()));
|
||||
}
|
||||
|
||||
template <class Container, class Trans> void insert_transformed (db::Layout & /*layout*/, Container &shapes, const db::Edge &s, const Trans &t)
|
||||
{
|
||||
shapes.insert (s.transformed (t));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Connectivity implementation
|
||||
|
||||
|
|
@ -993,7 +1012,6 @@ connected_clusters<T>::join_cluster_with (typename local_cluster<T>::id_type id,
|
|||
return;
|
||||
}
|
||||
|
||||
// join the shape clusters
|
||||
local_clusters<T>::join_cluster_with (id, with_id);
|
||||
|
||||
// handle the connections by translating
|
||||
|
|
@ -2115,23 +2133,6 @@ hier_clusters<T>::clusters_per_cell (db::cell_index_type cell_index)
|
|||
return c->second;
|
||||
}
|
||||
|
||||
template <class Shape, class Trans> void insert_transformed (db::Layout &layout, db::Shapes &shapes, const Shape &s, const Trans &t);
|
||||
|
||||
template <class Trans> void insert_transformed (db::Layout &layout, db::Shapes &shapes, const db::PolygonRef &s, const Trans &t)
|
||||
{
|
||||
db::Polygon poly = s.obj ();
|
||||
poly.transform (s.trans ());
|
||||
if (! t.is_unity ()) {
|
||||
poly.transform (t);
|
||||
}
|
||||
shapes.insert (db::PolygonRef (poly, layout.shape_repository ()));
|
||||
}
|
||||
|
||||
template <class Trans> void insert_transformed (db::Layout & /*layout*/, db::Shapes &shapes, const db::Edge &s, const Trans &t)
|
||||
{
|
||||
shapes.insert (s.transformed (t));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void
|
||||
hier_clusters<T>::return_to_hierarchy (db::Layout &layout, const std::map<unsigned int, unsigned int> &lm) const
|
||||
|
|
|
|||
|
|
@ -522,6 +522,14 @@ public:
|
|||
return --m_next_dummy_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating whether the given ID is a dummy ID
|
||||
*/
|
||||
bool is_dummy (typename local_cluster<T>::id_type id) const
|
||||
{
|
||||
return id > m_clusters.size ();
|
||||
}
|
||||
|
||||
private:
|
||||
void ensure_sorted ();
|
||||
|
||||
|
|
@ -600,12 +608,20 @@ public:
|
|||
return m_inst_prop_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Transform with the given transformation
|
||||
*/
|
||||
void transform (const db::ICplxTrans &tr)
|
||||
{
|
||||
m_inst_trans = tr * m_inst_trans;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Equality
|
||||
*/
|
||||
bool operator== (const ClusterInstElement &other) const
|
||||
{
|
||||
return m_inst_cell_index == other.m_inst_cell_index && m_inst_trans == other.m_inst_trans && m_inst_prop_id == other.m_inst_prop_id;
|
||||
return m_inst_cell_index == other.m_inst_cell_index && m_inst_trans.equal (other.m_inst_trans) && m_inst_prop_id == other.m_inst_prop_id;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -624,8 +640,8 @@ public:
|
|||
if (m_inst_cell_index != other.m_inst_cell_index) {
|
||||
return m_inst_cell_index < other.m_inst_cell_index;
|
||||
}
|
||||
if (m_inst_trans != other.m_inst_trans) {
|
||||
return m_inst_trans < other.m_inst_trans;
|
||||
if (! m_inst_trans.equal (other.m_inst_trans)) {
|
||||
return m_inst_trans.less (other.m_inst_trans);
|
||||
}
|
||||
return m_inst_prop_id < other.m_inst_prop_id;
|
||||
}
|
||||
|
|
@ -803,7 +819,7 @@ public:
|
|||
* The "with_id" cluster is removed. All connections of "with_id" are transferred to the
|
||||
* first one. All shapes of "with_id" are transferred to "id".
|
||||
*/
|
||||
void join_cluster_with (typename local_cluster<T>::id_type id, typename local_cluster<T>::id_type with_id);
|
||||
void join_cluster_with(typename local_cluster<T>::id_type id, typename local_cluster<T>::id_type with_id);
|
||||
|
||||
/**
|
||||
* @brief An iterator delivering all clusters (even the connectors)
|
||||
|
|
|
|||
|
|
@ -197,14 +197,36 @@ db::Region *LayoutToNetlist::make_polygon_layer (unsigned int layer_index, const
|
|||
return region.release ();
|
||||
}
|
||||
|
||||
size_t LayoutToNetlist::link_net_to_parent_circuit (const Net *subcircuit_net, Circuit *parent_circuit, const DCplxTrans &dtrans)
|
||||
{
|
||||
if (! subcircuit_net->circuit () || ! has_internal_layout () || ! internal_layout ()->is_valid_cell_index (parent_circuit->cell_index ())) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
db::CplxTrans dbu_trans (internal_layout ()->dbu ());
|
||||
db::ICplxTrans trans = dbu_trans.inverted () * dtrans * dbu_trans;
|
||||
|
||||
connected_clusters<db::PolygonRef> &parent_net_clusters = m_net_clusters.clusters_per_cell (parent_circuit->cell_index ());
|
||||
|
||||
size_t id = parent_net_clusters.insert_dummy (); // @@@
|
||||
|
||||
parent_net_clusters.add_connection (id, db::ClusterInstance (subcircuit_net->cluster_id (), subcircuit_net->circuit ()->cell_index (), trans, 0));
|
||||
return id;
|
||||
}
|
||||
|
||||
void LayoutToNetlist::ensure_netlist ()
|
||||
{
|
||||
if (! mp_netlist.get ()) {
|
||||
mp_netlist.reset (new db::Netlist (this));
|
||||
}
|
||||
}
|
||||
|
||||
void LayoutToNetlist::extract_devices (db::NetlistDeviceExtractor &extractor, const std::map<std::string, db::Region *> &layers)
|
||||
{
|
||||
if (m_netlist_extracted) {
|
||||
throw tl::Exception (tl::to_string (tr ("The netlist has already been extracted")));
|
||||
}
|
||||
if (! mp_netlist.get ()) {
|
||||
mp_netlist.reset (new db::Netlist ());
|
||||
}
|
||||
ensure_netlist ();
|
||||
extractor.extract (dss (), m_layout_index, layers, *mp_netlist, m_net_clusters, m_device_scaling);
|
||||
}
|
||||
|
||||
|
|
@ -277,9 +299,7 @@ void LayoutToNetlist::extract_netlist (const std::string &joined_net_names)
|
|||
if (m_netlist_extracted) {
|
||||
throw tl::Exception (tl::to_string (tr ("The netlist has already been extracted")));
|
||||
}
|
||||
if (! mp_netlist.get ()) {
|
||||
mp_netlist.reset (new db::Netlist ());
|
||||
}
|
||||
ensure_netlist ();
|
||||
|
||||
db::NetlistExtractor netex;
|
||||
netex.extract_nets (dss (), m_layout_index, m_conn, *mp_netlist, m_net_clusters, joined_net_names);
|
||||
|
|
@ -292,6 +312,11 @@ void LayoutToNetlist::set_netlist_extracted ()
|
|||
m_netlist_extracted = true;
|
||||
}
|
||||
|
||||
bool LayoutToNetlist::has_internal_layout () const
|
||||
{
|
||||
return mp_dss.get () && mp_dss->is_valid_layout_index (m_layout_index);
|
||||
}
|
||||
|
||||
const db::Layout *LayoutToNetlist::internal_layout () const
|
||||
{
|
||||
ensure_layout ();
|
||||
|
|
@ -540,9 +565,7 @@ db::Netlist *LayoutToNetlist::netlist () const
|
|||
|
||||
db::Netlist *LayoutToNetlist::make_netlist ()
|
||||
{
|
||||
if (! mp_netlist.get ()) {
|
||||
mp_netlist.reset (new db::Netlist ());
|
||||
}
|
||||
ensure_netlist ();
|
||||
return mp_netlist.get ();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ namespace db
|
|||
* @li
|
||||
*/
|
||||
class DB_PUBLIC LayoutToNetlist
|
||||
: public gsi::ObjectBase, public tl::Object
|
||||
: public gsi::ObjectBase, public db::NetlistManipulationCallbacks
|
||||
{
|
||||
public:
|
||||
typedef std::map<unsigned int, std::string>::const_iterator layer_iterator;
|
||||
|
|
@ -409,6 +409,11 @@ public:
|
|||
return *mp_dss;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns true, if there a layout is set
|
||||
*/
|
||||
bool has_internal_layout () const;
|
||||
|
||||
/**
|
||||
* @brief Gets the internal layout
|
||||
*/
|
||||
|
|
@ -756,6 +761,7 @@ private:
|
|||
typedef std::map<CellReuseTableKey, db::cell_index_type> cell_reuse_table_type;
|
||||
|
||||
void init ();
|
||||
void ensure_netlist ();
|
||||
size_t search_net (const db::ICplxTrans &trans, const db::Cell *cell, const db::local_cluster<db::PolygonRef> &test_cluster, std::vector<db::InstElement> &rev_inst_path);
|
||||
void build_net_rec (const db::Net &net, db::Layout &target, cell_index_type circuit_cell, const db::CellMapping &cmap, const std::map<unsigned int, const db::Region *> &lmap, const char *net_cell_name_prefix, db::properties_id_type netname_propid, BuildNetHierarchyMode hier_mode, const char *cell_name_prefix, const char *device_cell_name_prefix, cell_reuse_table_type &reuse_table, const ICplxTrans &tr) const;
|
||||
void build_net_rec (const db::Net &net, db::Layout &target, db::Cell &target_cell, const std::map<unsigned int, const db::Region *> &lmap, const char *net_cell_name_prefix, db::properties_id_type netname_propid, BuildNetHierarchyMode hier_mode, const char *cell_name_prefix, const char *device_cell_name_prefix, cell_reuse_table_type &reuse_table, const ICplxTrans &tr) const;
|
||||
|
|
@ -765,6 +771,9 @@ private:
|
|||
std::string make_new_name (const std::string &stem = std::string ());
|
||||
db::properties_id_type make_netname_propid (db::Layout &ly, const tl::Variant &netname_prop, const db::Net &net) const;
|
||||
db::CellMapping make_cell_mapping_into (db::Layout &layout, db::Cell &cell, const std::vector<const db::Net *> *nets, bool with_device_cells);
|
||||
|
||||
// implementation of NetlistManipulationCallbacks
|
||||
virtual size_t link_net_to_parent_circuit (const Net *subcircuit_net, Circuit *parent_circuit, const DCplxTrans &trans);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,8 +30,9 @@ namespace db
|
|||
// --------------------------------------------------------------------------------
|
||||
// Netlist class implementation
|
||||
|
||||
Netlist::Netlist ()
|
||||
: m_valid_topology (false), m_lock_count (0),
|
||||
Netlist::Netlist (NetlistManipulationCallbacks *callbacks)
|
||||
: mp_callbacks (callbacks),
|
||||
m_valid_topology (false), m_lock_count (0),
|
||||
m_circuit_by_name (this, &Netlist::begin_circuits, &Netlist::end_circuits),
|
||||
m_circuit_by_cell_index (this, &Netlist::begin_circuits, &Netlist::end_circuits),
|
||||
m_device_abstract_by_name (this, &Netlist::begin_device_abstracts, &Netlist::end_device_abstracts),
|
||||
|
|
|
|||
|
|
@ -35,6 +35,20 @@
|
|||
namespace db
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief An interface which connects the netlist with a layout representation
|
||||
* Specifically this interface allows manipulating the layout in sync with the netlist.
|
||||
*/
|
||||
class DB_PUBLIC NetlistManipulationCallbacks
|
||||
: public tl::Object
|
||||
{
|
||||
public:
|
||||
NetlistManipulationCallbacks () { }
|
||||
virtual ~NetlistManipulationCallbacks () { }
|
||||
|
||||
virtual size_t link_net_to_parent_circuit (const db::Net *subcircuit_net, db::Circuit *parent_circuit, const db::DCplxTrans &trans) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The netlist class
|
||||
*
|
||||
|
|
@ -65,7 +79,7 @@ public:
|
|||
*
|
||||
* This constructor creates an empty hierarchical netlist
|
||||
*/
|
||||
Netlist ();
|
||||
Netlist (NetlistManipulationCallbacks *callbacks = 0);
|
||||
|
||||
/**
|
||||
* @brief Copy constructor
|
||||
|
|
@ -480,6 +494,7 @@ private:
|
|||
friend class Circuit;
|
||||
friend class DeviceAbstract;
|
||||
|
||||
tl::weak_ptr<db::NetlistManipulationCallbacks> mp_callbacks;
|
||||
circuit_list m_circuits;
|
||||
device_class_list m_device_classes;
|
||||
device_abstract_list m_device_abstracts;
|
||||
|
|
@ -494,6 +509,11 @@ private:
|
|||
object_by_attr<Netlist, Netlist::device_abstract_iterator, name_attribute<DeviceAbstract> > m_device_abstract_by_name;
|
||||
object_by_attr<Netlist, Netlist::device_abstract_iterator, cell_index_attribute<DeviceAbstract> > m_device_abstract_by_cell_index;
|
||||
|
||||
db::NetlistManipulationCallbacks *callbacks ()
|
||||
{
|
||||
return mp_callbacks.get ();
|
||||
}
|
||||
|
||||
void invalidate_topology ();
|
||||
void validate_topology ();
|
||||
void circuits_changed ();
|
||||
|
|
|
|||
|
|
@ -2755,3 +2755,258 @@ TEST(11_DuplicateInstances)
|
|||
"end;\n"
|
||||
);
|
||||
}
|
||||
|
||||
TEST(12_FlattenCircuitDoesFlattenLayout)
|
||||
{
|
||||
db::Layout ly;
|
||||
db::LayerMap lmap;
|
||||
|
||||
unsigned int nwell = define_layer (ly, lmap, 1);
|
||||
unsigned int active = define_layer (ly, lmap, 2);
|
||||
unsigned int pplus = define_layer (ly, lmap, 10);
|
||||
unsigned int nplus = define_layer (ly, lmap, 11);
|
||||
unsigned int poly = define_layer (ly, lmap, 3);
|
||||
unsigned int poly_lbl = define_layer (ly, lmap, 3, 1);
|
||||
unsigned int diff_cont = define_layer (ly, lmap, 4);
|
||||
unsigned int poly_cont = define_layer (ly, lmap, 5);
|
||||
unsigned int metal1 = define_layer (ly, lmap, 6);
|
||||
unsigned int metal1_lbl = define_layer (ly, lmap, 6, 1);
|
||||
unsigned int via1 = define_layer (ly, lmap, 7);
|
||||
unsigned int metal2 = define_layer (ly, lmap, 8);
|
||||
unsigned int metal2_lbl = define_layer (ly, lmap, 8, 1);
|
||||
|
||||
{
|
||||
db::LoadLayoutOptions options;
|
||||
options.get_options<db::CommonReaderOptions> ().layer_map = lmap;
|
||||
options.get_options<db::CommonReaderOptions> ().create_other_layers = false;
|
||||
|
||||
std::string fn (tl::testsrc ());
|
||||
fn = tl::combine_path (fn, "testdata");
|
||||
fn = tl::combine_path (fn, "algo");
|
||||
fn = tl::combine_path (fn, "device_extract_l5.gds");
|
||||
|
||||
tl::InputStream stream (fn);
|
||||
db::Reader reader (stream);
|
||||
reader.read (ly, options);
|
||||
}
|
||||
|
||||
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> rbulk (l2n.make_layer ("bulk"));
|
||||
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> rpplus (l2n.make_layer (pplus, "pplus"));
|
||||
std::auto_ptr<db::Region> rnplus (l2n.make_layer (nplus, "nplus"));
|
||||
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 ractive_in_nwell = *ractive & *rnwell;
|
||||
db::Region rpactive = ractive_in_nwell & *rpplus;
|
||||
db::Region rntie = ractive_in_nwell & *rnplus;
|
||||
db::Region rpgate = rpactive & *rpoly;
|
||||
db::Region rpsd = rpactive - rpgate;
|
||||
|
||||
db::Region ractive_outside_nwell = *ractive - *rnwell;
|
||||
db::Region rnactive = ractive_outside_nwell & *rnplus;
|
||||
db::Region rptie = ractive_outside_nwell & *rpplus;
|
||||
db::Region rngate = rnactive & *rpoly;
|
||||
db::Region rnsd = rnactive - rngate;
|
||||
|
||||
// return the computed layers into the original layout and write it for debugging purposes
|
||||
|
||||
unsigned int lgate = ly.insert_layer (db::LayerProperties (20, 0)); // 20/0 -> Gate
|
||||
unsigned int lsd = ly.insert_layer (db::LayerProperties (21, 0)); // 21/0 -> Source/Drain
|
||||
unsigned int lpdiff = ly.insert_layer (db::LayerProperties (22, 0)); // 22/0 -> P Diffusion
|
||||
unsigned int lndiff = ly.insert_layer (db::LayerProperties (23, 0)); // 23/0 -> N Diffusion
|
||||
unsigned int lptie = ly.insert_layer (db::LayerProperties (24, 0)); // 24/0 -> P Tie
|
||||
unsigned int lntie = ly.insert_layer (db::LayerProperties (25, 0)); // 25/0 -> N Tie
|
||||
|
||||
rpgate.insert_into (&ly, tc.cell_index (), lgate);
|
||||
rngate.insert_into (&ly, tc.cell_index (), lgate);
|
||||
rpsd.insert_into (&ly, tc.cell_index (), lsd);
|
||||
rnsd.insert_into (&ly, tc.cell_index (), lsd);
|
||||
rpsd.insert_into (&ly, tc.cell_index (), lpdiff);
|
||||
rnsd.insert_into (&ly, tc.cell_index (), lndiff);
|
||||
rpsd.insert_into (&ly, tc.cell_index (), lptie);
|
||||
rnsd.insert_into (&ly, tc.cell_index (), lntie);
|
||||
|
||||
db::NetlistDeviceExtractorMOS4Transistor pmos_ex ("PMOS");
|
||||
db::NetlistDeviceExtractorMOS4Transistor nmos_ex ("NMOS");
|
||||
|
||||
// device extraction
|
||||
|
||||
db::NetlistDeviceExtractor::input_layers dl;
|
||||
|
||||
dl["SD"] = &rpsd;
|
||||
dl["G"] = &rpgate;
|
||||
dl["P"] = rpoly.get (); // not needed for extraction but to return terminal shapes
|
||||
dl["W"] = rnwell.get ();
|
||||
l2n.extract_devices (pmos_ex, dl);
|
||||
|
||||
dl["SD"] = &rnsd;
|
||||
dl["G"] = &rngate;
|
||||
dl["P"] = rpoly.get (); // not needed for extraction but to return terminal shapes
|
||||
dl["W"] = rbulk.get ();
|
||||
l2n.extract_devices (nmos_ex, dl);
|
||||
|
||||
// net extraction
|
||||
|
||||
l2n.register_layer (rpsd, "psd");
|
||||
l2n.register_layer (rnsd, "nsd");
|
||||
l2n.register_layer (rptie, "ptie");
|
||||
l2n.register_layer (rntie, "ntie");
|
||||
|
||||
// Intra-layer
|
||||
l2n.connect (rpsd);
|
||||
l2n.connect (rnsd);
|
||||
l2n.connect (*rnwell);
|
||||
l2n.connect (*rpoly);
|
||||
l2n.connect (*rdiff_cont);
|
||||
l2n.connect (*rpoly_cont);
|
||||
l2n.connect (*rmetal1);
|
||||
l2n.connect (*rvia1);
|
||||
l2n.connect (*rmetal2);
|
||||
l2n.connect (rptie);
|
||||
l2n.connect (rntie);
|
||||
// Inter-layer
|
||||
l2n.connect (rpsd, *rdiff_cont);
|
||||
l2n.connect (rnsd, *rdiff_cont);
|
||||
l2n.connect (*rpoly, *rpoly_cont);
|
||||
l2n.connect (*rpoly_cont, *rmetal1);
|
||||
l2n.connect (*rdiff_cont, *rmetal1);
|
||||
l2n.connect (*rdiff_cont, rptie);
|
||||
l2n.connect (*rdiff_cont, rntie);
|
||||
l2n.connect (*rnwell, rntie);
|
||||
l2n.connect (*rmetal1, *rvia1);
|
||||
l2n.connect (*rvia1, *rmetal2);
|
||||
l2n.connect (*rpoly, *rpoly_lbl); // attaches labels
|
||||
l2n.connect (*rmetal1, *rmetal1_lbl); // attaches labels
|
||||
l2n.connect (*rmetal2, *rmetal2_lbl); // attaches labels
|
||||
// Global
|
||||
l2n.connect_global (rptie, "BULK");
|
||||
l2n.connect_global (*rbulk, "BULK");
|
||||
|
||||
// create some mess - we have to keep references to the layers to make them not disappear
|
||||
rmetal1_lbl.reset (0);
|
||||
rmetal2_lbl.reset (0);
|
||||
rpoly_lbl.reset (0);
|
||||
|
||||
l2n.extract_netlist ();
|
||||
|
||||
l2n.netlist ()->flatten_circuit (l2n.netlist ()->circuit_by_name ("INV2"));
|
||||
l2n.netlist ()->flatten_circuit (l2n.netlist ()->circuit_by_name ("INV2PAIR"));
|
||||
l2n.netlist ()->flatten_circuit (l2n.netlist ()->circuit_by_name ("TRANS"));
|
||||
|
||||
// debug layers produced for nets
|
||||
// 201/0 -> Well
|
||||
// 203/0 -> Poly
|
||||
// 204/0 -> Diffusion contacts
|
||||
// 205/0 -> Poly contacts
|
||||
// 206/0 -> Metal1
|
||||
// 207/0 -> Via1
|
||||
// 208/0 -> Metal2
|
||||
// 210/0 -> N source/drain
|
||||
// 211/0 -> P source/drain
|
||||
// 212/0 -> N tie
|
||||
// 213/0 -> P tie
|
||||
std::map<const db::Region *, unsigned int> dump_map;
|
||||
dump_map [&rpsd ] = ly.insert_layer (db::LayerProperties (210, 0));
|
||||
dump_map [&rnsd ] = ly.insert_layer (db::LayerProperties (211, 0));
|
||||
dump_map [&rptie ] = ly.insert_layer (db::LayerProperties (212, 0));
|
||||
dump_map [&rntie ] = ly.insert_layer (db::LayerProperties (213, 0));
|
||||
dump_map [rbulk.get () ] = ly.insert_layer (db::LayerProperties (214, 0));
|
||||
dump_map [rnwell.get () ] = ly.insert_layer (db::LayerProperties (201, 0));
|
||||
dump_map [rpoly.get () ] = ly.insert_layer (db::LayerProperties (203, 0));
|
||||
dump_map [rdiff_cont.get ()] = ly.insert_layer (db::LayerProperties (204, 0));
|
||||
dump_map [rpoly_cont.get ()] = ly.insert_layer (db::LayerProperties (205, 0));
|
||||
dump_map [rmetal1.get () ] = ly.insert_layer (db::LayerProperties (206, 0));
|
||||
dump_map [rvia1.get () ] = ly.insert_layer (db::LayerProperties (207, 0));
|
||||
dump_map [rmetal2.get () ] = ly.insert_layer (db::LayerProperties (208, 0));
|
||||
|
||||
// write nets to layout
|
||||
db::CellMapping cm = l2n.cell_mapping_into (ly, tc);
|
||||
dump_nets_to_layout (l2n, ly, dump_map, cm);
|
||||
|
||||
dump_map.clear ();
|
||||
dump_map [&rpsd ] = ly.insert_layer (db::LayerProperties (310, 0));
|
||||
dump_map [&rnsd ] = ly.insert_layer (db::LayerProperties (311, 0));
|
||||
dump_map [&rptie ] = ly.insert_layer (db::LayerProperties (312, 0));
|
||||
dump_map [&rntie ] = ly.insert_layer (db::LayerProperties (313, 0));
|
||||
dump_map [rbulk.get () ] = ly.insert_layer (db::LayerProperties (314, 0));
|
||||
dump_map [rnwell.get () ] = ly.insert_layer (db::LayerProperties (301, 0));
|
||||
dump_map [rpoly.get () ] = ly.insert_layer (db::LayerProperties (303, 0));
|
||||
dump_map [rdiff_cont.get ()] = ly.insert_layer (db::LayerProperties (304, 0));
|
||||
dump_map [rpoly_cont.get ()] = ly.insert_layer (db::LayerProperties (305, 0));
|
||||
dump_map [rmetal1.get () ] = ly.insert_layer (db::LayerProperties (306, 0));
|
||||
dump_map [rvia1.get () ] = ly.insert_layer (db::LayerProperties (307, 0));
|
||||
dump_map [rmetal2.get () ] = ly.insert_layer (db::LayerProperties (308, 0));
|
||||
|
||||
dump_recursive_nets_to_layout (l2n, ly, dump_map, cm);
|
||||
|
||||
// compare netlist as string
|
||||
CHECKPOINT ();
|
||||
db::compare_netlist (_this, *l2n.netlist (),
|
||||
"circuit RINGO ();\n"
|
||||
" device PMOS $1 (S=FB,G=$I7,D=VDD,B=VDD) (L=0.25,W=1.75,AS=0.91875,AD=0.48125,PS=4.55,PD=2.3);\n"
|
||||
" device PMOS $2 (S=VDD,G=$I7,D=FB,B=VDD) (L=0.25,W=1.75,AS=0.48125,AD=0.91875,PS=2.3,PD=4.55);\n"
|
||||
" device NMOS $3 (S=FB,G=$I7,D=VSS,B=VSS) (L=0.25,W=1.75,AS=0.91875,AD=0.48125,PS=4.55,PD=2.3);\n"
|
||||
" device NMOS $4 (S=VSS,G=$I7,D=FB,B=VSS) (L=0.25,W=1.75,AS=0.48125,AD=0.91875,PS=2.3,PD=4.55);\n"
|
||||
" device PMOS $5 (S=OSC,G=FB,D=VDD,B=VDD) (L=0.25,W=1.75,AS=0.91875,AD=0.48125,PS=4.55,PD=2.3);\n"
|
||||
" device PMOS $6 (S=VDD,G=FB,D=OSC,B=VDD) (L=0.25,W=1.75,AS=0.48125,AD=0.91875,PS=2.3,PD=4.55);\n"
|
||||
" device NMOS $7 (S=OSC,G=FB,D=VSS,B=VSS) (L=0.25,W=1.75,AS=0.91875,AD=0.48125,PS=4.55,PD=2.3);\n"
|
||||
" device NMOS $8 (S=VSS,G=FB,D=OSC,B=VSS) (L=0.25,W=1.75,AS=0.48125,AD=0.91875,PS=2.3,PD=4.55);\n"
|
||||
" device PMOS $9 (S=$I22,G=FB,D=VDD,B=VDD) (L=0.25,W=1.75,AS=0.91875,AD=0.48125,PS=4.55,PD=2.3);\n"
|
||||
" device PMOS $10 (S=VDD,G=FB,D=$I22,B=VDD) (L=0.25,W=1.75,AS=0.48125,AD=0.91875,PS=2.3,PD=4.55);\n"
|
||||
" device NMOS $11 (S=$I22,G=FB,D=VSS,B=VSS) (L=0.25,W=1.75,AS=0.91875,AD=0.48125,PS=4.55,PD=2.3);\n"
|
||||
" device NMOS $12 (S=VSS,G=FB,D=$I22,B=VSS) (L=0.25,W=1.75,AS=0.48125,AD=0.91875,PS=2.3,PD=4.55);\n"
|
||||
" device PMOS $13 (S=$I13,G=$I22,D=VDD,B=VDD) (L=0.25,W=1.75,AS=0.91875,AD=0.48125,PS=4.55,PD=2.3);\n"
|
||||
" device PMOS $14 (S=VDD,G=$I22,D=$I13,B=VDD) (L=0.25,W=1.75,AS=0.48125,AD=0.91875,PS=2.3,PD=4.55);\n"
|
||||
" device NMOS $15 (S=$I13,G=$I22,D=VSS,B=VSS) (L=0.25,W=1.75,AS=0.91875,AD=0.48125,PS=4.55,PD=2.3);\n"
|
||||
" device NMOS $16 (S=VSS,G=$I22,D=$I13,B=VSS) (L=0.25,W=1.75,AS=0.48125,AD=0.91875,PS=2.3,PD=4.55);\n"
|
||||
" device PMOS $17 (S=$I23,G=$I13,D=VDD,B=VDD) (L=0.25,W=1.75,AS=0.91875,AD=0.48125,PS=4.55,PD=2.3);\n"
|
||||
" device PMOS $18 (S=VDD,G=$I13,D=$I23,B=VDD) (L=0.25,W=1.75,AS=0.48125,AD=0.91875,PS=2.3,PD=4.55);\n"
|
||||
" device NMOS $19 (S=$I23,G=$I13,D=VSS,B=VSS) (L=0.25,W=1.75,AS=0.91875,AD=0.48125,PS=4.55,PD=2.3);\n"
|
||||
" device NMOS $20 (S=VSS,G=$I13,D=$I23,B=VSS) (L=0.25,W=1.75,AS=0.48125,AD=0.91875,PS=2.3,PD=4.55);\n"
|
||||
" device PMOS $21 (S=$I5,G=$I23,D=VDD,B=VDD) (L=0.25,W=1.75,AS=0.91875,AD=0.48125,PS=4.55,PD=2.3);\n"
|
||||
" device PMOS $22 (S=VDD,G=$I23,D=$I5,B=VDD) (L=0.25,W=1.75,AS=0.48125,AD=0.91875,PS=2.3,PD=4.55);\n"
|
||||
" device NMOS $23 (S=$I5,G=$I23,D=VSS,B=VSS) (L=0.25,W=1.75,AS=0.91875,AD=0.48125,PS=4.55,PD=2.3);\n"
|
||||
" device NMOS $24 (S=VSS,G=$I23,D=$I5,B=VSS) (L=0.25,W=1.75,AS=0.48125,AD=0.91875,PS=2.3,PD=4.55);\n"
|
||||
" device PMOS $25 (S=$I24,G=$I5,D=VDD,B=VDD) (L=0.25,W=1.75,AS=0.91875,AD=0.48125,PS=4.55,PD=2.3);\n"
|
||||
" device PMOS $26 (S=VDD,G=$I5,D=$I24,B=VDD) (L=0.25,W=1.75,AS=0.48125,AD=0.91875,PS=2.3,PD=4.55);\n"
|
||||
" device NMOS $27 (S=$I24,G=$I5,D=VSS,B=VSS) (L=0.25,W=1.75,AS=0.91875,AD=0.48125,PS=4.55,PD=2.3);\n"
|
||||
" device NMOS $28 (S=VSS,G=$I5,D=$I24,B=VSS) (L=0.25,W=1.75,AS=0.48125,AD=0.91875,PS=2.3,PD=4.55);\n"
|
||||
" device PMOS $29 (S=$I6,G=$I24,D=VDD,B=VDD) (L=0.25,W=1.75,AS=0.91875,AD=0.48125,PS=4.55,PD=2.3);\n"
|
||||
" device PMOS $30 (S=VDD,G=$I24,D=$I6,B=VDD) (L=0.25,W=1.75,AS=0.48125,AD=0.91875,PS=2.3,PD=4.55);\n"
|
||||
" device NMOS $31 (S=$I6,G=$I24,D=VSS,B=VSS) (L=0.25,W=1.75,AS=0.91875,AD=0.48125,PS=4.55,PD=2.3);\n"
|
||||
" device NMOS $32 (S=VSS,G=$I24,D=$I6,B=VSS) (L=0.25,W=1.75,AS=0.48125,AD=0.91875,PS=2.3,PD=4.55);\n"
|
||||
" device PMOS $33 (S=$I25,G=$I6,D=VDD,B=VDD) (L=0.25,W=1.75,AS=0.91875,AD=0.48125,PS=4.55,PD=2.3);\n"
|
||||
" device PMOS $34 (S=VDD,G=$I6,D=$I25,B=VDD) (L=0.25,W=1.75,AS=0.48125,AD=0.91875,PS=2.3,PD=4.55);\n"
|
||||
" device NMOS $35 (S=$I25,G=$I6,D=VSS,B=VSS) (L=0.25,W=1.75,AS=0.91875,AD=0.48125,PS=4.55,PD=2.3);\n"
|
||||
" device NMOS $36 (S=VSS,G=$I6,D=$I25,B=VSS) (L=0.25,W=1.75,AS=0.48125,AD=0.91875,PS=2.3,PD=4.55);\n"
|
||||
" device PMOS $37 (S=$I7,G=$I25,D=VDD,B=VDD) (L=0.25,W=1.75,AS=0.91875,AD=0.48125,PS=4.55,PD=2.3);\n"
|
||||
" device PMOS $38 (S=VDD,G=$I25,D=$I7,B=VDD) (L=0.25,W=1.75,AS=0.48125,AD=0.91875,PS=2.3,PD=4.55);\n"
|
||||
" device NMOS $39 (S=$I7,G=$I25,D=VSS,B=VSS) (L=0.25,W=1.75,AS=0.91875,AD=0.48125,PS=4.55,PD=2.3);\n"
|
||||
" device NMOS $40 (S=VSS,G=$I25,D=$I7,B=VSS) (L=0.25,W=1.75,AS=0.48125,AD=0.91875,PS=2.3,PD=4.55);\n"
|
||||
"end;\n"
|
||||
);
|
||||
|
||||
// compare the collected test data
|
||||
|
||||
std::string au = tl::testsrc ();
|
||||
au = tl::combine_path (au, "testdata");
|
||||
au = tl::combine_path (au, "algo");
|
||||
au = tl::combine_path (au, "device_extract_au5_flattened_circuits.gds");
|
||||
|
||||
db::compare_layouts (_this, ly, au);
|
||||
}
|
||||
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -185,10 +185,22 @@ layout(
|
|||
rect(l8 (17310 3010) (180 180))
|
||||
rect(l11 (-1140 -240) (900 300))
|
||||
)
|
||||
net(12)
|
||||
net(13)
|
||||
net(14)
|
||||
net(15)
|
||||
net(12
|
||||
rect(l8 (10110 3010) (180 180))
|
||||
rect(l11 (-1140 -240) (900 300))
|
||||
)
|
||||
net(13
|
||||
rect(l8 (11910 3010) (180 180))
|
||||
rect(l11 (-1140 -240) (900 300))
|
||||
)
|
||||
net(14
|
||||
rect(l8 (13710 3010) (180 180))
|
||||
rect(l11 (-1140 -240) (900 300))
|
||||
)
|
||||
net(15
|
||||
rect(l8 (15510 3010) (180 180))
|
||||
rect(l11 (-1140 -240) (900 300))
|
||||
)
|
||||
|
||||
# Outgoing pins and their connections to nets
|
||||
pin(5 name(FB))
|
||||
|
|
|
|||
|
|
@ -621,10 +621,30 @@ layout(
|
|||
rect(l2 (-1275 1800) (425 1500))
|
||||
rect(l6 (-425 -4890) (425 950))
|
||||
)
|
||||
net(12)
|
||||
net(13)
|
||||
net(14)
|
||||
net(15)
|
||||
net(12
|
||||
rect(l8 (10110 3010) (180 180))
|
||||
rect(l11 (-1140 -240) (900 300))
|
||||
rect(l2 (-1275 1800) (425 1500))
|
||||
rect(l6 (-425 -4890) (425 950))
|
||||
)
|
||||
net(13
|
||||
rect(l8 (11910 3010) (180 180))
|
||||
rect(l11 (-1140 -240) (900 300))
|
||||
rect(l2 (-1275 1800) (425 1500))
|
||||
rect(l6 (-425 -4890) (425 950))
|
||||
)
|
||||
net(14
|
||||
rect(l8 (13710 3010) (180 180))
|
||||
rect(l11 (-1140 -240) (900 300))
|
||||
rect(l2 (-1275 1800) (425 1500))
|
||||
rect(l6 (-425 -4890) (425 950))
|
||||
)
|
||||
net(15
|
||||
rect(l8 (15510 3010) (180 180))
|
||||
rect(l11 (-1140 -240) (900 300))
|
||||
rect(l2 (-1275 1800) (425 1500))
|
||||
rect(l6 (-425 -4890) (425 950))
|
||||
)
|
||||
|
||||
# Outgoing pins and their connections to nets
|
||||
pin(5 name(FB))
|
||||
|
|
|
|||
|
|
@ -621,10 +621,30 @@ layout(
|
|||
rect(l2 (-1275 1800) (425 1500))
|
||||
rect(l6 (-425 -4890) (425 950))
|
||||
)
|
||||
net(12)
|
||||
net(13)
|
||||
net(14)
|
||||
net(15)
|
||||
net(12
|
||||
rect(l8 (10110 3010) (180 180))
|
||||
rect(l11 (-1140 -240) (900 300))
|
||||
rect(l2 (-1275 1800) (425 1500))
|
||||
rect(l6 (-425 -4890) (425 950))
|
||||
)
|
||||
net(13
|
||||
rect(l8 (11910 3010) (180 180))
|
||||
rect(l11 (-1140 -240) (900 300))
|
||||
rect(l2 (-1275 1800) (425 1500))
|
||||
rect(l6 (-425 -4890) (425 950))
|
||||
)
|
||||
net(14
|
||||
rect(l8 (13710 3010) (180 180))
|
||||
rect(l11 (-1140 -240) (900 300))
|
||||
rect(l2 (-1275 1800) (425 1500))
|
||||
rect(l6 (-425 -4890) (425 950))
|
||||
)
|
||||
net(15
|
||||
rect(l8 (15510 3010) (180 180))
|
||||
rect(l11 (-1140 -240) (900 300))
|
||||
rect(l2 (-1275 1800) (425 1500))
|
||||
rect(l6 (-425 -4890) (425 950))
|
||||
)
|
||||
|
||||
# Outgoing pins and their connections to nets
|
||||
pin(5 name(FB))
|
||||
|
|
|
|||
Loading…
Reference in New Issue