mirror of https://github.com/KLayout/klayout.git
WIP: cold references - keep reference information while libraries are not there or cells are missing.
This commit is contained in:
parent
fcf4fd74f6
commit
ab36a660fb
|
|
@ -19,6 +19,7 @@ SOURCES = \
|
|||
dbClipboard.cc \
|
||||
dbClipboardData.cc \
|
||||
dbClip.cc \
|
||||
dbColdProxy.cc \
|
||||
dbCommonReader.cc \
|
||||
dbEdge.cc \
|
||||
dbEdgePair.cc \
|
||||
|
|
@ -214,6 +215,7 @@ HEADERS = \
|
|||
dbClipboardData.h \
|
||||
dbClipboard.h \
|
||||
dbClip.h \
|
||||
dbColdProxy.h \
|
||||
dbCommonReader.h \
|
||||
dbEdge.h \
|
||||
dbEdgePair.h \
|
||||
|
|
|
|||
|
|
@ -0,0 +1,128 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2020 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 "dbColdProxy.h"
|
||||
#include "dbLibraryManager.h"
|
||||
#include "dbLibrary.h"
|
||||
#include "dbLayout.h"
|
||||
#include "dbLayoutUtils.h"
|
||||
|
||||
#include "tlThreads.h"
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
static tl::Mutex s_map_mutex;
|
||||
static std::map<std::string, tl::weak_collection<ColdProxy> > s_proxies_per_library_name;
|
||||
|
||||
const tl::weak_collection<ColdProxy> &
|
||||
ColdProxy::cold_proxies_per_lib_name (const std::string &libname)
|
||||
{
|
||||
tl::MutexLocker locker (&s_map_mutex);
|
||||
|
||||
std::map<std::string, tl::weak_collection<ColdProxy> >::const_iterator i = s_proxies_per_library_name.find (libname);
|
||||
if (i != s_proxies_per_library_name.end ()) {
|
||||
return i->second;
|
||||
} else {
|
||||
static tl::weak_collection<ColdProxy> s_empty;
|
||||
return s_empty;
|
||||
}
|
||||
}
|
||||
|
||||
ColdProxy::ColdProxy (db::cell_index_type ci, db::Layout &layout, const ProxyContextInfo &info)
|
||||
: Cell (ci, layout), mp_context_info (new ProxyContextInfo (info))
|
||||
{
|
||||
if (! info.lib_name.empty ()) {
|
||||
tl::MutexLocker locker (&s_map_mutex);
|
||||
s_proxies_per_library_name [info.lib_name].push_back (this);
|
||||
}
|
||||
}
|
||||
|
||||
ColdProxy::~ColdProxy ()
|
||||
{
|
||||
delete mp_context_info;
|
||||
mp_context_info = 0;
|
||||
}
|
||||
|
||||
Cell *
|
||||
ColdProxy::clone (Layout &layout) const
|
||||
{
|
||||
Cell *cell = new ColdProxy (db::Cell::cell_index (), layout, *mp_context_info);
|
||||
// copy the cell content
|
||||
*cell = *this;
|
||||
return cell;
|
||||
}
|
||||
|
||||
std::string
|
||||
ColdProxy::get_basic_name () const
|
||||
{
|
||||
if (! mp_context_info->pcell_name.empty ()) {
|
||||
return "<defunc>" + mp_context_info->pcell_name;
|
||||
} else if (! mp_context_info->cell_name.empty ()) {
|
||||
return "<defunc>" + mp_context_info->cell_name;
|
||||
} else {
|
||||
return Cell::get_basic_name ();
|
||||
}
|
||||
}
|
||||
|
||||
std::string
|
||||
ColdProxy::get_display_name () const
|
||||
{
|
||||
if (! mp_context_info->lib_name.empty ()) {
|
||||
std::string stem = "<defunct>" + mp_context_info->lib_name + ".";
|
||||
if (! mp_context_info->pcell_name.empty ()) {
|
||||
return stem + mp_context_info->pcell_name;
|
||||
} else if (! mp_context_info->cell_name.empty ()) {
|
||||
return stem + mp_context_info->cell_name;
|
||||
} else {
|
||||
return stem + "<unknown>";
|
||||
}
|
||||
} else {
|
||||
return Cell::get_display_name ();
|
||||
}
|
||||
}
|
||||
|
||||
std::string
|
||||
ColdProxy::get_qualified_name () const
|
||||
{
|
||||
if (! mp_context_info->lib_name.empty ()) {
|
||||
std::string stem = "<defunct>" + mp_context_info->lib_name + ".";
|
||||
if (! mp_context_info->pcell_name.empty ()) {
|
||||
if (mp_context_info->pcell_parameters.empty ()) {
|
||||
return stem + mp_context_info->pcell_name;
|
||||
} else {
|
||||
// TODO: list parameters? Might be long.
|
||||
return stem + mp_context_info->pcell_name + "(...)";
|
||||
}
|
||||
} else if (! mp_context_info->cell_name.empty ()) {
|
||||
return stem + mp_context_info->cell_name;
|
||||
} else {
|
||||
return stem + "<unknown>";
|
||||
}
|
||||
} else {
|
||||
return Cell::get_qualified_name ();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2020 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_dbColdProxy
|
||||
#define HDR_dbColdProxy
|
||||
|
||||
#include "dbCommon.h"
|
||||
|
||||
#include "dbTypes.h"
|
||||
#include "dbCell.h"
|
||||
|
||||
#include "tlObject.h"
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
struct ProxyContextInfo;
|
||||
|
||||
/**
|
||||
* @brief A cell specialization: a cold proxy representing a library or PCell which has gone out of scope
|
||||
*
|
||||
* If a PCell or library cell gets disconnected - for example, because the technology has changed or during
|
||||
* development of PCell code - this proxy replaces the original one. It stores the connection information, so
|
||||
* it can be regenerated when it becomes valid again.
|
||||
*/
|
||||
class DB_PUBLIC ColdProxy
|
||||
: public Cell, public tl::Object
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief The constructor
|
||||
*
|
||||
* Creates a cold proxy represented by the ProxyContextInfo data.
|
||||
*/
|
||||
ColdProxy (db::cell_index_type ci, db::Layout &layout, const ProxyContextInfo &info);
|
||||
|
||||
/**
|
||||
* @brief The destructor
|
||||
*/
|
||||
~ColdProxy ();
|
||||
|
||||
/**
|
||||
* @brief Cloning
|
||||
*/
|
||||
virtual Cell *clone (Layout &layout) const;
|
||||
|
||||
/**
|
||||
* @brief Get the library id
|
||||
*/
|
||||
const ProxyContextInfo &context_info () const
|
||||
{
|
||||
return *mp_context_info;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Indicates that this cell is a proxy cell
|
||||
*/
|
||||
virtual bool is_proxy () const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets a list of cold proxies for a given library name
|
||||
*/
|
||||
static const tl::weak_collection<ColdProxy> &cold_proxies_per_lib_name (const std::string &libname);
|
||||
|
||||
/**
|
||||
* @brief Gets the basic name
|
||||
*/
|
||||
virtual std::string get_basic_name () const;
|
||||
|
||||
/**
|
||||
* @brief Gets the display name
|
||||
*/
|
||||
virtual std::string get_display_name () const;
|
||||
|
||||
/**
|
||||
* @brief Gets the qualified name
|
||||
*/
|
||||
virtual std::string get_qualified_name () const;
|
||||
|
||||
private:
|
||||
ProxyContextInfo *mp_context_info;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
|
@ -30,6 +30,7 @@
|
|||
#include "dbPCellVariant.h"
|
||||
#include "dbPCellDeclaration.h"
|
||||
#include "dbLibraryProxy.h"
|
||||
#include "dbColdProxy.h"
|
||||
#include "dbLibraryManager.h"
|
||||
#include "dbLibrary.h"
|
||||
#include "dbRegion.h"
|
||||
|
|
@ -260,6 +261,65 @@ LayerIterator::operator*() const
|
|||
return std::pair<unsigned int, const db::LayerProperties *> (m_layer_index, &m_layout.get_properties (m_layer_index));
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
// Implementation of the ProxyContextInfo class
|
||||
|
||||
ProxyContextInfo
|
||||
ProxyContextInfo::deserialize (std::vector<std::string>::const_iterator from, std::vector<std::string>::const_iterator to)
|
||||
{
|
||||
ProxyContextInfo info;
|
||||
|
||||
for (std::vector<std::string>::const_iterator i = from; i != to; ++i) {
|
||||
|
||||
tl::Extractor ex (i->c_str ());
|
||||
|
||||
if (ex.test ("LIB=")) {
|
||||
|
||||
info.lib_name = ex.skip ();
|
||||
|
||||
} else if (ex.test ("P(")) {
|
||||
|
||||
std::pair<std::string, tl::Variant> vv;
|
||||
|
||||
ex.read_word_or_quoted (vv.first);
|
||||
ex.test (")");
|
||||
ex.test ("=");
|
||||
ex.read (vv.second);
|
||||
|
||||
info.pcell_parameters.insert (vv);
|
||||
|
||||
} else if (ex.test ("PCELL=")) {
|
||||
|
||||
info.pcell_name = ex.skip ();
|
||||
|
||||
} else if (ex.test ("CELL=")) {
|
||||
|
||||
info.cell_name = ex.skip ();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
void
|
||||
ProxyContextInfo::serialize (std::vector<std::string> &strings)
|
||||
{
|
||||
if (! lib_name.empty ()) {
|
||||
strings.push_back ("LIB=" + lib_name);
|
||||
}
|
||||
for (std::map<std::string, tl::Variant> ::const_iterator p = pcell_parameters.begin (); p != pcell_parameters.end (); ++p) {
|
||||
strings.push_back ("P(" + tl::to_word_or_quoted_string (p->first) + ")=" + p->second.to_parsable_string ());
|
||||
}
|
||||
if (! pcell_name.empty ()) {
|
||||
strings.push_back ("PCELL=" + pcell_name);
|
||||
}
|
||||
if (! cell_name.empty ()) {
|
||||
strings.push_back ("CELL=" + cell_name);
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
// Implementation of the Layout class
|
||||
|
||||
|
|
@ -522,12 +582,10 @@ Layout::set_technology_name (const std::string &tech)
|
|||
|
||||
if (! pn.first) {
|
||||
|
||||
// substitute by static layout cell
|
||||
// @@@ TODO: keep reference so we don't loose the connection immediately.
|
||||
std::string name = cell_name (ci);
|
||||
db::Cell *old_cell = take_cell (ci);
|
||||
insert_cell (ci, name, new db::Cell (*old_cell));
|
||||
delete old_cell;
|
||||
// substitute by a cold proxy
|
||||
db::ProxyContextInfo info;
|
||||
get_context_info (ci, info);
|
||||
create_cold_proxy_as (info, ci);
|
||||
|
||||
} else {
|
||||
|
||||
|
|
@ -537,12 +595,10 @@ Layout::set_technology_name (const std::string &tech)
|
|||
const db::PCellDeclaration *new_pcell_decl = new_lib->layout ().pcell_declaration (pn.second);
|
||||
if (! old_pcell_decl || ! new_pcell_decl) {
|
||||
|
||||
// substitute by static layout cell
|
||||
// @@@ TODO: keep reference so we don't loose the connection immediately.
|
||||
std::string name = cell_name (ci);
|
||||
db::Cell *old_cell = take_cell (ci);
|
||||
insert_cell (ci, name, new db::Cell (*old_cell));
|
||||
delete old_cell;
|
||||
// substitute by a cold proxy
|
||||
db::ProxyContextInfo info;
|
||||
get_context_info (ci, info);
|
||||
create_cold_proxy_as (info, ci);
|
||||
|
||||
} else {
|
||||
|
||||
|
|
@ -566,12 +622,10 @@ Layout::set_technology_name (const std::string &tech)
|
|||
|
||||
if (! cn.first) {
|
||||
|
||||
// unlink this proxy: substitute by static layout cell
|
||||
// @@@ TODO: keep reference so we don't loose the connection immediately.
|
||||
std::string name = cell_name (ci);
|
||||
db::Cell *old_cell = take_cell (ci);
|
||||
insert_cell (ci, name, new db::Cell (*old_cell));
|
||||
delete old_cell;
|
||||
// unlink this proxy: substitute by a cold proxy
|
||||
db::ProxyContextInfo info;
|
||||
get_context_info (ci, info);
|
||||
create_cold_proxy_as (info, ci);
|
||||
|
||||
} else {
|
||||
|
||||
|
|
@ -588,6 +642,9 @@ Layout::set_technology_name (const std::string &tech)
|
|||
}
|
||||
|
||||
m_tech_name = tech;
|
||||
|
||||
// we may have re-established a connection for pending ("cold") proxies so we can try to restore them
|
||||
restore_proxies ();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -1948,8 +2005,26 @@ static const std::vector<tl::Variant> &gauge_parameters (const std::vector<tl::V
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
Layout::replace_cell (cell_index_type target_cell_index, db::Cell *new_cell, bool retain_layout)
|
||||
{
|
||||
invalidate_hier ();
|
||||
|
||||
db::Cell *old_cell = m_cell_ptrs [target_cell_index];
|
||||
if (old_cell) {
|
||||
old_cell->unregister ();
|
||||
if (retain_layout) {
|
||||
new_cell->Cell::operator= (*old_cell);
|
||||
}
|
||||
}
|
||||
|
||||
m_cells.erase (iterator (old_cell));
|
||||
m_cells.push_back_ptr (new_cell);
|
||||
m_cell_ptrs [target_cell_index] = new_cell;
|
||||
}
|
||||
|
||||
void
|
||||
Layout::get_pcell_variant_as (pcell_id_type pcell_id, const std::vector<tl::Variant> &p, cell_index_type target_cell_index, ImportLayerMapping *layer_mapping)
|
||||
Layout::get_pcell_variant_as (pcell_id_type pcell_id, const std::vector<tl::Variant> &p, cell_index_type target_cell_index, ImportLayerMapping *layer_mapping, bool retain_layout)
|
||||
{
|
||||
pcell_header_type *header = pcell_header (pcell_id);
|
||||
tl_assert (header != 0);
|
||||
|
|
@ -1963,16 +2038,13 @@ Layout::get_pcell_variant_as (pcell_id_type pcell_id, const std::vector<tl::Vari
|
|||
tl_assert (! (manager () && manager ()->transacting ()));
|
||||
tl_assert (m_cell_ptrs [target_cell_index] != 0);
|
||||
|
||||
invalidate_hier ();
|
||||
|
||||
m_cells.erase (iterator (m_cell_ptrs [target_cell_index]));
|
||||
|
||||
pcell_variant_type *variant = new pcell_variant_type (target_cell_index, *this, pcell_id, parameters);
|
||||
m_cells.push_back_ptr (variant);
|
||||
m_cell_ptrs [target_cell_index] = variant;
|
||||
replace_cell (target_cell_index, variant, retain_layout);
|
||||
|
||||
// produce the layout
|
||||
variant->update (layer_mapping);
|
||||
if (! retain_layout) {
|
||||
// produce the layout unless we retained it
|
||||
variant->update (layer_mapping);
|
||||
}
|
||||
}
|
||||
|
||||
cell_index_type
|
||||
|
|
@ -2316,8 +2388,20 @@ Layout::get_pcell_variant_cell (cell_index_type cell_index, const std::vector<tl
|
|||
|
||||
}
|
||||
|
||||
bool
|
||||
Layout::get_context_info (cell_index_type cell_index, std::vector <std::string> &context_info) const
|
||||
bool
|
||||
Layout::get_context_info (cell_index_type cell_index, std::vector <std::string> &strings) const
|
||||
{
|
||||
ProxyContextInfo info;
|
||||
if (! get_context_info (cell_index, info)) {
|
||||
return false;
|
||||
} else {
|
||||
info.serialize (strings);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
Layout::get_context_info (cell_index_type cell_index, ProxyContextInfo &info) const
|
||||
{
|
||||
const db::Cell *cptr = &cell (cell_index);
|
||||
const db::Layout *ly = this;
|
||||
|
|
@ -2333,7 +2417,7 @@ Layout::get_context_info (cell_index_type cell_index, std::vector <std::string>
|
|||
// one level of library indirection
|
||||
ly = &lib->layout ();
|
||||
cptr = &ly->cell (lib_proxy->library_cell_index ());
|
||||
context_info.push_back ("LIB=" + lib->get_name ());
|
||||
info.lib_name = lib->get_name ();
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -2347,19 +2431,36 @@ Layout::get_context_info (cell_index_type cell_index, std::vector <std::string>
|
|||
const std::vector<db::PCellParameterDeclaration> &pcp = pcell_decl->parameter_declarations ();
|
||||
std::vector<db::PCellParameterDeclaration>::const_iterator pd = pcp.begin ();
|
||||
for (std::vector<tl::Variant>::const_iterator p = pcell_variant->parameters ().begin (); p != pcell_variant->parameters ().end () && pd != pcp.end (); ++p, ++pd) {
|
||||
context_info.push_back ("P(" + tl::to_word_or_quoted_string (pd->get_name ()) + ")=" + p->to_parsable_string ());
|
||||
info.pcell_parameters.insert (std::make_pair (pd->get_name (), *p));
|
||||
}
|
||||
|
||||
const db::PCellHeader *header = ly->pcell_header (pcell_variant->pcell_id ());
|
||||
context_info.push_back ("PCELL=" + header->get_name ());
|
||||
info.pcell_name = header->get_name ();
|
||||
|
||||
} else {
|
||||
context_info.push_back ("CELL=" + std::string (ly->cell_name (cptr->cell_index ())));
|
||||
info.cell_name = ly->cell_name (cptr->cell_index ());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
Layout::restore_proxies (ImportLayerMapping *layer_mapping)
|
||||
{
|
||||
std::vector<db::ColdProxy *> cold_proxies;
|
||||
|
||||
for (iterator c = begin (); c != end (); ++c) {
|
||||
db::ColdProxy *proxy = dynamic_cast<db::ColdProxy *> (c.operator-> ());
|
||||
if (proxy) {
|
||||
cold_proxies.push_back (proxy);
|
||||
}
|
||||
}
|
||||
|
||||
for (std::vector<db::ColdProxy *>::const_iterator p = cold_proxies.begin (); p != cold_proxies.end (); ++p) {
|
||||
recover_proxy_as ((*p)->cell_index (), (*p)->context_info (), layer_mapping);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
Layout::recover_proxy_as (cell_index_type cell_index, std::vector <std::string>::const_iterator from, std::vector <std::string>::const_iterator to, ImportLayerMapping *layer_mapping)
|
||||
{
|
||||
|
|
@ -2367,17 +2468,21 @@ Layout::recover_proxy_as (cell_index_type cell_index, std::vector <std::string>:
|
|||
return false;
|
||||
}
|
||||
|
||||
tl::Extractor ex (from->c_str ());
|
||||
return recover_proxy_as (cell_index, ProxyContextInfo::deserialize (from, to), layer_mapping);
|
||||
}
|
||||
|
||||
if (ex.test ("LIB=")) {
|
||||
bool
|
||||
Layout::recover_proxy_as (cell_index_type cell_index, const ProxyContextInfo &info, ImportLayerMapping *layer_mapping)
|
||||
{
|
||||
if (! info.lib_name.empty ()) {
|
||||
|
||||
std::string lib_name = ex.skip ();
|
||||
Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (lib_name, m_tech_name);
|
||||
if (! lib) {
|
||||
return false;
|
||||
db::Cell *lib_cell = 0;
|
||||
|
||||
Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (info.lib_name, m_tech_name);
|
||||
if (lib) {
|
||||
lib_cell = lib->layout ().recover_proxy_no_lib (info);
|
||||
}
|
||||
|
||||
db::Cell *lib_cell = lib->layout ().recover_proxy (from + 1, to);
|
||||
if (lib_cell) {
|
||||
get_lib_proxy_as (lib, lib_cell->cell_index (), cell_index, layer_mapping);
|
||||
return true;
|
||||
|
|
@ -2385,38 +2490,28 @@ Layout::recover_proxy_as (cell_index_type cell_index, std::vector <std::string>:
|
|||
|
||||
} else {
|
||||
|
||||
std::map<std::string, tl::Variant> parameters;
|
||||
if (! info.pcell_name.empty ()) {
|
||||
|
||||
while (from != to && (ex = tl::Extractor (from->c_str ())).test ("P(")) {
|
||||
|
||||
std::string name;
|
||||
ex.read_word_or_quoted (name);
|
||||
ex.test (")");
|
||||
ex.test ("=");
|
||||
|
||||
ex.read (parameters.insert (std::make_pair (name, tl::Variant ())).first->second);
|
||||
|
||||
++from;
|
||||
|
||||
}
|
||||
|
||||
if (ex.test ("PCELL=")) {
|
||||
|
||||
std::pair<bool, pcell_id_type> pc = pcell_by_name (ex.skip ());
|
||||
std::pair<bool, pcell_id_type> pc = pcell_by_name (info.pcell_name.c_str ());
|
||||
if (pc.first) {
|
||||
get_pcell_variant_as (pc.second, pcell_declaration (pc.second)->map_parameters (parameters), cell_index, layer_mapping);
|
||||
get_pcell_variant_as (pc.second, pcell_declaration (pc.second)->map_parameters (info.pcell_parameters), cell_index, layer_mapping);
|
||||
return true;
|
||||
}
|
||||
|
||||
} else if (ex.test ("CELL=")) {
|
||||
} else if (! info.cell_name.empty ()) {
|
||||
|
||||
// This should not happen. A cell (given by the cell index) cannot be proxy to another cell in the same layout.
|
||||
// This should not happen. A cell (given by the cell name) cannot be proxy to another cell in the same layout.
|
||||
tl_assert (false);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (! dynamic_cast<db::ColdProxy *> (m_cell_ptrs [cell_index])) {
|
||||
// create a cold proxy representing the context information so we can restore it
|
||||
create_cold_proxy_as (info, cell_index);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -2427,55 +2522,54 @@ Layout::recover_proxy (std::vector <std::string>::const_iterator from, std::vect
|
|||
return 0;
|
||||
}
|
||||
|
||||
tl::Extractor ex (from->c_str ());
|
||||
return recover_proxy (ProxyContextInfo::deserialize (from, to));
|
||||
}
|
||||
|
||||
if (ex.test ("LIB=")) {
|
||||
db::Cell *
|
||||
Layout::recover_proxy (const ProxyContextInfo &info)
|
||||
{
|
||||
if (! info.lib_name.empty ()) {
|
||||
|
||||
std::string lib_name = ex.skip ();
|
||||
Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (lib_name, m_tech_name);
|
||||
if (! lib) {
|
||||
return 0;
|
||||
Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (info.lib_name, m_tech_name);
|
||||
|
||||
db::Cell *lib_cell = 0;
|
||||
if (lib) {
|
||||
lib_cell = lib->layout ().recover_proxy_no_lib (info);
|
||||
}
|
||||
|
||||
db::Cell *lib_cell = lib->layout ().recover_proxy (from + 1, to);
|
||||
if (lib_cell) {
|
||||
cell_index_type cell_index = get_lib_proxy (lib, lib_cell->cell_index ());
|
||||
return &cell (cell_index);
|
||||
return m_cell_ptrs [get_lib_proxy (lib, lib_cell->cell_index ())];
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
std::map<std::string, tl::Variant> parameters;
|
||||
|
||||
while (from != to && (ex = tl::Extractor (from->c_str ())).test ("P(")) {
|
||||
|
||||
std::string name;
|
||||
ex.read_word_or_quoted (name);
|
||||
ex.test (")");
|
||||
ex.test ("=");
|
||||
|
||||
ex.read (parameters.insert (std::make_pair (name, tl::Variant ())).first->second);
|
||||
|
||||
++from;
|
||||
|
||||
db::Cell *proxy = recover_proxy_no_lib (info);
|
||||
if (proxy) {
|
||||
return proxy;
|
||||
}
|
||||
|
||||
if (ex.test ("PCELL=")) {
|
||||
}
|
||||
|
||||
std::pair<bool, pcell_id_type> pc = pcell_by_name (ex.skip ());
|
||||
if (pc.first) {
|
||||
cell_index_type cell_index = get_pcell_variant (pc.second, pcell_declaration (pc.second)->map_parameters (parameters));
|
||||
return &cell (cell_index);
|
||||
}
|
||||
return m_cell_ptrs [create_cold_proxy (info)];
|
||||
}
|
||||
|
||||
} else if (ex.test ("CELL=")) {
|
||||
db::Cell *
|
||||
Layout::recover_proxy_no_lib (const ProxyContextInfo &info)
|
||||
{
|
||||
if (! info.pcell_name.empty ()) {
|
||||
|
||||
std::pair<bool, cell_index_type> cc = cell_by_name (ex.skip ());
|
||||
if (cc.first) {
|
||||
return &cell (cc.second);
|
||||
}
|
||||
std::pair<bool, pcell_id_type> pc = pcell_by_name (info.pcell_name.c_str ());
|
||||
if (pc.first) {
|
||||
cell_index_type cell_index = get_pcell_variant (pc.second, pcell_declaration (pc.second)->map_parameters (info.pcell_parameters));
|
||||
return m_cell_ptrs [cell_index];
|
||||
}
|
||||
|
||||
}
|
||||
} else if (! info.cell_name.empty ()) {
|
||||
|
||||
std::pair<bool, cell_index_type> cc = cell_by_name (info.cell_name.c_str ());
|
||||
if (cc.first) {
|
||||
return m_cell_ptrs [cc.second];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -2507,21 +2601,18 @@ Layout::unregister_lib_proxy (db::LibraryProxy *lib_proxy)
|
|||
}
|
||||
|
||||
void
|
||||
Layout::get_lib_proxy_as (Library *lib, cell_index_type cell_index, cell_index_type target_cell_index, ImportLayerMapping *layer_mapping)
|
||||
Layout::get_lib_proxy_as (Library *lib, cell_index_type cell_index, cell_index_type target_cell_index, ImportLayerMapping *layer_mapping, bool retain_layout)
|
||||
{
|
||||
tl_assert (! (manager () && manager ()->transacting ()));
|
||||
tl_assert (m_cell_ptrs [target_cell_index] != 0);
|
||||
|
||||
invalidate_hier ();
|
||||
|
||||
m_cells.erase (iterator (m_cell_ptrs [target_cell_index]));
|
||||
|
||||
LibraryProxy *proxy = new LibraryProxy (target_cell_index, *this, lib->get_id (), cell_index);
|
||||
m_cells.push_back_ptr (proxy);
|
||||
m_cell_ptrs [target_cell_index] = proxy;
|
||||
replace_cell (target_cell_index, proxy, retain_layout);
|
||||
|
||||
// produce the layout
|
||||
proxy->update (layer_mapping);
|
||||
if (! retain_layout) {
|
||||
// produce the layout unless we retained it
|
||||
proxy->update (layer_mapping);
|
||||
}
|
||||
}
|
||||
|
||||
cell_index_type
|
||||
|
|
@ -2552,7 +2643,7 @@ Layout::get_lib_proxy (Library *lib, cell_index_type cell_index)
|
|||
manager ()->queue (this, new NewRemoveCellOp (new_index, m_cell_names [new_index], false /*new*/, 0));
|
||||
}
|
||||
|
||||
// produce the layout
|
||||
// produce the layout
|
||||
proxy->update ();
|
||||
|
||||
return new_index;
|
||||
|
|
@ -2560,6 +2651,47 @@ Layout::get_lib_proxy (Library *lib, cell_index_type cell_index)
|
|||
}
|
||||
}
|
||||
|
||||
cell_index_type
|
||||
Layout::create_cold_proxy (const db::ProxyContextInfo &info)
|
||||
{
|
||||
// create a new unique name
|
||||
std::string b;
|
||||
if (! info.cell_name.empty ()) {
|
||||
b = info.cell_name;
|
||||
} else if (! info.pcell_name.empty ()) {
|
||||
b = info.pcell_name;
|
||||
}
|
||||
if (m_cell_map.find (b.c_str ()) != m_cell_map.end ()) {
|
||||
b = uniquify_cell_name (b.c_str ());
|
||||
}
|
||||
|
||||
// create a new cell (a LibraryProxy)
|
||||
cell_index_type new_index = allocate_new_cell ();
|
||||
|
||||
ColdProxy *proxy = new ColdProxy (new_index, *this, info);
|
||||
m_cells.push_back_ptr (proxy);
|
||||
m_cell_ptrs [new_index] = proxy;
|
||||
|
||||
// enter it's index and cell_name
|
||||
register_cell_name (b.c_str (), new_index);
|
||||
|
||||
if (manager () && manager ()->transacting ()) {
|
||||
manager ()->queue (this, new NewRemoveCellOp (new_index, m_cell_names [new_index], false /*new*/, 0));
|
||||
}
|
||||
|
||||
return new_index;
|
||||
}
|
||||
|
||||
void
|
||||
Layout::create_cold_proxy_as (const db::ProxyContextInfo &info, cell_index_type target_cell_index)
|
||||
{
|
||||
tl_assert (! (manager () && manager ()->transacting ()));
|
||||
tl_assert (m_cell_ptrs [target_cell_index] != 0);
|
||||
|
||||
ColdProxy *proxy = new ColdProxy (target_cell_index, *this, info);
|
||||
replace_cell (target_cell_index, proxy, true);
|
||||
}
|
||||
|
||||
void
|
||||
Layout::redo (db::Op *op)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -457,6 +457,20 @@ public:
|
|||
virtual std::pair <bool, unsigned int> map_layer (const LayerProperties &lprops) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A binary object representing context information for regenerating library proxies and PCells
|
||||
*/
|
||||
struct DB_PUBLIC ProxyContextInfo
|
||||
{
|
||||
std::string lib_name;
|
||||
std::string cell_name;
|
||||
std::string pcell_name;
|
||||
std::map<std::string, tl::Variant> pcell_parameters;
|
||||
|
||||
static ProxyContextInfo deserialize (std::vector<std::string>::const_iterator from, std::vector<std::string>::const_iterator to);
|
||||
void serialize (std::vector<std::string> &strings);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The layout object
|
||||
*
|
||||
|
|
@ -863,8 +877,9 @@ public:
|
|||
* @param parameters The PCell parameters
|
||||
* @param cell_index The cell index which is to be replaced by the PCell variant proxy
|
||||
* @param layer_mapping The optional layer mapping object that maps the PCell layers to the layout's layers
|
||||
* @param retain_layout Set to true for not using update() on the PCell but to retain existing layout (conservative approach)
|
||||
*/
|
||||
void get_pcell_variant_as (pcell_id_type pcell_id, const std::vector<tl::Variant> ¶meters, cell_index_type cell_index, ImportLayerMapping *layer_mapping = 0);
|
||||
void get_pcell_variant_as (pcell_id_type pcell_id, const std::vector<tl::Variant> ¶meters, cell_index_type cell_index, ImportLayerMapping *layer_mapping = 0, bool retain_layout = false);
|
||||
|
||||
/**
|
||||
* @brief Get the PCell variant cell of a existing cell with new parameters
|
||||
|
|
@ -1010,9 +1025,21 @@ public:
|
|||
/**
|
||||
* @brief Get the proxy cell (index) for a given library an cell index (inside that library)
|
||||
*
|
||||
* This method replaces the cell with the given target cell index by a library.
|
||||
* @param retain_layout Set to true for not using update() on the PCell but to retain existing layout (conservative approach)
|
||||
*
|
||||
* This method replaces the cell with the given target cell index by a library.
|
||||
*/
|
||||
void get_lib_proxy_as (Library *lib, cell_index_type cell_index, cell_index_type target_cell_index, ImportLayerMapping *layer_mapping = 0);
|
||||
void get_lib_proxy_as (Library *lib, cell_index_type cell_index, cell_index_type target_cell_index, ImportLayerMapping *layer_mapping = 0, bool retain_layout = false);
|
||||
|
||||
/**
|
||||
* @brief Creates a cold proxy representing the given context information
|
||||
*/
|
||||
cell_index_type create_cold_proxy (const db::ProxyContextInfo &info);
|
||||
|
||||
/**
|
||||
* @brief Subsitutes the given cell by a cold proxy representing the given context information
|
||||
*/
|
||||
void create_cold_proxy_as (const db::ProxyContextInfo &info, cell_index_type cell_index);
|
||||
|
||||
/**
|
||||
* @brief Get the context information for a given cell (for writing into a file)
|
||||
|
|
@ -1024,6 +1051,11 @@ public:
|
|||
*/
|
||||
bool get_context_info (cell_index_type cell_index, std::vector <std::string> &context_info) const;
|
||||
|
||||
/**
|
||||
* @brief Gets the context information as a binary object
|
||||
*/
|
||||
bool get_context_info (cell_index_type cell_index, ProxyContextInfo &context_info) const;
|
||||
|
||||
/**
|
||||
* @brief Recover a proxy cell from the given context info.
|
||||
*
|
||||
|
|
@ -1035,6 +1067,11 @@ public:
|
|||
*/
|
||||
db::Cell *recover_proxy (std::vector <std::string>::const_iterator from, std::vector <std::string>::const_iterator to);
|
||||
|
||||
/**
|
||||
* @brief Recover a proxy cell from the given binary context info object.
|
||||
*/
|
||||
db::Cell *recover_proxy (const ProxyContextInfo &context_info);
|
||||
|
||||
/**
|
||||
* @brief Recover a proxy cell from the given context info.
|
||||
*
|
||||
|
|
@ -1050,6 +1087,27 @@ public:
|
|||
*/
|
||||
bool recover_proxy_as (cell_index_type cell_index, std::vector <std::string>::const_iterator from, std::vector <std::string>::const_iterator to, ImportLayerMapping *layer_mapping = 0);
|
||||
|
||||
/**
|
||||
* @brief Recover a proxy cell from the given binary context info object
|
||||
*
|
||||
* See the string-based version of "recover_proxy_as" for details.
|
||||
*/
|
||||
bool recover_proxy_as (cell_index_type cell_index, const ProxyContextInfo &context_info, ImportLayerMapping *layer_mapping = 0);
|
||||
|
||||
/**
|
||||
* @brief Restores proxies as far as possible
|
||||
*
|
||||
* This feature can be used after a library update to make sure that proxies are updated.
|
||||
* Library updates may enabled lost connections which are help in cold proxies. This method will recover
|
||||
* these connections.
|
||||
*/
|
||||
void restore_proxies(ImportLayerMapping *layer_mapping = 0);
|
||||
|
||||
/**
|
||||
* @brief Replaces the given cell index with the new cell
|
||||
*/
|
||||
void replace_cell (cell_index_type target_cell_index, db::Cell *new_cell, bool retain_layout);
|
||||
|
||||
/**
|
||||
* @brief Delete a cell plus the subcells not used otherwise
|
||||
*
|
||||
|
|
@ -1853,6 +1911,11 @@ private:
|
|||
* @brief Implementation of prune_cells and some prune_subcells variants
|
||||
*/
|
||||
void do_prune_cells_or_subcells (const std::set<cell_index_type> &ids, int levels, bool subcells);
|
||||
|
||||
/**
|
||||
* @brief Recovers a proxy without considering the library from context_info
|
||||
*/
|
||||
db::Cell *recover_proxy_no_lib (const ProxyContextInfo &context_info);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -191,12 +191,10 @@ Library::remap_to (db::Library *other)
|
|||
|
||||
if (! pn.first) {
|
||||
|
||||
// substitute by static layout cell
|
||||
// @@@ TODO: keep reference so we don't loose the connection immediately.
|
||||
std::string name = r->first->cell_name (ci);
|
||||
db::Cell *old_cell = r->first->take_cell (ci);
|
||||
r->first->insert_cell (ci, name, new db::Cell (*old_cell));
|
||||
delete old_cell;
|
||||
// substitute by a cold proxy
|
||||
db::ProxyContextInfo info;
|
||||
r->first->get_context_info (ci, info);
|
||||
r->first->create_cold_proxy_as (info, ci);
|
||||
|
||||
} else {
|
||||
|
||||
|
|
@ -204,12 +202,10 @@ Library::remap_to (db::Library *other)
|
|||
const db::PCellDeclaration *new_pcell_decl = other->layout ().pcell_declaration (pn.second);
|
||||
if (! old_pcell_decl || ! new_pcell_decl) {
|
||||
|
||||
// substitute by static layout cell
|
||||
// @@@ TODO: keep reference so we don't loose the connection immediately.
|
||||
std::string name = r->first->cell_name (ci);
|
||||
db::Cell *old_cell = r->first->take_cell (ci);
|
||||
r->first->insert_cell (ci, name, new db::Cell (*old_cell));
|
||||
delete old_cell;
|
||||
// substitute by a cold proxy
|
||||
db::ProxyContextInfo info;
|
||||
r->first->get_context_info (ci, info);
|
||||
r->first->create_cold_proxy_as (info, ci);
|
||||
|
||||
} else {
|
||||
|
||||
|
|
@ -234,12 +230,10 @@ Library::remap_to (db::Library *other)
|
|||
|
||||
if (! cn.first) {
|
||||
|
||||
// unlink this proxy: substitute by static layout cell
|
||||
// @@@ TODO: keep reference so we don't loose the connection immediately.
|
||||
std::string name = r->first->cell_name (ci);
|
||||
db::Cell *old_cell = r->first->take_cell (ci);
|
||||
r->first->insert_cell (ci, name, new db::Cell (*old_cell));
|
||||
delete old_cell;
|
||||
// substitute by a cold proxy
|
||||
db::ProxyContextInfo info;
|
||||
r->first->get_context_info (ci, info);
|
||||
r->first->create_cold_proxy_as (info, ci);
|
||||
|
||||
} else {
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
#include "dbLibraryManager.h"
|
||||
#include "dbLibrary.h"
|
||||
#include "dbCommon.h"
|
||||
#include "dbColdProxy.h"
|
||||
|
||||
#include "tlAssert.h"
|
||||
#include "tlStaticObjects.h"
|
||||
|
|
@ -158,6 +159,21 @@ LibraryManager::register_lib (Library *library)
|
|||
l = m_lib_by_name.find (library->get_name ());
|
||||
m_lib_by_name.insert (l, std::make_pair (library->get_name (), id));
|
||||
|
||||
// take care of cold referrers - these may not get valid
|
||||
// NOTE: this will try to substitute the cold proxies we may have generated during "remap_to" above, but
|
||||
// "restore_proxies" takes care not to re-substitute cold proxies.
|
||||
|
||||
const tl::weak_collection<db::ColdProxy> &cold_proxies = db::ColdProxy::cold_proxies_per_lib_name (library->get_name ());
|
||||
std::set<db::Layout *> to_refresh;
|
||||
for (tl::weak_collection<db::ColdProxy>::const_iterator p = cold_proxies.begin (); p != cold_proxies.end (); ++p) {
|
||||
to_refresh.insert (const_cast<db::Layout *> (p->layout ()));
|
||||
}
|
||||
|
||||
for (std::set<db::Layout *>::const_iterator l = to_refresh.begin (); l != to_refresh.end (); ++l) {
|
||||
(*l)->restore_proxies (0);
|
||||
}
|
||||
|
||||
// issue the change notification
|
||||
changed_event ();
|
||||
|
||||
return id;
|
||||
|
|
|
|||
|
|
@ -99,8 +99,6 @@ LibraryProxy::remap (lib_id_type lib_id, cell_index_type lib_cell_index)
|
|||
m_lib_id = lib_id;
|
||||
m_library_cell_index = lib_cell_index;
|
||||
|
||||
// It's important to register at the new library, but the old library is about to the deleted, so we don't unregister.
|
||||
// That does not disturb the old library iterating over the layouts.
|
||||
db::Library *lib = db::LibraryManager::instance ().lib (m_lib_id);
|
||||
if (lib) {
|
||||
lib->register_proxy (this, layout ());
|
||||
|
|
|
|||
|
|
@ -358,17 +358,21 @@ GDS2ReaderBase::do_read (db::Layout &layout)
|
|||
|
||||
db::cell_index_type cell_index = make_cell (layout, m_cellname);
|
||||
|
||||
db::Cell *cell = &layout.cell (cell_index);
|
||||
|
||||
bool ignore_cell = false;
|
||||
std::map <tl::string, std::vector <std::string> >::const_iterator ctx = m_context_info.find (m_cellname);
|
||||
if (ctx != m_context_info.end ()) {
|
||||
GDS2ReaderLayerMapping layer_mapping (this, &layout, m_create_layers);
|
||||
if (layout.recover_proxy_as (cell_index, ctx->second.begin (), ctx->second.end (), &layer_mapping)) {
|
||||
// ignore everything in that cell since it is created by the import:
|
||||
cell = 0;
|
||||
ignore_cell = true;
|
||||
}
|
||||
}
|
||||
|
||||
db::Cell *cell = 0;
|
||||
if (! ignore_cell) {
|
||||
cell = &layout.cell (cell_index);
|
||||
}
|
||||
|
||||
long attr = 0;
|
||||
db::PropertiesRepository::properties_set cell_properties;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue