mirror of https://github.com/KLayout/klayout.git
Merge branch 'issue-691'
This commit is contained in:
commit
866ac7ec76
|
|
@ -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 "<defunct>" + mp_context_info->pcell_name;
|
||||
} else if (! mp_context_info->cell_name.empty ()) {
|
||||
return "<defunct>" + 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
|
||||
|
||||
|
||||
|
|
@ -24,11 +24,13 @@
|
|||
#include "dbLayout.h"
|
||||
#include "dbMemStatistics.h"
|
||||
#include "dbTrans.h"
|
||||
#include "dbTechnology.h"
|
||||
#include "dbShapeRepository.h"
|
||||
#include "dbPCellHeader.h"
|
||||
#include "dbPCellVariant.h"
|
||||
#include "dbPCellDeclaration.h"
|
||||
#include "dbLibraryProxy.h"
|
||||
#include "dbColdProxy.h"
|
||||
#include "dbLibraryManager.h"
|
||||
#include "dbLibrary.h"
|
||||
#include "dbRegion.h"
|
||||
|
|
@ -84,6 +86,27 @@ private:
|
|||
db::properties_id_type m_from, m_to;
|
||||
};
|
||||
|
||||
struct SetLayoutTechName
|
||||
: public LayoutOp
|
||||
{
|
||||
SetLayoutTechName (const std::string &from, const std::string &to)
|
||||
: m_from (from), m_to (to)
|
||||
{ }
|
||||
|
||||
virtual void redo (db::Layout *layout) const
|
||||
{
|
||||
layout->set_technology_name_without_update (m_to);
|
||||
}
|
||||
|
||||
virtual void undo (db::Layout *layout) const
|
||||
{
|
||||
layout->set_technology_name_without_update (m_from);
|
||||
}
|
||||
|
||||
private:
|
||||
std::string m_from, m_to;
|
||||
};
|
||||
|
||||
struct SetLayoutDBU
|
||||
: public LayoutOp
|
||||
{
|
||||
|
|
@ -259,6 +282,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
|
||||
|
||||
|
|
@ -442,6 +524,187 @@ Layout::operator= (const Layout &d)
|
|||
return *this;
|
||||
}
|
||||
|
||||
const db::Technology *
|
||||
Layout::technology () const
|
||||
{
|
||||
return db::Technologies::instance ()->technology_by_name (m_tech_name);
|
||||
}
|
||||
|
||||
void
|
||||
Layout::set_technology_name_without_update (const std::string &tech)
|
||||
{
|
||||
if (tech != m_tech_name) {
|
||||
if (manager () && manager ()->transacting ()) {
|
||||
manager ()->queue (this, new SetLayoutTechName (m_tech_name, tech));
|
||||
}
|
||||
m_tech_name = tech;
|
||||
technology_changed_event ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Layout::set_technology_name (const std::string &tech)
|
||||
{
|
||||
if (tech == m_tech_name) {
|
||||
return;
|
||||
}
|
||||
|
||||
// determine which library to map to what
|
||||
std::map<db::lib_id_type, db::lib_id_type> mapping;
|
||||
std::set<db::lib_id_type> seen;
|
||||
std::set<db::lib_id_type> lost;
|
||||
|
||||
for (db::Layout::iterator c = begin (); c != end (); ++c) {
|
||||
|
||||
db::LibraryProxy *lib_proxy = dynamic_cast<db::LibraryProxy *> (&*c);
|
||||
if (lib_proxy && seen.find (lib_proxy->lib_id ()) == seen.end ()) {
|
||||
|
||||
seen.insert (lib_proxy->lib_id ());
|
||||
|
||||
std::pair<bool, db::lib_id_type> new_id (false, 0);
|
||||
const db::Library *l = db::LibraryManager::instance ().lib (lib_proxy->lib_id ());
|
||||
if (l) {
|
||||
new_id = db::LibraryManager::instance ().lib_by_name (l->get_name (), tech);
|
||||
}
|
||||
|
||||
if (new_id.first && new_id.second != l->get_id ()) {
|
||||
mapping.insert (std::make_pair (l->get_id (), new_id.second));
|
||||
} else if (! new_id.first) {
|
||||
lost.insert (lib_proxy->lib_id ());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (! mapping.empty () || ! lost.empty ()) {
|
||||
|
||||
bool needs_cleanup = false;
|
||||
|
||||
std::vector<std::pair<db::LibraryProxy *, db::PCellVariant *> > pcells_to_map;
|
||||
std::vector<db::LibraryProxy *> lib_cells_to_map;
|
||||
std::vector<db::LibraryProxy *> lib_cells_lost;
|
||||
|
||||
for (db::Layout::iterator c = begin (); c != end (); ++c) {
|
||||
|
||||
std::map<db::lib_id_type, db::lib_id_type>::const_iterator m;
|
||||
|
||||
db::LibraryProxy *lib_proxy = dynamic_cast<db::LibraryProxy *> (&*c);
|
||||
if (! lib_proxy) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((m = mapping.find (lib_proxy->lib_id ())) != mapping.end ()) {
|
||||
|
||||
db::Library *lib = db::LibraryManager::instance ().lib (lib_proxy->lib_id ());
|
||||
db::Cell *lib_cell = &lib->layout ().cell (lib_proxy->library_cell_index ());
|
||||
db::PCellVariant *lib_pcell = dynamic_cast <db::PCellVariant *> (lib_cell);
|
||||
if (lib_pcell) {
|
||||
pcells_to_map.push_back (std::make_pair (lib_proxy, lib_pcell));
|
||||
} else {
|
||||
lib_cells_to_map.push_back (lib_proxy);
|
||||
}
|
||||
|
||||
needs_cleanup = true;
|
||||
|
||||
} else if (lost.find (lib_proxy->lib_id ()) != lost.end ()) {
|
||||
|
||||
lib_cells_lost.push_back (lib_proxy);
|
||||
|
||||
needs_cleanup = true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// We do PCell resolution before the library proxy resolution. The reason is that
|
||||
// PCells may generate library proxies in their instantiation. Hence we must instantiate
|
||||
// the PCells before we can resolve them.
|
||||
for (std::vector<std::pair<db::LibraryProxy *, db::PCellVariant *> >::const_iterator lp = pcells_to_map.begin (); lp != pcells_to_map.end (); ++lp) {
|
||||
|
||||
db::cell_index_type ci = lp->first->Cell::cell_index ();
|
||||
db::PCellVariant *lib_pcell = lp->second;
|
||||
|
||||
std::pair<bool, pcell_id_type> pn = lib_pcell->layout ()->pcell_by_name (lp->first->get_basic_name ().c_str ());
|
||||
|
||||
if (! pn.first) {
|
||||
|
||||
// substitute by a cold proxy
|
||||
db::ProxyContextInfo info;
|
||||
get_context_info (ci, info);
|
||||
create_cold_proxy_as (info, ci);
|
||||
|
||||
} else {
|
||||
|
||||
db::Library *new_lib = db::LibraryManager::instance ().lib (mapping [lp->first->lib_id ()]);
|
||||
|
||||
const db::PCellDeclaration *old_pcell_decl = lib_pcell->layout ()->pcell_declaration (lib_pcell->pcell_id ());
|
||||
const db::PCellDeclaration *new_pcell_decl = new_lib->layout ().pcell_declaration (pn.second);
|
||||
if (! old_pcell_decl || ! new_pcell_decl) {
|
||||
|
||||
// substitute by a cold proxy
|
||||
db::ProxyContextInfo info;
|
||||
get_context_info (ci, info);
|
||||
create_cold_proxy_as (info, ci);
|
||||
|
||||
} else {
|
||||
|
||||
// map pcell parameters by name
|
||||
std::map<std::string, tl::Variant> param_by_name = lib_pcell->parameters_by_name ();
|
||||
lp->first->remap (new_lib->get_id (), new_lib->layout ().get_pcell_variant (pn.second, new_pcell_decl->map_parameters (param_by_name)));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (std::vector<db::LibraryProxy *>::const_iterator lp = lib_cells_to_map.begin (); lp != lib_cells_to_map.end (); ++lp) {
|
||||
|
||||
db::Library *new_lib = db::LibraryManager::instance ().lib (mapping [(*lp)->lib_id ()]);
|
||||
|
||||
db::cell_index_type ci = (*lp)->Cell::cell_index ();
|
||||
|
||||
std::pair<bool, cell_index_type> cn = new_lib->layout ().cell_by_name ((*lp)->get_basic_name ().c_str ());
|
||||
|
||||
if (! cn.first) {
|
||||
|
||||
// unlink this proxy: substitute by a cold proxy
|
||||
db::ProxyContextInfo info;
|
||||
get_context_info (ci, info);
|
||||
create_cold_proxy_as (info, ci);
|
||||
|
||||
} else {
|
||||
|
||||
(*lp)->remap (new_lib->get_id (), cn.second);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (std::vector<db::LibraryProxy *>::const_iterator lp = lib_cells_lost.begin (); lp != lib_cells_lost.end (); ++lp) {
|
||||
|
||||
db::cell_index_type ci = (*lp)->Cell::cell_index ();
|
||||
|
||||
// substitute by a cold proxy
|
||||
db::ProxyContextInfo info;
|
||||
get_context_info (ci, info);
|
||||
create_cold_proxy_as (info, ci);
|
||||
|
||||
}
|
||||
|
||||
if (needs_cleanup) {
|
||||
cleanup ();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
set_technology_name_without_update (tech);
|
||||
|
||||
// we may have re-established a connection for pending ("cold") proxies so we can try to restore them
|
||||
restore_proxies ();
|
||||
}
|
||||
|
||||
void
|
||||
Layout::mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, bool no_self, void *parent) const
|
||||
{
|
||||
|
|
@ -1800,8 +2063,37 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
if (manager () && manager ()->transacting ()) {
|
||||
// note the "take" method - this takes out the cell but does not delete it (we need it inside undo)
|
||||
m_cells.take (iterator (old_cell));
|
||||
manager ()->queue (this, new NewRemoveCellOp (target_cell_index, cell_name (target_cell_index), true /*remove*/, old_cell));
|
||||
} else {
|
||||
m_cells.erase (iterator (old_cell));
|
||||
}
|
||||
|
||||
m_cells.push_back_ptr (new_cell);
|
||||
m_cell_ptrs [target_cell_index] = new_cell;
|
||||
|
||||
if (manager () && manager ()->transacting ()) {
|
||||
manager ()->queue (this, new NewRemoveCellOp (target_cell_index, m_cell_names [target_cell_index], false /*new*/, 0));
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
|
@ -1812,19 +2104,15 @@ Layout::get_pcell_variant_as (pcell_id_type pcell_id, const std::vector<tl::Vari
|
|||
// this variant must not exist yet for "get as" semantics
|
||||
tl_assert (header->get_variant (*this, parameters) == 0);
|
||||
|
||||
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
|
||||
|
|
@ -2168,10 +2456,29 @@ 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::ColdProxy *cold_proxy = dynamic_cast <const db::ColdProxy *> (cptr);
|
||||
if (cold_proxy) {
|
||||
info = cold_proxy->context_info ();
|
||||
return true;
|
||||
}
|
||||
|
||||
const db::Layout *ly = this;
|
||||
|
||||
const db::LibraryProxy *lib_proxy;
|
||||
|
|
@ -2185,7 +2492,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 ();
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -2199,19 +2506,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)
|
||||
{
|
||||
|
|
@ -2219,17 +2543,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);
|
||||
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;
|
||||
|
|
@ -2237,38 +2565,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;
|
||||
}
|
||||
|
||||
|
|
@ -2279,55 +2597,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);
|
||||
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];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -2359,21 +2676,17 @@ 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
|
||||
|
|
@ -2404,7 +2717,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;
|
||||
|
|
@ -2412,6 +2725,46 @@ 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 (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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ class Region;
|
|||
class Edges;
|
||||
class EdgePairs;
|
||||
class Texts;
|
||||
class Technology;
|
||||
class CellMapping;
|
||||
class LayerMapping;
|
||||
|
||||
|
|
@ -456,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
|
||||
*
|
||||
|
|
@ -555,10 +570,36 @@ public:
|
|||
}
|
||||
|
||||
/**
|
||||
* @brief Clear the layout
|
||||
* @brief Clears the layout
|
||||
*/
|
||||
void clear ();
|
||||
|
||||
/**
|
||||
* @brief Gets the technology name the layout is associated with
|
||||
*/
|
||||
const std::string &technology_name () const
|
||||
{
|
||||
return m_tech_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the technology object the layout is associated with or null if no valid technology is associated
|
||||
*/
|
||||
const db::Technology *technology () const;
|
||||
|
||||
/**
|
||||
* @brief Changes the technology, the layout is associated with
|
||||
* Changing the layout may re-assess all the library references as libraries can be technology specific
|
||||
*/
|
||||
void set_technology_name (const std::string &tech);
|
||||
|
||||
/**
|
||||
* @brief Changes the technology name
|
||||
* This method will only change the technology name, but does not re-assess the library links.
|
||||
* It's provided mainly to support undo/redo and testing.
|
||||
*/
|
||||
void set_technology_name_without_update (const std::string &tech);
|
||||
|
||||
/**
|
||||
* @brief Accessor to the array repository
|
||||
*/
|
||||
|
|
@ -843,8 +884,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
|
||||
|
|
@ -990,9 +1032,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)
|
||||
|
|
@ -1004,6 +1058,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.
|
||||
*
|
||||
|
|
@ -1015,6 +1074,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.
|
||||
*
|
||||
|
|
@ -1030,6 +1094,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
|
||||
*
|
||||
|
|
@ -1738,6 +1823,11 @@ public:
|
|||
*/
|
||||
const std::string &meta_info_value (const std::string &name) const;
|
||||
|
||||
/**
|
||||
* @brief This event is triggered when the technology changes
|
||||
*/
|
||||
tl::Event technology_changed_event;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Establish the graph's internals according to the dirty flags
|
||||
|
|
@ -1779,6 +1869,7 @@ private:
|
|||
bool m_do_cleanup;
|
||||
bool m_editable;
|
||||
meta_info m_meta_info;
|
||||
std::string m_tech_name;
|
||||
tl::Mutex m_lock;
|
||||
|
||||
/**
|
||||
|
|
@ -1832,6 +1923,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);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ tl::Variant LayoutContextHandler::eval_double_bracket (const std::string &s) con
|
|||
|
||||
std::string tail = cp + 1;
|
||||
|
||||
db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (libname);
|
||||
db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (libname, mp_layout->technology_name ());
|
||||
if (! lib) {
|
||||
throw tl::Exception (tl::to_string (tr ("Not a valid library name: ")) + libname);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -191,11 +191,10 @@ Library::remap_to (db::Library *other)
|
|||
|
||||
if (! pn.first) {
|
||||
|
||||
// substitute by static layout cell
|
||||
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 {
|
||||
|
||||
|
|
@ -203,11 +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
|
||||
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 {
|
||||
|
||||
|
|
@ -232,11 +230,10 @@ Library::remap_to (db::Library *other)
|
|||
|
||||
if (! cn.first) {
|
||||
|
||||
// unlink this proxy: substitute by static layout cell
|
||||
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"
|
||||
|
|
@ -66,14 +67,39 @@ LibraryManager::~LibraryManager ()
|
|||
}
|
||||
|
||||
std::pair<bool, lib_id_type>
|
||||
LibraryManager::lib_by_name (const std::string &name) const
|
||||
LibraryManager::lib_by_name (const std::string &name, const std::set<std::string> &for_technologies) const
|
||||
{
|
||||
iterator l = m_lib_by_name.find (name);
|
||||
if (l == m_lib_by_name.end ()) {
|
||||
return std::make_pair (false, lib_id_type (0));
|
||||
} else {
|
||||
return std::make_pair (true, l->second);
|
||||
iterator l;
|
||||
|
||||
if (! for_technologies.empty ()) {
|
||||
|
||||
l = m_lib_by_name.find (name);
|
||||
while (l != m_lib_by_name.end () && l->first == name) {
|
||||
const db::Library *lptr = lib (l->second);
|
||||
bool found = lptr->for_technologies ();
|
||||
for (std::set<std::string>::const_iterator t = for_technologies.begin (); t != for_technologies.end () && found; ++t) {
|
||||
if (! lptr->is_for_technology (*t)) {
|
||||
found = false;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
return std::make_pair (true, l->second);
|
||||
}
|
||||
++l;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// fallback: technology-unspecific libs
|
||||
l = m_lib_by_name.find (name);
|
||||
while (l != m_lib_by_name.end () && l->first == name) {
|
||||
if (! lib (l->second)->for_technologies ()) {
|
||||
return std::make_pair (true, l->second);
|
||||
}
|
||||
++l;
|
||||
}
|
||||
|
||||
return std::make_pair (false, lib_id_type (0));
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -116,15 +142,44 @@ LibraryManager::register_lib (Library *library)
|
|||
library->set_id (id);
|
||||
|
||||
// if the new library replaces the old one, remap existing library proxies before deleting the library
|
||||
lib_name_map::iterator ln = m_lib_by_name.find (library->get_name ());
|
||||
if (ln != m_lib_by_name.end () && m_libs [ln->second]) {
|
||||
m_libs [ln->second]->remap_to (library);
|
||||
delete m_libs [ln->second];
|
||||
m_libs [ln->second] = 0;
|
||||
// (replacement is done only when all technologies are substituted)
|
||||
lib_name_map::iterator l = m_lib_by_name.find (library->get_name ());
|
||||
bool found = false;
|
||||
while (l != m_lib_by_name.end () && l->first == library->get_name ()) {
|
||||
if (m_libs [l->second] && m_libs [l->second]->get_technologies () == library->get_technologies ()) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
++l;
|
||||
}
|
||||
|
||||
m_lib_by_name.insert (std::make_pair (library->get_name (), id)).first->second = id;
|
||||
if (found) {
|
||||
// substitute
|
||||
m_libs [l->second]->remap_to (library);
|
||||
delete m_libs [l->second];
|
||||
m_libs [l->second] = 0;
|
||||
m_lib_by_name.erase (l);
|
||||
}
|
||||
|
||||
// insert new lib as first of this name
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@
|
|||
#include <map>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <set>
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
|
@ -50,7 +51,7 @@ class Library;
|
|||
class DB_PUBLIC LibraryManager
|
||||
{
|
||||
public:
|
||||
typedef std::map <std::string, lib_id_type> lib_name_map;
|
||||
typedef std::multimap <std::string, lib_id_type> lib_name_map;
|
||||
typedef lib_name_map::const_iterator iterator;
|
||||
|
||||
/**
|
||||
|
|
@ -90,11 +91,41 @@ public:
|
|||
}
|
||||
|
||||
/**
|
||||
* @brief Get the library by name
|
||||
* @brief Get the library by name which is valid for all given technologies
|
||||
*
|
||||
* This method looks up a library which is valid for all technologies listed in "for_technologies". It may be
|
||||
* responsible for more than that too.
|
||||
*
|
||||
* @return A pair, the boolean is true, if the name is valid. The second member is the library id.
|
||||
*/
|
||||
std::pair<bool, lib_id_type> lib_by_name (const std::string &name) const;
|
||||
std::pair<bool, lib_id_type> lib_by_name (const std::string &name, const std::set<std::string> &for_technologies) const;
|
||||
|
||||
/**
|
||||
* @brief Get the library by name which is valid for the given technology
|
||||
*
|
||||
* This method looks up a library which is valid for the given technology. It may be
|
||||
* responsible for more than that too.
|
||||
*
|
||||
* @return A pair, the boolean is true, if the name is valid. The second member is the library id.
|
||||
*/
|
||||
std::pair<bool, lib_id_type> lib_by_name (const std::string &name, const std::string &for_technology) const
|
||||
{
|
||||
std::set<std::string> techs;
|
||||
if (! for_technology.empty ()) {
|
||||
techs.insert (for_technology);
|
||||
}
|
||||
return lib_by_name (name, techs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the library by name for any technology
|
||||
*
|
||||
* @return A pair, the boolean is true, if the name is valid. The second member is the library id.
|
||||
*/
|
||||
std::pair<bool, lib_id_type> lib_by_name (const std::string &name) const
|
||||
{
|
||||
return lib_by_name (name, std::set<std::string> ());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the library by name
|
||||
|
|
@ -111,6 +142,36 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the library by name and technology
|
||||
*
|
||||
* @return The pointer to the library or 0, if there is no library with that name.
|
||||
*/
|
||||
Library *lib_ptr_by_name (const std::string &name, const std::string &for_technology) const
|
||||
{
|
||||
std::pair<bool, lib_id_type> ll = lib_by_name (name, for_technology);
|
||||
if (ll.first) {
|
||||
return lib (ll.second);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the library by name and technology
|
||||
*
|
||||
* @return The pointer to the library or 0, if there is no library with that name.
|
||||
*/
|
||||
Library *lib_ptr_by_name (const std::string &name, const std::set<std::string> &for_technologies) const
|
||||
{
|
||||
std::pair<bool, lib_id_type> ll = lib_by_name (name, for_technologies);
|
||||
if (ll.first) {
|
||||
return lib (ll.second);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Register a library under the given name and associate a 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 ());
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
#include "gsiObject.h"
|
||||
#include "dbLayout.h"
|
||||
#include "tlVariant.h"
|
||||
#include "tlObject.h"
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
|
@ -327,7 +328,8 @@ public:
|
|||
* @brief A declaration for a PCell
|
||||
*/
|
||||
class DB_PUBLIC PCellDeclaration
|
||||
: public gsi::ObjectBase
|
||||
: public gsi::ObjectBase,
|
||||
public tl::Object
|
||||
{
|
||||
public:
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@
|
|||
#include "dbLayoutUtils.h"
|
||||
#include "dbLayerMapping.h"
|
||||
#include "dbCellMapping.h"
|
||||
#include "dbTechnology.h"
|
||||
#include "tlStream.h"
|
||||
|
||||
namespace gsi
|
||||
|
|
@ -750,7 +751,7 @@ static db::Cell *create_cell2 (db::Layout *layout, const std::string &name, cons
|
|||
|
||||
static db::Cell *create_cell3 (db::Layout *layout, const std::string &name, const std::string &libname)
|
||||
{
|
||||
db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (libname);
|
||||
db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (libname, layout->technology_name ());
|
||||
if (! lib) {
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -765,7 +766,7 @@ static db::Cell *create_cell3 (db::Layout *layout, const std::string &name, cons
|
|||
|
||||
static db::Cell *create_cell4 (db::Layout *layout, const std::string &name, const std::string &libname, const std::map<std::string, tl::Variant> ¶ms)
|
||||
{
|
||||
db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (libname);
|
||||
db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (libname, layout->technology_name ());
|
||||
if (! lib) {
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -988,6 +989,21 @@ Class<db::Layout> decl_Layout ("db", "Layout",
|
|||
"\n"
|
||||
"This method has been introduced in version 0.25."
|
||||
) +
|
||||
gsi::method ("technology_name", &db::Layout::technology_name,
|
||||
"@brief Gets the name of the technology this layout is associated with\n"
|
||||
"This method has been introduced in version 0.27. Before that, the technology has been kept in the 'technology' meta data element."
|
||||
) +
|
||||
gsi::method ("technology", &db::Layout::technology,
|
||||
"@brief Gets the \\Technology object of the technology this layout is associated with or nil if the layout is not associated with a technology\n"
|
||||
"This method has been introduced in version 0.27. Before that, the technology has been kept in the 'technology' meta data element."
|
||||
) +
|
||||
gsi::method ("technology_name=", &db::Layout::set_technology_name, gsi::arg ("name"),
|
||||
"@brief Sets the name of the technology this layout is associated with\n"
|
||||
"Changing the technology name will re-assess all library references because libraries can be technology specified. "
|
||||
"Cell layouts may be substituted during this re-assessment.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27."
|
||||
) +
|
||||
gsi::method ("is_editable?", &db::Layout::is_editable,
|
||||
"@brief Returns a value indicating whether the layout is editable.\n"
|
||||
"@return True, if the layout is editable.\n"
|
||||
|
|
|
|||
|
|
@ -43,9 +43,14 @@ static db::Library *new_lib ()
|
|||
return new db::Library ();
|
||||
}
|
||||
|
||||
static db::Library *library_by_name (const std::string &name)
|
||||
static db::Library *library_by_name (const std::string &name, const std::string &for_technology)
|
||||
{
|
||||
return db::LibraryManager::instance ().lib_ptr_by_name (name);
|
||||
return db::LibraryManager::instance ().lib_ptr_by_name (name, for_technology);
|
||||
}
|
||||
|
||||
static db::Library *library_by_id (db::lib_id_type id)
|
||||
{
|
||||
return db::LibraryManager::instance ().lib (id);
|
||||
}
|
||||
|
||||
static std::vector<std::string> library_names ()
|
||||
|
|
@ -57,6 +62,15 @@ static std::vector<std::string> library_names ()
|
|||
return r;
|
||||
}
|
||||
|
||||
static std::vector<db::lib_id_type> library_ids ()
|
||||
{
|
||||
std::vector<db::lib_id_type> r;
|
||||
for (db::LibraryManager::iterator l = db::LibraryManager::instance ().begin (); l != db::LibraryManager::instance ().end (); ++l) {
|
||||
r.push_back (l->second);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
static void register_lib (db::Library *lib, const std::string &name)
|
||||
{
|
||||
lib->set_name (name);
|
||||
|
|
@ -110,22 +124,45 @@ LibraryClass decl_Library ("db", "Library",
|
|||
gsi::constructor ("new", &new_lib,
|
||||
"@brief Creates a new, empty library"
|
||||
) +
|
||||
gsi::method ("library_by_name", &library_by_name, gsi::arg ("name"),
|
||||
gsi::method ("library_by_name", &library_by_name, gsi::arg ("name"), gsi::arg ("for_technology", std::string (), "unspecific"),
|
||||
"@brief Gets a library by name\n"
|
||||
"Returns the library object for the given name. If the name is not a valid\n"
|
||||
"library name, nil is returned.\n"
|
||||
"\n"
|
||||
"Different libraries can be registered under the same names for different technologies. When a technology name is given in 'for_technologies', "
|
||||
"the first library matching this technology is returned. If no technology is given, the first library is returned.\n"
|
||||
"\n"
|
||||
"The technology selector has been introduced in version 0.27."
|
||||
) +
|
||||
gsi::method ("library_by_id", &library_by_id, gsi::arg ("id"),
|
||||
"@brief Gets the library object for the given ID\n"
|
||||
"If the ID is not valid, nil is returned.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27."
|
||||
) +
|
||||
gsi::method ("library_names", &library_names,
|
||||
"@brief Returns a list of the names of all libraries registered in the system.\n"
|
||||
"\n"
|
||||
"NOTE: starting with version 0.27, the name of a library does not need to be unique if libraries are associated with specific technologies. "
|
||||
"This method will only return the names and it's not possible not unambiguously derive the library object. It is recommended to use "
|
||||
"\\library_ids and \\library_by_id to obtain the library unambiguously."
|
||||
) +
|
||||
gsi::method ("library_ids", &library_ids,
|
||||
"@brief Returns a list of valid library IDs.\n"
|
||||
"See \\library_names for the reasoning behind this method."
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27."
|
||||
) +
|
||||
gsi::method_ext ("register", ®ister_lib, gsi::arg ("name"),
|
||||
"@brief Registers the library with the given name\n"
|
||||
"\n"
|
||||
"This method can be called in the constructor to register the library after \n"
|
||||
"the layout object has been filled with content. If a library with that name\n"
|
||||
"already exists, it will be replaced with this library. \n"
|
||||
"already exists for the same technologies, it will be replaced with this library. \n"
|
||||
"\n"
|
||||
"This method will set the libraries' name.\n"
|
||||
"\n"
|
||||
"The technology specific bahvior has been introduced in version 0.27."
|
||||
) +
|
||||
gsi::method_ext ("delete", &delete_lib,
|
||||
"@brief Deletes the library\n"
|
||||
|
|
|
|||
|
|
@ -20,9 +20,12 @@
|
|||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include "dbLayout.h"
|
||||
#include "dbLibraryManager.h"
|
||||
#include "dbLibrary.h"
|
||||
#include "dbColdProxy.h"
|
||||
#include "dbLibraryProxy.h"
|
||||
#include "dbTextWriter.h"
|
||||
#include "tlString.h"
|
||||
#include "tlUnitTest.h"
|
||||
|
||||
|
|
@ -464,3 +467,170 @@ TEST(4)
|
|||
prop_id = g.properties_repository ().properties_id (ps);
|
||||
EXPECT_EQ (el.property_ids_dirty, true);
|
||||
}
|
||||
|
||||
static std::string l2s (const db::Layout &layout)
|
||||
{
|
||||
tl::OutputStringStream os;
|
||||
tl::OutputStream ostream (os);
|
||||
db::TextWriter writer (ostream);
|
||||
writer.write (layout);
|
||||
return os.string ();
|
||||
}
|
||||
|
||||
TEST(5)
|
||||
{
|
||||
// Technology management and library substitution
|
||||
|
||||
db::cell_index_type ci;
|
||||
unsigned int li;
|
||||
db::Cell *cell;
|
||||
|
||||
db::Library *lib_a = new db::Library ();
|
||||
lib_a->set_name ("LIB");
|
||||
ci = lib_a->layout ().add_cell ("LIBCELL");
|
||||
li = lib_a->layout ().insert_layer (db::LayerProperties (1, 0));
|
||||
lib_a->layout ().cell (ci).shapes (li).insert (db::Box (0, 0, 100, 200));
|
||||
lib_a->add_technology ("A");
|
||||
db::LibraryManager::instance ().register_lib (lib_a);
|
||||
|
||||
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("LIB", "A").first, true);
|
||||
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("LIB", "A").second, lib_a->get_id ());
|
||||
EXPECT_EQ (db::LibraryManager::instance ().lib_ptr_by_name ("LIB", "A") == lib_a, true);
|
||||
|
||||
db::Library *lib_b = new db::Library ();
|
||||
lib_b->set_name ("LIB");
|
||||
ci = lib_b->layout ().add_cell ("LIBCELL");
|
||||
li = lib_b->layout ().insert_layer (db::LayerProperties (2, 0));
|
||||
lib_b->layout ().cell (ci).shapes (li).insert (db::Box (0, 0, 200, 100));
|
||||
lib_b->add_technology ("B");
|
||||
db::LibraryManager::instance ().register_lib (lib_b);
|
||||
|
||||
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("LIB", "B").first, true);
|
||||
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("LIB", "B").second, lib_b->get_id ());
|
||||
EXPECT_EQ (db::LibraryManager::instance ().lib_ptr_by_name ("LIB", "B") == lib_b, true);
|
||||
|
||||
db::Library *lib_c = new db::Library ();
|
||||
lib_c->set_name ("LIB");
|
||||
ci = lib_c->layout ().add_cell ("LIBCELL2");
|
||||
li = lib_c->layout ().insert_layer (db::LayerProperties (2, 0));
|
||||
lib_c->layout ().cell (ci).shapes (li).insert (db::Box (0, 0, 200, 100));
|
||||
lib_c->add_technology ("C");
|
||||
db::LibraryManager::instance ().register_lib (lib_c);
|
||||
|
||||
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("LIB", "C").first, true);
|
||||
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("LIB", "C").second, lib_c->get_id ());
|
||||
EXPECT_EQ (db::LibraryManager::instance ().lib_ptr_by_name ("LIB", "C") == lib_c, true);
|
||||
|
||||
db::Manager m;
|
||||
db::Layout l (&m);
|
||||
EXPECT_EQ (l.technology_name (), "");
|
||||
|
||||
db::ProxyContextInfo info;
|
||||
info.lib_name = "LIB";
|
||||
info.cell_name = "LIBCELL";
|
||||
|
||||
cell = l.recover_proxy (info);
|
||||
EXPECT_EQ (dynamic_cast<db::ColdProxy *> (cell) != 0, true);
|
||||
EXPECT_EQ (cell->get_qualified_name (), "<defunct>LIB.LIBCELL");
|
||||
EXPECT_EQ (cell->get_basic_name (), "<defunct>LIBCELL");
|
||||
EXPECT_EQ (cell->get_display_name (), "<defunct>LIB.LIBCELL");
|
||||
|
||||
EXPECT_EQ (l2s (l), "begin_lib 0.001\nbegin_cell {LIBCELL}\nend_cell\nend_lib\n");
|
||||
|
||||
// now restore the proxies
|
||||
l.set_technology_name ("A");
|
||||
EXPECT_EQ (l.technology_name (), "A");
|
||||
|
||||
EXPECT_EQ (l2s (l), "begin_lib 0.001\nbegin_cell {LIBCELL}\nbox 1 0 {0 0} {100 200}\nend_cell\nend_lib\n");
|
||||
|
||||
// now switch to cold proxies again as the technology does not have "LIBCELL" (but rather LIBCELL2)
|
||||
l.set_technology_name ("C");
|
||||
EXPECT_EQ (l.technology_name (), "C");
|
||||
|
||||
cell = &l.cell (l.cell_by_name ("LIBCELL").second);
|
||||
EXPECT_EQ (dynamic_cast<db::ColdProxy *> (cell) != 0, true);
|
||||
EXPECT_EQ (cell->get_qualified_name (), "<defunct>LIB.LIBCELL");
|
||||
EXPECT_EQ (cell->get_basic_name (), "<defunct>LIBCELL");
|
||||
EXPECT_EQ (cell->get_display_name (), "<defunct>LIB.LIBCELL");
|
||||
|
||||
// NOTE: the box on 1/0 retained
|
||||
EXPECT_EQ (l2s (l), "begin_lib 0.001\nbegin_cell {LIBCELL}\nbox 1 0 {0 0} {100 200}\nend_cell\nend_lib\n");
|
||||
|
||||
// switch to another LIBCELL, this time using layer 2/0
|
||||
m.transaction ("switch_to_b");
|
||||
l.set_technology_name ("B");
|
||||
m.commit ();
|
||||
|
||||
EXPECT_EQ (l.technology_name (), "B");
|
||||
cell = &l.cell (l.cell_by_name ("LIBCELL").second);
|
||||
EXPECT_EQ (dynamic_cast<db::LibraryProxy *> (cell) != 0, true);
|
||||
EXPECT_EQ (l2s (l), "begin_lib 0.001\nbegin_cell {LIBCELL}\nbox 2 0 {0 0} {200 100}\nend_cell\nend_lib\n");
|
||||
|
||||
m.undo ();
|
||||
EXPECT_EQ (l.technology_name (), "C");
|
||||
|
||||
cell = &l.cell (l.cell_by_name ("LIBCELL").second);
|
||||
EXPECT_EQ (dynamic_cast<db::ColdProxy *> (cell) != 0, true);
|
||||
EXPECT_EQ (cell->get_qualified_name (), "<defunct>LIB.LIBCELL");
|
||||
EXPECT_EQ (cell->get_basic_name (), "<defunct>LIBCELL");
|
||||
EXPECT_EQ (cell->get_display_name (), "<defunct>LIB.LIBCELL");
|
||||
EXPECT_EQ (l2s (l), "begin_lib 0.001\nbegin_cell {LIBCELL}\nbox 1 0 {0 0} {100 200}\nend_cell\nend_lib\n");
|
||||
|
||||
m.redo ();
|
||||
|
||||
EXPECT_EQ (l.technology_name (), "B");
|
||||
cell = &l.cell (l.cell_by_name ("LIBCELL").second);
|
||||
EXPECT_EQ (dynamic_cast<db::LibraryProxy *> (cell) != 0, true);
|
||||
EXPECT_EQ (l2s (l), "begin_lib 0.001\nbegin_cell {LIBCELL}\nbox 2 0 {0 0} {200 100}\nend_cell\nend_lib\n");
|
||||
|
||||
db::LibraryManager::instance ().delete_lib (lib_a);
|
||||
db::LibraryManager::instance ().delete_lib (lib_b);
|
||||
db::LibraryManager::instance ().delete_lib (lib_c);
|
||||
}
|
||||
|
||||
TEST(6)
|
||||
{
|
||||
// Cold proxies and context serialization
|
||||
db::Cell *cell;
|
||||
|
||||
db::Manager m;
|
||||
db::Layout l (&m);
|
||||
|
||||
EXPECT_EQ (l.technology_name (), "");
|
||||
|
||||
db::ProxyContextInfo info;
|
||||
info.lib_name = "Basic";
|
||||
info.pcell_name = "CIRCLE";
|
||||
info.pcell_parameters ["actual_radius"] = tl::Variant (10.0);
|
||||
info.pcell_parameters ["npoints"] = tl::Variant (8);
|
||||
info.pcell_parameters ["layer"] = tl::Variant (db::LayerProperties (1, 0));
|
||||
|
||||
m.transaction ("import");
|
||||
cell = l.recover_proxy (info);
|
||||
m.commit ();
|
||||
EXPECT_EQ (cell->get_qualified_name (), "Basic.CIRCLE");
|
||||
EXPECT_EQ (cell->get_basic_name (), "CIRCLE");
|
||||
EXPECT_EQ (cell->get_display_name (), "Basic.CIRCLE(l=1/0,r=10,n=8)");
|
||||
|
||||
EXPECT_EQ (l2s (l), "begin_lib 0.001\nbegin_cell {CIRCLE}\nboundary 1 0 {-4142 -10000} {-10000 -4142} {-10000 4142} {-4142 10000} {4142 10000} {10000 4142} {10000 -4142} {4142 -10000} {-4142 -10000}\nend_cell\nend_lib\n");
|
||||
|
||||
db::ProxyContextInfo info2;
|
||||
l.get_context_info (cell->cell_index (), info2);
|
||||
info2.pcell_parameters ["actual_radius"] = tl::Variant (5.0);
|
||||
|
||||
m.transaction ("modify");
|
||||
db::cell_index_type ci = cell->cell_index ();
|
||||
l.recover_proxy_as (ci, info2);
|
||||
m.commit ();
|
||||
cell = &l.cell (ci);
|
||||
EXPECT_EQ (cell->get_qualified_name (), "Basic.CIRCLE");
|
||||
EXPECT_EQ (cell->get_basic_name (), "CIRCLE");
|
||||
EXPECT_EQ (cell->get_display_name (), "Basic.CIRCLE(l=1/0,r=5,n=8)");
|
||||
|
||||
EXPECT_EQ (l2s (l), "begin_lib 0.001\nbegin_cell {CIRCLE}\nboundary 1 0 {-2071 -5000} {-5000 -2071} {-5000 2071} {-2071 5000} {2071 5000} {5000 2071} {5000 -2071} {2071 -5000} {-2071 -5000}\nend_cell\nend_lib\n");
|
||||
|
||||
m.undo ();
|
||||
EXPECT_EQ (l2s (l), "begin_lib 0.001\nbegin_cell {CIRCLE}\nboundary 1 0 {-4142 -10000} {-10000 -4142} {-10000 4142} {-4142 10000} {4142 10000} {10000 4142} {10000 -4142} {4142 -10000} {-4142 -10000}\nend_cell\nend_lib\n");
|
||||
m.redo ();
|
||||
EXPECT_EQ (l2s (l), "begin_lib 0.001\nbegin_cell {CIRCLE}\nboundary 1 0 {-2071 -5000} {-5000 -2071} {-5000 2071} {-2071 5000} {2071 5000} {5000 2071} {5000 -2071} {2071 -5000} {-2071 -5000}\nend_cell\nend_lib\n");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -617,3 +617,61 @@ TEST(3)
|
|||
}
|
||||
}
|
||||
|
||||
TEST(4)
|
||||
{
|
||||
LIBT_A *lib_a1 = new LIBT_A ();
|
||||
lib_a1->add_technology ("X");
|
||||
db::LibraryManager::instance ().register_lib (lib_a1);
|
||||
|
||||
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").first, true);
|
||||
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").second, lib_a1->get_id ());
|
||||
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Z").first, false);
|
||||
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").first, true);
|
||||
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").second, lib_a1->get_id ());
|
||||
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").first, true);
|
||||
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").second, lib_a1->get_id ());
|
||||
|
||||
LIBT_A *lib_a2 = new LIBT_A ();
|
||||
lib_a2->add_technology ("Y");
|
||||
db::LibraryManager::instance ().register_lib (lib_a2);
|
||||
|
||||
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").first, true);
|
||||
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").second, lib_a2->get_id ());
|
||||
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Z").first, false);
|
||||
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").first, true);
|
||||
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").second, lib_a2->get_id ());
|
||||
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").first, true);
|
||||
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").second, lib_a1->get_id ());
|
||||
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Y").first, true);
|
||||
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Y").second, lib_a2->get_id ());
|
||||
|
||||
LIBT_A *lib_a3 = new LIBT_A ();
|
||||
lib_a3->add_technology ("X");
|
||||
db::LibraryManager::instance ().register_lib (lib_a3);
|
||||
|
||||
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").first, true);
|
||||
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").second, lib_a3->get_id ());
|
||||
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Z").first, false);
|
||||
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").first, true);
|
||||
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").second, lib_a3->get_id ());
|
||||
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").first, true);
|
||||
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").second, lib_a3->get_id ());
|
||||
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Y").first, true);
|
||||
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Y").second, lib_a2->get_id ());
|
||||
|
||||
|
||||
LIBT_A *lib_a4 = new LIBT_A ();
|
||||
db::LibraryManager::instance ().register_lib (lib_a4);
|
||||
|
||||
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").first, true);
|
||||
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").second, lib_a3->get_id ());
|
||||
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Z").first, true);
|
||||
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Z").second, lib_a4->get_id ());
|
||||
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").first, true);
|
||||
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").second, lib_a3->get_id ());
|
||||
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").first, true);
|
||||
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").second, lib_a3->get_id ());
|
||||
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Y").first, true);
|
||||
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Y").second, lib_a2->get_id ());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -69,8 +69,8 @@ static void configure_from_line_edit (lay::Dispatcher *dispatcher, QLineEdit *le
|
|||
// ------------------------------------------------------------------
|
||||
// EditorOptionsGeneric implementation
|
||||
|
||||
EditorOptionsGeneric::EditorOptionsGeneric (lay::Dispatcher *dispatcher)
|
||||
: EditorOptionsPage (dispatcher)
|
||||
EditorOptionsGeneric::EditorOptionsGeneric (lay::LayoutView *view, lay::Dispatcher *dispatcher)
|
||||
: EditorOptionsPage (view, dispatcher)
|
||||
{
|
||||
mp_ui = new Ui::EditorOptionsGeneric ();
|
||||
mp_ui->setupUi (this);
|
||||
|
|
@ -206,8 +206,8 @@ EditorOptionsGeneric::setup (lay::Dispatcher *root)
|
|||
// ------------------------------------------------------------------
|
||||
// EditorOptionsText implementation
|
||||
|
||||
EditorOptionsText::EditorOptionsText (lay::Dispatcher *dispatcher)
|
||||
: lay::EditorOptionsPage (dispatcher)
|
||||
EditorOptionsText::EditorOptionsText (lay::LayoutView *view, lay::Dispatcher *dispatcher)
|
||||
: lay::EditorOptionsPage (view, dispatcher)
|
||||
{
|
||||
mp_ui = new Ui::EditorOptionsText ();
|
||||
mp_ui->setupUi (this);
|
||||
|
|
@ -284,8 +284,8 @@ EditorOptionsText::setup (lay::Dispatcher *root)
|
|||
// ------------------------------------------------------------------
|
||||
// EditorOptionsPath implementation
|
||||
|
||||
EditorOptionsPath::EditorOptionsPath (lay::Dispatcher *dispatcher)
|
||||
: lay::EditorOptionsPage (dispatcher)
|
||||
EditorOptionsPath::EditorOptionsPath (lay::LayoutView *view, lay::Dispatcher *dispatcher)
|
||||
: lay::EditorOptionsPage (view, dispatcher)
|
||||
{
|
||||
mp_ui = new Ui::EditorOptionsPath ();
|
||||
mp_ui->setupUi (this);
|
||||
|
|
@ -385,8 +385,8 @@ EditorOptionsPath::setup (lay::Dispatcher *root)
|
|||
// ------------------------------------------------------------------
|
||||
// EditorOptionsInst implementation
|
||||
|
||||
EditorOptionsInst::EditorOptionsInst (lay::Dispatcher *dispatcher)
|
||||
: lay::EditorOptionsPage (dispatcher)
|
||||
EditorOptionsInst::EditorOptionsInst (lay::LayoutView *view, lay::Dispatcher *dispatcher)
|
||||
: lay::EditorOptionsPage (view, dispatcher)
|
||||
{
|
||||
mp_ui = new Ui::EditorOptionsInst ();
|
||||
mp_ui->setupUi (this);
|
||||
|
|
@ -440,14 +440,13 @@ EditorOptionsInst::update_cell_edits ()
|
|||
}
|
||||
|
||||
db::Layout *layout = 0;
|
||||
lay::LayoutView *view = lay::LayoutView::current ();
|
||||
|
||||
// find the layout the cell has to be looked up: that is either the layout of the current instance or
|
||||
// the library selected
|
||||
if (mp_ui->lib_cbx->current_library ()) {
|
||||
layout = &mp_ui->lib_cbx->current_library ()->layout ();
|
||||
} else if (view && view->cellview (m_cv_index).is_valid ()) {
|
||||
layout = &view->cellview (m_cv_index)->layout ();
|
||||
} else if (view ()->cellview (m_cv_index).is_valid ()) {
|
||||
layout = &view ()->cellview (m_cv_index)->layout ();
|
||||
}
|
||||
|
||||
if (! layout) {
|
||||
|
|
@ -485,7 +484,7 @@ EditorOptionsInst::browse_cell ()
|
|||
{
|
||||
BEGIN_PROTECTED
|
||||
|
||||
if (m_cv_index >= 0 && lay::LayoutView::current () && lay::LayoutView::current ()->cellview (m_cv_index).is_valid ()) {
|
||||
if (m_cv_index >= 0 && view ()->cellview (m_cv_index).is_valid ()) {
|
||||
|
||||
// find the layout the cell has to be looked up: that is either the layout of the current instance or
|
||||
// the library selected
|
||||
|
|
@ -495,7 +494,7 @@ BEGIN_PROTECTED
|
|||
lib = mp_ui->lib_cbx->current_library ();
|
||||
layout = &lib->layout ();
|
||||
} else {
|
||||
layout = &lay::LayoutView::current ()->cellview (m_cv_index)->layout ();
|
||||
layout = &view ()->cellview (m_cv_index)->layout ();
|
||||
}
|
||||
|
||||
bool all_cells = (mp_ui->lib_cbx->current_library () != 0 ? false : true);
|
||||
|
|
@ -579,24 +578,36 @@ EditorOptionsInst::apply (lay::Dispatcher *root)
|
|||
root->config_set (cfg_edit_inst_place_origin, tl::to_string (place_origin));
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
EditorOptionsInst::technology_changed (const std::string &)
|
||||
{
|
||||
// The layout's technology has changed
|
||||
setup (dispatcher ());
|
||||
}
|
||||
|
||||
void
|
||||
EditorOptionsInst::active_cellview_changed ()
|
||||
{
|
||||
// The active cellview has changed
|
||||
setup (dispatcher ());
|
||||
}
|
||||
|
||||
void
|
||||
EditorOptionsInst::setup (lay::Dispatcher *root)
|
||||
{
|
||||
m_cv_index = -1;
|
||||
if (lay::LayoutView::current ()) {
|
||||
m_cv_index = lay::LayoutView::current ()->active_cellview_index ();
|
||||
}
|
||||
m_cv_index = view ()->active_cellview_index ();
|
||||
|
||||
try {
|
||||
|
||||
mp_ui->lib_cbx->blockSignals (true);
|
||||
|
||||
std::string techname;
|
||||
|
||||
mp_ui->lib_cbx->update_list ();
|
||||
if (m_cv_index >= 0 && lay::LayoutView::current () && lay::LayoutView::current ()->cellview (m_cv_index).is_valid ()) {
|
||||
mp_ui->lib_cbx->set_technology_filter (lay::LayoutView::current ()->cellview (m_cv_index)->tech_name (), true);
|
||||
} else {
|
||||
mp_ui->lib_cbx->set_technology_filter (std::string (), false);
|
||||
if (m_cv_index >= 0 && view ()->cellview (m_cv_index).is_valid ()) {
|
||||
techname = view ()->cellview (m_cv_index)->tech_name ();
|
||||
}
|
||||
mp_ui->lib_cbx->set_technology_filter (techname, ! techname.empty ());
|
||||
|
||||
// cell name
|
||||
std::string s;
|
||||
|
|
@ -606,7 +617,7 @@ EditorOptionsInst::setup (lay::Dispatcher *root)
|
|||
// library
|
||||
std::string l;
|
||||
root->config_get (cfg_edit_inst_lib_name, l);
|
||||
mp_ui->lib_cbx->set_current_library (db::LibraryManager::instance ().lib_ptr_by_name (l));
|
||||
mp_ui->lib_cbx->set_current_library (db::LibraryManager::instance ().lib_ptr_by_name (l, techname));
|
||||
|
||||
mp_ui->lib_cbx->blockSignals (false);
|
||||
update_cell_edits ();
|
||||
|
|
@ -667,8 +678,8 @@ EditorOptionsInst::setup (lay::Dispatcher *root)
|
|||
// ------------------------------------------------------------------
|
||||
// EditorOptionsInstPCellParam implementation
|
||||
|
||||
EditorOptionsInstPCellParam::EditorOptionsInstPCellParam (lay::Dispatcher *dispatcher)
|
||||
: lay::EditorOptionsPage (dispatcher), mp_pcell_parameters (0), mp_placeholder_label (0)
|
||||
EditorOptionsInstPCellParam::EditorOptionsInstPCellParam (lay::LayoutView *view, lay::Dispatcher *dispatcher)
|
||||
: lay::EditorOptionsPage (view, dispatcher), mp_pcell_parameters (0), mp_placeholder_label (0)
|
||||
{
|
||||
mp_ui = new Ui::EditorOptionsInstPCellParam ();
|
||||
mp_ui->setupUi (this);
|
||||
|
|
@ -693,11 +704,11 @@ EditorOptionsInstPCellParam::apply (lay::Dispatcher *root)
|
|||
std::string param;
|
||||
db::Layout *layout = 0;
|
||||
|
||||
db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (m_lib_name);
|
||||
db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (m_lib_name, view ()->active_cellview ().is_valid () ? view ()->active_cellview ()->tech_name () : std::string ());
|
||||
if (lib) {
|
||||
layout = &lib->layout ();
|
||||
} else if (m_cv_index >= 0 && lay::LayoutView::current () && lay::LayoutView::current ()->cellview (m_cv_index).is_valid ()) {
|
||||
layout = &lay::LayoutView::current ()->cellview (m_cv_index)->layout ();
|
||||
} else if (m_cv_index >= 0 && view ()->cellview (m_cv_index).is_valid ()) {
|
||||
layout = &view ()->cellview (m_cv_index)->layout ();
|
||||
}
|
||||
|
||||
bool ok = true;
|
||||
|
|
@ -717,13 +728,16 @@ EditorOptionsInstPCellParam::apply (lay::Dispatcher *root)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
EditorOptionsInstPCellParam::technology_changed (const std::string &)
|
||||
{
|
||||
setup (dispatcher ());
|
||||
}
|
||||
|
||||
void
|
||||
EditorOptionsInstPCellParam::setup (lay::Dispatcher *root)
|
||||
{
|
||||
m_cv_index = -1;
|
||||
if (lay::LayoutView::current ()) {
|
||||
m_cv_index = lay::LayoutView::current ()->active_cellview_index ();
|
||||
}
|
||||
m_cv_index = view ()->active_cellview_index ();
|
||||
|
||||
bool needs_update = (mp_pcell_parameters == 0);
|
||||
|
||||
|
|
@ -743,7 +757,7 @@ EditorOptionsInstPCellParam::setup (lay::Dispatcher *root)
|
|||
needs_update = true;
|
||||
}
|
||||
|
||||
db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (m_lib_name);
|
||||
db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (m_lib_name, view ()->active_cellview ().is_valid () ? view ()->active_cellview ()->tech_name () : std::string ());
|
||||
|
||||
// pcell parameters
|
||||
std::string param;
|
||||
|
|
@ -752,8 +766,8 @@ EditorOptionsInstPCellParam::setup (lay::Dispatcher *root)
|
|||
db::Layout *layout = 0;
|
||||
if (lib) {
|
||||
layout = &lib->layout ();
|
||||
} else if (m_cv_index >= 0 && lay::LayoutView::current () && lay::LayoutView::current ()->cellview (m_cv_index).is_valid ()) {
|
||||
layout = &lay::LayoutView::current ()->cellview (m_cv_index)->layout ();
|
||||
} else if (m_cv_index >= 0 && view ()->cellview (m_cv_index).is_valid ()) {
|
||||
layout = &view ()->cellview (m_cv_index)->layout ();
|
||||
}
|
||||
|
||||
std::vector<tl::Variant> pv;
|
||||
|
|
@ -820,15 +834,14 @@ void
|
|||
EditorOptionsInstPCellParam::update_pcell_parameters (const std::vector <tl::Variant> ¶meters)
|
||||
{
|
||||
db::Layout *layout = 0;
|
||||
lay::LayoutView *view = lay::LayoutView::current ();
|
||||
|
||||
// find the layout the cell has to be looked up: that is either the layout of the current instance or
|
||||
// the library selected
|
||||
db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (m_lib_name);
|
||||
db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (m_lib_name, view ()->active_cellview ().is_valid () ? view ()->active_cellview ()->tech_name () : std::string ());
|
||||
if (lib) {
|
||||
layout = &lib->layout ();
|
||||
} else if (view) {
|
||||
const lay::CellView &cv = view->cellview (m_cv_index);
|
||||
} else {
|
||||
const lay::CellView &cv = view ()->cellview (m_cv_index);
|
||||
if (cv.is_valid ()) {
|
||||
layout = &cv->layout ();
|
||||
}
|
||||
|
|
@ -856,10 +869,10 @@ EditorOptionsInstPCellParam::update_pcell_parameters (const std::vector <tl::Var
|
|||
mp_pcell_parameters = 0;
|
||||
mp_placeholder_label = 0;
|
||||
|
||||
if (pc.first && layout->pcell_declaration (pc.second) && view && view->cellview (m_cv_index).is_valid ()) {
|
||||
if (pc.first && layout->pcell_declaration (pc.second) && view ()->cellview (m_cv_index).is_valid ()) {
|
||||
|
||||
mp_pcell_parameters = new PCellParametersPage (this, true /*dense*/);
|
||||
mp_pcell_parameters->setup (&view->cellview (m_cv_index)->layout (), view, m_cv_index, layout->pcell_declaration (pc.second), parameters);
|
||||
mp_pcell_parameters->setup (&view ()->cellview (m_cv_index)->layout (), view (), m_cv_index, layout->pcell_declaration (pc.second), parameters);
|
||||
this->layout ()->addWidget (mp_pcell_parameters);
|
||||
|
||||
mp_pcell_parameters->set_state (pcp_state);
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ namespace lay
|
|||
{
|
||||
class PluginDeclaration;
|
||||
class Dispatcher;
|
||||
class LayoutView;
|
||||
class Plugin;
|
||||
}
|
||||
|
||||
|
|
@ -68,7 +69,7 @@ class EditorOptionsGeneric
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
EditorOptionsGeneric (lay::Dispatcher *dispatcher);
|
||||
EditorOptionsGeneric (lay::LayoutView *view, lay::Dispatcher *dispatcher);
|
||||
~EditorOptionsGeneric ();
|
||||
|
||||
virtual std::string title () const;
|
||||
|
|
@ -91,7 +92,7 @@ class EditorOptionsText
|
|||
: public lay::EditorOptionsPage
|
||||
{
|
||||
public:
|
||||
EditorOptionsText (lay::Dispatcher *dispatcher);
|
||||
EditorOptionsText (lay::LayoutView *view, lay::Dispatcher *dispatcher);
|
||||
~EditorOptionsText ();
|
||||
|
||||
virtual std::string title () const;
|
||||
|
|
@ -112,7 +113,7 @@ class EditorOptionsPath
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
EditorOptionsPath (lay::Dispatcher *dispatcher);
|
||||
EditorOptionsPath (lay::LayoutView *view, lay::Dispatcher *dispatcher);
|
||||
~EditorOptionsPath ();
|
||||
|
||||
virtual std::string title () const;
|
||||
|
|
@ -136,7 +137,7 @@ class EditorOptionsInst
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
EditorOptionsInst (lay::Dispatcher *root);
|
||||
EditorOptionsInst (lay::LayoutView *view, lay::Dispatcher *root);
|
||||
~EditorOptionsInst ();
|
||||
|
||||
virtual std::string title () const;
|
||||
|
|
@ -154,6 +155,9 @@ private:
|
|||
Ui::EditorOptionsInst *mp_ui;
|
||||
edt::PCellParametersPage *mp_pcell_parameters;
|
||||
int m_cv_index;
|
||||
|
||||
virtual void technology_changed (const std::string &);
|
||||
virtual void active_cellview_changed ();
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -165,7 +169,7 @@ class EditorOptionsInstPCellParam
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
EditorOptionsInstPCellParam (lay::Dispatcher *root);
|
||||
EditorOptionsInstPCellParam (lay::LayoutView *view, lay::Dispatcher *root);
|
||||
~EditorOptionsInstPCellParam ();
|
||||
|
||||
virtual std::string title () const;
|
||||
|
|
@ -184,6 +188,7 @@ private:
|
|||
std::string m_lib_name, m_cell_name;
|
||||
|
||||
void update_pcell_parameters (const std::vector <tl::Variant> ¶meters);
|
||||
virtual void technology_changed (const std::string &);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -153,7 +153,7 @@ PCellParametersPage::PCellParametersPage (QWidget *parent, bool dense)
|
|||
void
|
||||
PCellParametersPage::init ()
|
||||
{
|
||||
mp_pcell_decl = 0;
|
||||
mp_pcell_decl.reset (0);
|
||||
mp_layout = 0;
|
||||
mp_view = 0;
|
||||
m_cv_index = 0;
|
||||
|
|
@ -185,7 +185,7 @@ PCellParametersPage::init ()
|
|||
void
|
||||
PCellParametersPage::setup (const db::Layout *layout, lay::LayoutView *view, int cv_index, const db::PCellDeclaration *pcell_decl, const db::pcell_parameters_type ¶meters)
|
||||
{
|
||||
mp_pcell_decl = pcell_decl;
|
||||
mp_pcell_decl.reset (const_cast<db::PCellDeclaration *> (pcell_decl)); // no const weak_ptr ...
|
||||
mp_layout = layout;
|
||||
mp_view = view;
|
||||
m_cv_index = cv_index;
|
||||
|
|
@ -457,131 +457,136 @@ std::vector<tl::Variant>
|
|||
PCellParametersPage::get_parameters (bool *ok)
|
||||
{
|
||||
std::vector<tl::Variant> parameters;
|
||||
bool edit_error = true;
|
||||
|
||||
int r = 0;
|
||||
const std::vector<db::PCellParameterDeclaration> &pcp = mp_pcell_decl->parameter_declarations ();
|
||||
for (std::vector<db::PCellParameterDeclaration>::const_iterator p = pcp.begin (); p != pcp.end (); ++p, ++r) {
|
||||
try {
|
||||
|
||||
if (p->is_hidden () || p->get_type () == db::PCellParameterDeclaration::t_shape) {
|
||||
if (! mp_pcell_decl) {
|
||||
throw tl::Exception (tl::to_string (tr ("PCell no longer valid.")));
|
||||
}
|
||||
|
||||
if (r < (int) m_parameters.size ()) {
|
||||
parameters.push_back (m_parameters [r]);
|
||||
} else {
|
||||
parameters.push_back (p->get_default ());
|
||||
}
|
||||
bool edit_error = true;
|
||||
|
||||
} else {
|
||||
int r = 0;
|
||||
const std::vector<db::PCellParameterDeclaration> &pcp = mp_pcell_decl->parameter_declarations ();
|
||||
for (std::vector<db::PCellParameterDeclaration>::const_iterator p = pcp.begin (); p != pcp.end (); ++p, ++r) {
|
||||
|
||||
parameters.push_back (tl::Variant ());
|
||||
if (p->is_hidden () || p->get_type () == db::PCellParameterDeclaration::t_shape) {
|
||||
|
||||
if (p->get_choices ().empty ()) {
|
||||
|
||||
switch (p->get_type ()) {
|
||||
|
||||
case db::PCellParameterDeclaration::t_int:
|
||||
{
|
||||
QLineEdit *le = dynamic_cast<QLineEdit *> (m_widgets [r]);
|
||||
if (le) {
|
||||
|
||||
try {
|
||||
|
||||
int v = 0;
|
||||
tl::from_string (tl::to_string (le->text ()), v);
|
||||
|
||||
parameters.back () = tl::Variant (v);
|
||||
lay::indicate_error (le, 0);
|
||||
|
||||
} catch (tl::Exception &ex) {
|
||||
|
||||
lay::indicate_error (le, &ex);
|
||||
edit_error = false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case db::PCellParameterDeclaration::t_double:
|
||||
{
|
||||
QLineEdit *le = dynamic_cast<QLineEdit *> (m_widgets [r]);
|
||||
if (le) {
|
||||
|
||||
try {
|
||||
|
||||
double v = 0;
|
||||
tl::from_string (tl::to_string (le->text ()), v);
|
||||
|
||||
parameters.back () = tl::Variant (v);
|
||||
lay::indicate_error (le, 0);
|
||||
|
||||
} catch (tl::Exception &ex) {
|
||||
|
||||
lay::indicate_error (le, &ex);
|
||||
edit_error = false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case db::PCellParameterDeclaration::t_string:
|
||||
{
|
||||
QLineEdit *le = dynamic_cast<QLineEdit *> (m_widgets [r]);
|
||||
if (le) {
|
||||
parameters.back () = tl::Variant (tl::to_string (le->text ()));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case db::PCellParameterDeclaration::t_list:
|
||||
{
|
||||
QLineEdit *le = dynamic_cast<QLineEdit *> (m_widgets [r]);
|
||||
if (le) {
|
||||
std::vector<std::string> values = tl::split (tl::to_string (le->text ()), ",");
|
||||
parameters.back () = tl::Variant (values.begin (), values.end ());
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case db::PCellParameterDeclaration::t_layer:
|
||||
{
|
||||
lay::LayerSelectionComboBox *ly = dynamic_cast<lay::LayerSelectionComboBox *> (m_widgets [r]);
|
||||
if (ly) {
|
||||
parameters.back () = tl::Variant (ly->current_layer_props ());
|
||||
}
|
||||
}
|
||||
break;
|
||||
case db::PCellParameterDeclaration::t_boolean:
|
||||
{
|
||||
QCheckBox *cbx = dynamic_cast<QCheckBox *> (m_widgets [r]);
|
||||
if (cbx) {
|
||||
parameters.back () = tl::Variant (cbx->isChecked ());
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
if (r < (int) m_parameters.size ()) {
|
||||
parameters.push_back (m_parameters [r]);
|
||||
} else {
|
||||
parameters.push_back (p->get_default ());
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
QComboBox *cb = dynamic_cast<QComboBox*> (m_widgets [r]);
|
||||
if (cb && cb->currentIndex () >= 0 && cb->currentIndex () < int (p->get_choices ().size ())) {
|
||||
parameters.back () = p->get_choices () [cb->currentIndex ()];
|
||||
parameters.push_back (tl::Variant ());
|
||||
|
||||
if (p->get_choices ().empty ()) {
|
||||
|
||||
switch (p->get_type ()) {
|
||||
|
||||
case db::PCellParameterDeclaration::t_int:
|
||||
{
|
||||
QLineEdit *le = dynamic_cast<QLineEdit *> (m_widgets [r]);
|
||||
if (le) {
|
||||
|
||||
try {
|
||||
|
||||
int v = 0;
|
||||
tl::from_string (tl::to_string (le->text ()), v);
|
||||
|
||||
parameters.back () = tl::Variant (v);
|
||||
lay::indicate_error (le, 0);
|
||||
|
||||
} catch (tl::Exception &ex) {
|
||||
|
||||
lay::indicate_error (le, &ex);
|
||||
edit_error = false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case db::PCellParameterDeclaration::t_double:
|
||||
{
|
||||
QLineEdit *le = dynamic_cast<QLineEdit *> (m_widgets [r]);
|
||||
if (le) {
|
||||
|
||||
try {
|
||||
|
||||
double v = 0;
|
||||
tl::from_string (tl::to_string (le->text ()), v);
|
||||
|
||||
parameters.back () = tl::Variant (v);
|
||||
lay::indicate_error (le, 0);
|
||||
|
||||
} catch (tl::Exception &ex) {
|
||||
|
||||
lay::indicate_error (le, &ex);
|
||||
edit_error = false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case db::PCellParameterDeclaration::t_string:
|
||||
{
|
||||
QLineEdit *le = dynamic_cast<QLineEdit *> (m_widgets [r]);
|
||||
if (le) {
|
||||
parameters.back () = tl::Variant (tl::to_string (le->text ()));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case db::PCellParameterDeclaration::t_list:
|
||||
{
|
||||
QLineEdit *le = dynamic_cast<QLineEdit *> (m_widgets [r]);
|
||||
if (le) {
|
||||
std::vector<std::string> values = tl::split (tl::to_string (le->text ()), ",");
|
||||
parameters.back () = tl::Variant (values.begin (), values.end ());
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case db::PCellParameterDeclaration::t_layer:
|
||||
{
|
||||
lay::LayerSelectionComboBox *ly = dynamic_cast<lay::LayerSelectionComboBox *> (m_widgets [r]);
|
||||
if (ly) {
|
||||
parameters.back () = tl::Variant (ly->current_layer_props ());
|
||||
}
|
||||
}
|
||||
break;
|
||||
case db::PCellParameterDeclaration::t_boolean:
|
||||
{
|
||||
QCheckBox *cbx = dynamic_cast<QCheckBox *> (m_widgets [r]);
|
||||
if (cbx) {
|
||||
parameters.back () = tl::Variant (cbx->isChecked ());
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
QComboBox *cb = dynamic_cast<QComboBox*> (m_widgets [r]);
|
||||
if (cb && cb->currentIndex () >= 0 && cb->currentIndex () < int (p->get_choices ().size ())) {
|
||||
parameters.back () = p->get_choices () [cb->currentIndex ()];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
if (! edit_error) {
|
||||
throw tl::Exception (tl::to_string (tr ("There are errors. See the highlighted edit fields for details.")));
|
||||
}
|
||||
|
|
@ -628,6 +633,10 @@ PCellParametersPage::get_parameters (bool *ok)
|
|||
void
|
||||
PCellParametersPage::set_parameters (const std::vector<tl::Variant> ¶meters)
|
||||
{
|
||||
if (! mp_pcell_decl) {
|
||||
return;
|
||||
}
|
||||
|
||||
// write the changed value back
|
||||
size_t r = 0;
|
||||
const std::vector<db::PCellParameterDeclaration> &pcp = mp_pcell_decl->parameter_declarations ();
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ public:
|
|||
*/
|
||||
const db::PCellDeclaration *pcell_decl () const
|
||||
{
|
||||
return mp_pcell_decl;
|
||||
return mp_pcell_decl.get ();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -122,7 +122,7 @@ private:
|
|||
QScrollArea *mp_parameters_area;
|
||||
QLabel *mp_error_label;
|
||||
QLabel *mp_error_icon;
|
||||
const db::PCellDeclaration *mp_pcell_decl;
|
||||
tl::weak_ptr<db::PCellDeclaration> mp_pcell_decl;
|
||||
std::vector<QWidget *> m_widgets;
|
||||
const db::Layout *mp_layout;
|
||||
lay::LayoutView *mp_view;
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ void get_text_editor_options_pages (std::vector<lay::EditorOptionsPage *> &ret,
|
|||
|
||||
ret.push_back (new RecentConfigurationPage (view, dispatcher, "edit-recent-text-param",
|
||||
&text_cfg_descriptors[0], &text_cfg_descriptors[sizeof (text_cfg_descriptors) / sizeof (text_cfg_descriptors[0])]));
|
||||
ret.push_back (new edt::EditorOptionsText (dispatcher));
|
||||
ret.push_back (new edt::EditorOptionsText (view, dispatcher));
|
||||
}
|
||||
|
||||
static
|
||||
|
|
@ -101,7 +101,7 @@ void get_path_editor_options_pages (std::vector<lay::EditorOptionsPage *> &ret,
|
|||
|
||||
ret.push_back (new RecentConfigurationPage (view, dispatcher, "edit-recent-path-param",
|
||||
&path_cfg_descriptors[0], &path_cfg_descriptors[sizeof (path_cfg_descriptors) / sizeof (path_cfg_descriptors[0])]));
|
||||
ret.push_back (new EditorOptionsPath (dispatcher));
|
||||
ret.push_back (new EditorOptionsPath (view, dispatcher));
|
||||
}
|
||||
|
||||
static
|
||||
|
|
@ -145,8 +145,8 @@ void get_inst_editor_options_pages (std::vector<lay::EditorOptionsPage *> &ret,
|
|||
|
||||
ret.push_back (new RecentConfigurationPage (view, dispatcher, "edit-recent-inst-param",
|
||||
&inst_cfg_descriptors[0], &inst_cfg_descriptors[sizeof (inst_cfg_descriptors) / sizeof (inst_cfg_descriptors[0])]));
|
||||
ret.push_back (new EditorOptionsInstPCellParam (dispatcher));
|
||||
ret.push_back (new EditorOptionsInst (dispatcher));
|
||||
ret.push_back (new EditorOptionsInstPCellParam (view, dispatcher));
|
||||
ret.push_back (new EditorOptionsInst (view, dispatcher));
|
||||
}
|
||||
|
||||
template <class Svc>
|
||||
|
|
@ -327,10 +327,10 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
virtual void get_editor_options_pages (std::vector<lay::EditorOptionsPage *> &pages, lay::LayoutView * /*view*/, lay::Dispatcher *dispatcher) const
|
||||
virtual void get_editor_options_pages (std::vector<lay::EditorOptionsPage *> &pages, lay::LayoutView *view, lay::Dispatcher *dispatcher) const
|
||||
{
|
||||
// NOTE: we do not set plugin_declaration which makes the page unspecific
|
||||
EditorOptionsGeneric *generic_opt = new EditorOptionsGeneric (dispatcher);
|
||||
EditorOptionsGeneric *generic_opt = new EditorOptionsGeneric (view, dispatcher);
|
||||
pages.push_back (generic_opt);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ RecentConfigurationPage::init ()
|
|||
ly->addWidget (mp_tree_widget);
|
||||
|
||||
connect (mp_tree_widget, SIGNAL (itemClicked (QTreeWidgetItem *, int)), this, SLOT (item_clicked (QTreeWidgetItem *)));
|
||||
mp_view->layer_list_changed_event.add (this, &RecentConfigurationPage::layers_changed);
|
||||
view ()->layer_list_changed_event.add (this, &RecentConfigurationPage::layers_changed);
|
||||
|
||||
mp_tree_widget->setColumnCount (int (m_cfg.size ()));
|
||||
|
||||
|
|
@ -179,15 +179,15 @@ RecentConfigurationPage::render_to (QTreeWidgetItem *item, int column, const std
|
|||
|
||||
case RecentConfigurationPage::Layer:
|
||||
{
|
||||
int icon_size = mp_view->style ()->pixelMetric (QStyle::PM_ButtonIconSize);
|
||||
int icon_size = view ()->style ()->pixelMetric (QStyle::PM_ButtonIconSize);
|
||||
lay::LayerPropertiesConstIterator l;
|
||||
try {
|
||||
l = lp_iter_from_string (mp_view, values [column]);
|
||||
l = lp_iter_from_string (view (), values [column]);
|
||||
} catch (tl::Exception &ex) {
|
||||
tl::error << tl::to_string (tr ("Configuration error (Layer): ")) << ex.msg ();
|
||||
}
|
||||
if (! l.is_null () && ! l.at_end ()) {
|
||||
item->setIcon (column, lay::LayerTreeModel::icon_for_layer (l, mp_view, icon_size, icon_size, 0, true));
|
||||
item->setIcon (column, lay::LayerTreeModel::icon_for_layer (l, view (), icon_size, icon_size, 0, true));
|
||||
item->setText (column, tl::to_qstring (values [column]));
|
||||
} else {
|
||||
item->setIcon (column, QIcon ());
|
||||
|
|
@ -241,7 +241,11 @@ RecentConfigurationPage::render_to (QTreeWidgetItem *item, int column, const std
|
|||
const db::Library *lib = 0;
|
||||
for (std::list<ConfigurationDescriptor>::const_iterator c = m_cfg.begin (); c != m_cfg.end (); ++c, ++libname_column) {
|
||||
if (c->rendering == RecentConfigurationPage::CellLibraryName) {
|
||||
lib = db::LibraryManager::instance ().lib_ptr_by_name (values [libname_column]);
|
||||
if (view ()->active_cellview ().is_valid ()) {
|
||||
lib = db::LibraryManager::instance ().lib_ptr_by_name (values [libname_column], view ()->active_cellview ()->tech_name ());
|
||||
} else {
|
||||
lib = db::LibraryManager::instance ().lib_ptr_by_name (values [libname_column]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -304,6 +308,12 @@ RecentConfigurationPage::layers_changed (int)
|
|||
update_list (get_stored_values ());
|
||||
}
|
||||
|
||||
void
|
||||
RecentConfigurationPage::technology_changed (const std::string &)
|
||||
{
|
||||
update_list (get_stored_values ());
|
||||
}
|
||||
|
||||
void
|
||||
RecentConfigurationPage::update_list (const std::list<std::vector<std::string> > &stored_values)
|
||||
{
|
||||
|
|
@ -353,7 +363,7 @@ RecentConfigurationPage::item_clicked (QTreeWidgetItem *item)
|
|||
ex.read (cv_index);
|
||||
}
|
||||
|
||||
mp_view->set_or_request_current_layer (cv_index, lp);
|
||||
view ()->set_or_request_current_layer (cv_index, lp);
|
||||
|
||||
} else {
|
||||
dispatcher ()->config_set (c->cfg_name, v);
|
||||
|
|
@ -375,11 +385,11 @@ RecentConfigurationPage::commit_recent (lay::Dispatcher *root)
|
|||
|
||||
std::string s;
|
||||
|
||||
if (!(mp_view->current_layer ().is_null () || mp_view->current_layer ().at_end ()) && mp_view->current_layer ()->is_visual ()) {
|
||||
if (!(view ()->current_layer ().is_null () || view ()->current_layer ().at_end ()) && view ()->current_layer ()->is_visual ()) {
|
||||
|
||||
int cv_index = mp_view->current_layer ()->cellview_index ();
|
||||
const lay::CellView &cv = mp_view->cellview (cv_index);
|
||||
int li = mp_view->current_layer ()->layer_index ();
|
||||
int cv_index = view ()->current_layer ()->cellview_index ();
|
||||
const lay::CellView &cv = view ()->cellview (cv_index);
|
||||
int li = view ()->current_layer ()->layer_index ();
|
||||
if (cv.is_valid () && cv->layout ().is_valid_layer (li)) {
|
||||
s = cv->layout ().get_properties (li).to_string ();
|
||||
if (cv_index > 0) {
|
||||
|
|
|
|||
|
|
@ -46,8 +46,7 @@ class EditorOptionsPages;
|
|||
* @brief The base class for a object properties page
|
||||
*/
|
||||
class RecentConfigurationPage
|
||||
: public lay::EditorOptionsPage,
|
||||
public tl::Object
|
||||
: public lay::EditorOptionsPage
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
|
@ -79,7 +78,7 @@ public:
|
|||
|
||||
template <class Iter>
|
||||
RecentConfigurationPage (lay::LayoutView *view, lay::Dispatcher *dispatcher, const std::string &recent_cfg_name, Iter begin_cfg, Iter end_cfg)
|
||||
: EditorOptionsPage (dispatcher), mp_view (view), m_recent_cfg_name (recent_cfg_name), m_cfg (begin_cfg, end_cfg)
|
||||
: EditorOptionsPage (view, dispatcher), m_recent_cfg_name (recent_cfg_name), m_cfg (begin_cfg, end_cfg)
|
||||
{
|
||||
init ();
|
||||
}
|
||||
|
|
@ -96,7 +95,6 @@ private slots:
|
|||
void item_clicked (QTreeWidgetItem *item);
|
||||
|
||||
private:
|
||||
lay::LayoutView *mp_view;
|
||||
std::string m_recent_cfg_name;
|
||||
std::list<ConfigurationDescriptor> m_cfg;
|
||||
QTreeWidget *mp_tree_widget;
|
||||
|
|
@ -107,6 +105,7 @@ private:
|
|||
void set_stored_values (const std::list<std::vector<std::string> > &values) const;
|
||||
void render_to (QTreeWidgetItem *item, int column, const std::vector<std::string> &values, RecentConfigurationPage::ConfigurationRendering rendering);
|
||||
void layers_changed (int);
|
||||
virtual void technology_changed (const std::string &);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1414,7 +1414,7 @@ InstService::make_cell (const lay::CellView &cv)
|
|||
|
||||
lay::LayerState layer_state = view ()->layer_snapshot ();
|
||||
|
||||
db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (m_lib_name);
|
||||
db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (m_lib_name, cv->tech_name ());
|
||||
|
||||
// find the layout the cell has to be looked up: that is either the layout of the current instance or
|
||||
// the library selected
|
||||
|
|
@ -1853,8 +1853,13 @@ InstService::switch_cell_or_pcell (bool switch_parameters)
|
|||
|
||||
}
|
||||
|
||||
db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (m_lib_name);
|
||||
const lay::CellView &cv = view ()->cellview (m_cv_index);
|
||||
db::Library *lib = 0;
|
||||
if (cv.is_valid ()) {
|
||||
lib = db::LibraryManager::instance ().lib_ptr_by_name (m_lib_name, cv->tech_name ());
|
||||
} else {
|
||||
lib = db::LibraryManager::instance ().lib_ptr_by_name (m_lib_name);
|
||||
}
|
||||
|
||||
// find the layout the cell has to be looked up: that is either the layout of the current instance or
|
||||
// the library selected
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ LibraryController::sync_files ()
|
|||
m_file_watcher->enable (false);
|
||||
}
|
||||
|
||||
std::map<std::string, std::pair<std::string, QDateTime> > new_lib_files;
|
||||
std::map<std::string, LibInfo> new_lib_files;
|
||||
|
||||
// build a list of paths vs. technology
|
||||
std::vector<std::pair<std::string, std::string> > paths;
|
||||
|
|
@ -174,11 +174,11 @@ LibraryController::sync_files ()
|
|||
QFileInfo fi (tl::to_qstring (lib_path));
|
||||
|
||||
bool needs_load = false;
|
||||
std::map<std::string, std::pair<std::string, QDateTime> >::iterator ll = m_lib_files.find (lib_path);
|
||||
std::map<std::string, LibInfo>::iterator ll = m_lib_files.find (lib_path);
|
||||
if (ll == m_lib_files.end ()) {
|
||||
needs_load = true;
|
||||
} else {
|
||||
if (fi.lastModified () > ll->second.second) {
|
||||
if (fi.lastModified () > ll->second.time) {
|
||||
needs_load = true;
|
||||
} else {
|
||||
new_lib_files.insert (*ll);
|
||||
|
|
@ -189,7 +189,9 @@ LibraryController::sync_files ()
|
|||
|
||||
std::auto_ptr<db::Library> lib (new db::Library ());
|
||||
lib->set_description (filename);
|
||||
lib->set_technology (p->second);
|
||||
if (! p->second.empty ()) {
|
||||
lib->set_technology (p->second);
|
||||
}
|
||||
lib->set_name (tl::to_string (QFileInfo (*im).baseName ()));
|
||||
|
||||
tl::log << "Reading library '" << lib_path << "'";
|
||||
|
|
@ -205,8 +207,19 @@ LibraryController::sync_files ()
|
|||
}
|
||||
}
|
||||
|
||||
tl::log << "Registering as '" << lib->get_name () << "' for tech '" << p->second << "'";
|
||||
new_lib_files.insert (std::make_pair (lib_path, std::make_pair (lib->get_name (), fi.lastModified ())));
|
||||
if (! p->second.empty ()) {
|
||||
tl::log << "Registering as '" << lib->get_name () << "' for tech '" << p->second << "'";
|
||||
} else {
|
||||
tl::log << "Registering as '" << lib->get_name () << "'";
|
||||
}
|
||||
|
||||
LibInfo li;
|
||||
li.name = lib->get_name ();
|
||||
li.time = fi.lastModified ();
|
||||
if (! p->second.empty ()) {
|
||||
li.tech.insert (p->second);
|
||||
}
|
||||
new_lib_files.insert (std::make_pair (lib_path, li));
|
||||
|
||||
db::LibraryManager::instance ().register_lib (lib.release ());
|
||||
|
||||
|
|
@ -230,14 +243,14 @@ LibraryController::sync_files ()
|
|||
|
||||
std::set<std::string> new_names;
|
||||
|
||||
for (std::map<std::string, std::pair<std::string, QDateTime> >::const_iterator lf = new_lib_files.begin (); lf != new_lib_files.end (); ++lf) {
|
||||
new_names.insert (lf->second.first);
|
||||
for (std::map<std::string, LibInfo>::const_iterator lf = new_lib_files.begin (); lf != new_lib_files.end (); ++lf) {
|
||||
new_names.insert (lf->second.name);
|
||||
}
|
||||
|
||||
for (std::map<std::string, std::pair<std::string, QDateTime> >::const_iterator lf = m_lib_files.begin (); lf != m_lib_files.end (); ++lf) {
|
||||
if (new_names.find (lf->second.first) == new_names.end ()) {
|
||||
for (std::map<std::string, LibInfo>::const_iterator lf = m_lib_files.begin (); lf != m_lib_files.end (); ++lf) {
|
||||
if (new_names.find (lf->second.name) == new_names.end ()) {
|
||||
try {
|
||||
std::pair<bool, db::lib_id_type> li = db::LibraryManager::instance ().lib_by_name (lf->second.first);
|
||||
std::pair<bool, db::lib_id_type> li = db::LibraryManager::instance ().lib_by_name (lf->second.name, lf->second.tech);
|
||||
if (li.first) {
|
||||
db::LibraryManager::instance ().delete_lib (db::LibraryManager::instance ().lib (li.second));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -119,9 +119,17 @@ private slots:
|
|||
void sync_with_external_sources ();
|
||||
|
||||
private:
|
||||
struct LibInfo
|
||||
{
|
||||
LibInfo () : name (), time (), tech () { }
|
||||
std::string name;
|
||||
QDateTime time;
|
||||
std::set<std::string> tech;
|
||||
};
|
||||
|
||||
tl::FileSystemWatcher *m_file_watcher;
|
||||
tl::DeferredMethod<LibraryController> dm_sync_files;
|
||||
std::map<std::string, std::pair<std::string, QDateTime> > m_lib_files;
|
||||
std::map<std::string, LibInfo> m_lib_files;
|
||||
|
||||
void sync_files ();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2506,7 +2506,7 @@ void
|
|||
MainWindow::cm_new_layout ()
|
||||
{
|
||||
std::string technology = m_initial_technology;
|
||||
static std::string s_new_cell_cell_name;
|
||||
static std::string s_new_cell_cell_name ("TOP");
|
||||
static double s_new_cell_window_size = 2.0;
|
||||
|
||||
double dbu = 0.0;
|
||||
|
|
|
|||
|
|
@ -285,15 +285,33 @@ bool
|
|||
TechnologyController::menu_activated (const std::string &symbol) const
|
||||
{
|
||||
if (symbol == "technology_selector:apply_technology") {
|
||||
|
||||
if (lay::LayoutView::current () && lay::LayoutView::current ()->active_cellview ().is_valid ()) {
|
||||
// Cancels the current modes - changing the technology may make libraries unavailable
|
||||
// for example.
|
||||
|
||||
if (mp_mw) {
|
||||
|
||||
// Cancels the current modes - changing the technology may make libraries unavailable
|
||||
// for example.
|
||||
mp_mw->cancel ();
|
||||
|
||||
// apply technology with undo
|
||||
mp_mw->manager ().transaction (tl::sprintf (tl::to_string (tr ("Apply technology '%s'")), m_current_technology));
|
||||
try {
|
||||
lay::LayoutView::current ()->active_cellview ()->apply_technology (m_current_technology);
|
||||
mp_mw->manager ().commit ();
|
||||
} catch (...) {
|
||||
mp_mw->manager ().cancel ();
|
||||
throw;
|
||||
}
|
||||
|
||||
} else {
|
||||
lay::LayoutView::current ()->active_cellview ()->apply_technology (m_current_technology);
|
||||
}
|
||||
lay::LayoutView::current ()->active_cellview ()->apply_technology (m_current_technology);
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
} else {
|
||||
return lay::PluginDeclaration::menu_activated (symbol);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,6 +59,8 @@ LayoutHandle::LayoutHandle (db::Layout *layout, const std::string &filename)
|
|||
m_dirty (false),
|
||||
m_save_options_valid (false)
|
||||
{
|
||||
layout->technology_changed_event.add (this, &LayoutHandle::on_technology_changed);
|
||||
|
||||
// layouts in the managed layouts space participate in spare proxy cleanup
|
||||
layout->do_cleanup (true);
|
||||
|
||||
|
|
@ -108,6 +110,12 @@ LayoutHandle::~LayoutHandle ()
|
|||
file_watcher ().remove_file (filename ());
|
||||
}
|
||||
|
||||
void
|
||||
LayoutHandle::on_technology_changed ()
|
||||
{
|
||||
technology_changed_event ();
|
||||
}
|
||||
|
||||
void
|
||||
LayoutHandle::layout_changed ()
|
||||
{
|
||||
|
|
@ -206,13 +214,20 @@ LayoutHandle::remove_ref ()
|
|||
}
|
||||
}
|
||||
|
||||
const std::string &
|
||||
LayoutHandle::tech_name () const
|
||||
{
|
||||
static std::string s_empty;
|
||||
return mp_layout ? mp_layout->technology_name () : s_empty;
|
||||
}
|
||||
|
||||
const db::Technology *
|
||||
LayoutHandle::technology () const
|
||||
{
|
||||
return db::Technologies::instance ()->technology_by_name (m_tech_name);
|
||||
return mp_layout ? mp_layout->technology () : 0;
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
LayoutHandle::apply_technology (const std::string &tn)
|
||||
{
|
||||
set_tech_name (tn);
|
||||
|
|
@ -223,16 +238,8 @@ LayoutHandle::apply_technology (const std::string &tn)
|
|||
void
|
||||
LayoutHandle::set_tech_name (const std::string &tn)
|
||||
{
|
||||
if (tn != m_tech_name) {
|
||||
if (db::Technologies::instance ()->has_technology (tn)) {
|
||||
m_tech_name = tn;
|
||||
} else {
|
||||
m_tech_name = std::string ();
|
||||
}
|
||||
if (mp_layout) {
|
||||
mp_layout->add_meta_info (db::MetaInfo ("technology", tl::to_string (tr ("Technology name")), tn));
|
||||
}
|
||||
technology_changed_event ();
|
||||
if (mp_layout && tn != tech_name ()) {
|
||||
mp_layout->set_technology_name (tn);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -347,7 +354,7 @@ LayoutHandle::load (const db::LoadLayoutOptions &options, const std::string &tec
|
|||
|
||||
// If there is no technology given and the reader reports one, use this one
|
||||
if (technology.empty ()) {
|
||||
std::string tech_from_reader = layout ().meta_info_value ("technology");
|
||||
std::string tech_from_reader = layout ().technology_name ();
|
||||
if (! tech_from_reader.empty ()) {
|
||||
set_tech_name (tech_from_reader);
|
||||
}
|
||||
|
|
@ -373,7 +380,7 @@ LayoutHandle::load ()
|
|||
db::LayerMap new_lmap = reader.read (layout (), m_load_options);
|
||||
|
||||
// Attach the technology from the reader if it reports one
|
||||
std::string tech_from_reader = layout ().meta_info_value ("technology");
|
||||
std::string tech_from_reader = layout ().technology_name ();
|
||||
if (! tech_from_reader.empty ()) {
|
||||
set_tech_name (tech_from_reader);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -115,10 +115,7 @@ public:
|
|||
*
|
||||
* An empty name indicates the default technology should be used.
|
||||
*/
|
||||
const std::string &tech_name () const
|
||||
{
|
||||
return m_tech_name;
|
||||
}
|
||||
const std::string &tech_name () const;
|
||||
|
||||
/**
|
||||
* @brief Applies the given technology
|
||||
|
|
@ -300,12 +297,13 @@ private:
|
|||
int m_ref_count;
|
||||
std::string m_name;
|
||||
std::string m_filename;
|
||||
std::string m_tech_name;
|
||||
bool m_dirty;
|
||||
db::SaveLayoutOptions m_save_options;
|
||||
bool m_save_options_valid;
|
||||
db::LoadLayoutOptions m_load_options;
|
||||
|
||||
void on_technology_changed ();
|
||||
|
||||
static std::map <std::string, LayoutHandle *> ms_dict;
|
||||
static tl::FileSystemWatcher *mp_file_watcher;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
#include "tlInternational.h"
|
||||
#include "layEditorOptionsPage.h"
|
||||
#include "layEditorOptionsPages.h"
|
||||
#include "layLayoutView.h"
|
||||
|
||||
namespace lay
|
||||
{
|
||||
|
|
@ -31,10 +32,10 @@ namespace lay
|
|||
// ------------------------------------------------------------------
|
||||
// EditorOptionsPage implementation
|
||||
|
||||
EditorOptionsPage::EditorOptionsPage (lay::Dispatcher *dispatcher)
|
||||
: QWidget (0), mp_owner (0), m_active (true), mp_plugin_declaration (0), mp_dispatcher (dispatcher)
|
||||
EditorOptionsPage::EditorOptionsPage (lay::LayoutView *view, lay::Dispatcher *dispatcher)
|
||||
: QWidget (0), mp_owner (0), m_active (true), mp_plugin_declaration (0), mp_dispatcher (dispatcher), mp_view (view)
|
||||
{
|
||||
// nothing yet ..
|
||||
attach_events ();
|
||||
}
|
||||
|
||||
EditorOptionsPage::~EditorOptionsPage ()
|
||||
|
|
@ -42,6 +43,30 @@ EditorOptionsPage::~EditorOptionsPage ()
|
|||
set_owner (0);
|
||||
}
|
||||
|
||||
void
|
||||
EditorOptionsPage::attach_events ()
|
||||
{
|
||||
detach_from_all_events ();
|
||||
view ()->active_cellview_changed_event.add (this, &EditorOptionsPage::on_active_cellview_changed);
|
||||
int cv_index = view ()->active_cellview_index ();
|
||||
if (cv_index >= 0) {
|
||||
view ()->cellview (cv_index)->technology_changed_event.add (this, &EditorOptionsPage::on_technology_changed);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
EditorOptionsPage::on_active_cellview_changed ()
|
||||
{
|
||||
active_cellview_changed ();
|
||||
attach_events ();
|
||||
}
|
||||
|
||||
void
|
||||
EditorOptionsPage::on_technology_changed ()
|
||||
{
|
||||
technology_changed (view ()->active_cellview_ref ()->tech_name ());
|
||||
}
|
||||
|
||||
void
|
||||
EditorOptionsPage::set_owner (EditorOptionsPages *owner)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@
|
|||
|
||||
#include "laybasicCommon.h"
|
||||
|
||||
#include "tlObject.h"
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
namespace lay
|
||||
|
|
@ -32,19 +34,21 @@ namespace lay
|
|||
|
||||
class PluginDeclaration;
|
||||
class Dispatcher;
|
||||
class LayoutView;
|
||||
class Plugin;
|
||||
class CellView;
|
||||
class EditorOptionsPages;
|
||||
|
||||
/**
|
||||
* @brief The base class for a object properties page
|
||||
*/
|
||||
class LAYBASIC_PUBLIC EditorOptionsPage
|
||||
: public QWidget
|
||||
: public QWidget, public tl::Object
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
EditorOptionsPage (lay::Dispatcher *dispatcher);
|
||||
EditorOptionsPage (lay::LayoutView *view, lay::Dispatcher *dispatcher);
|
||||
virtual ~EditorOptionsPage ();
|
||||
|
||||
virtual std::string title () const = 0;
|
||||
|
|
@ -72,11 +76,24 @@ protected:
|
|||
return mp_dispatcher;
|
||||
}
|
||||
|
||||
lay::LayoutView *view () const
|
||||
{
|
||||
return mp_view;
|
||||
}
|
||||
|
||||
virtual void active_cellview_changed () { }
|
||||
virtual void technology_changed (const std::string & /*tech*/) { }
|
||||
|
||||
private:
|
||||
EditorOptionsPages *mp_owner;
|
||||
bool m_active;
|
||||
const lay::PluginDeclaration *mp_plugin_declaration;
|
||||
lay::Dispatcher *mp_dispatcher;
|
||||
lay::LayoutView *mp_view;
|
||||
|
||||
void on_active_cellview_changed ();
|
||||
void on_technology_changed ();
|
||||
void attach_events ();
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -530,16 +530,28 @@ LibrariesView::do_update_content (int lib_index)
|
|||
|
||||
size_t imin = (lib_index < 0 ? 0 : (size_t) lib_index);
|
||||
size_t imax = (lib_index < 0 ? std::numeric_limits <size_t>::max () : (size_t) lib_index);
|
||||
std::string tech_name;
|
||||
|
||||
// rebuild all events
|
||||
detach_from_all_events ();
|
||||
|
||||
mp_view->active_cellview_changed_event.add (this, &LibrariesView::update_required);
|
||||
lay::CellViewRef cv = mp_view->active_cellview_ref ();
|
||||
if (cv.is_valid ()) {
|
||||
cv->technology_changed_event.add (this, &LibrariesView::update_required);
|
||||
tech_name = cv->tech_name ();
|
||||
}
|
||||
|
||||
db::LibraryManager::instance ().changed_event.add (this, &LibrariesView::update_required);
|
||||
|
||||
std::vector<db::Library *> libraries;
|
||||
for (db::LibraryManager::iterator lib = db::LibraryManager::instance ().begin (); lib != db::LibraryManager::instance ().end (); ++lib) {
|
||||
libraries.push_back (db::LibraryManager::instance ().lib (lib->second));
|
||||
libraries.back ()->layout ().hier_changed_event.add (this, &LibrariesView::update_required);
|
||||
libraries.back ()->retired_state_changed_event.add (this, &LibrariesView::update_required);
|
||||
db::Library *lib_ptr = db::LibraryManager::instance ().lib (lib->second);
|
||||
if (! lib_ptr->for_technologies () || lib_ptr->is_for_technology (tech_name)) {
|
||||
libraries.push_back (lib_ptr);
|
||||
libraries.back ()->layout ().hier_changed_event.add (this, &LibrariesView::update_required);
|
||||
libraries.back ()->retired_state_changed_event.add (this, &LibrariesView::update_required);
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = imin; i < libraries.size () && i <= imax; ++i) {
|
||||
|
|
|
|||
|
|
@ -298,6 +298,7 @@ struct LayerSelectionComboBoxPrivateData
|
|||
const db::Layout *layout;
|
||||
lay::LayoutView *view;
|
||||
int cv_index;
|
||||
db::LayerProperties last_props;
|
||||
};
|
||||
|
||||
LayerSelectionComboBox::LayerSelectionComboBox (QWidget *parent)
|
||||
|
|
@ -424,6 +425,14 @@ LayerSelectionComboBox::set_view (lay::LayoutView *view, int cv_index, bool all_
|
|||
mp_private->cv_index = cv_index;
|
||||
mp_private->all_layers = all_layers;
|
||||
|
||||
view->layer_list_changed_event.add (this, &LayerSelectionComboBox::on_layer_list_changed);
|
||||
|
||||
update_layer_list ();
|
||||
}
|
||||
|
||||
void
|
||||
LayerSelectionComboBox::on_layer_list_changed (int)
|
||||
{
|
||||
update_layer_list ();
|
||||
}
|
||||
|
||||
|
|
@ -442,7 +451,7 @@ void
|
|||
LayerSelectionComboBox::update_layer_list ()
|
||||
{
|
||||
int i = currentIndex ();
|
||||
db::LayerProperties props;
|
||||
db::LayerProperties props = mp_private->last_props;
|
||||
if (i >= 0 && i < int (mp_private->layers.size ())) {
|
||||
props = mp_private->layers [i].first;
|
||||
}
|
||||
|
|
@ -522,6 +531,8 @@ LayerSelectionComboBox::update_layer_list ()
|
|||
void
|
||||
LayerSelectionComboBox::set_current_layer (const db::LayerProperties &props)
|
||||
{
|
||||
mp_private->last_props = props;
|
||||
|
||||
for (std::vector <std::pair <db::LayerProperties, int> >::iterator ll = mp_private->layers.begin (); ll != mp_private->layers.end (); ++ll) {
|
||||
if (ll->first.log_equal (props)) {
|
||||
setCurrentIndex (std::distance (mp_private->layers.begin (), ll));
|
||||
|
|
@ -562,7 +573,7 @@ LayerSelectionComboBox::current_layer_props () const
|
|||
{
|
||||
int i = currentIndex ();
|
||||
if (i < 0 || i > int (mp_private->layers.size ())) {
|
||||
return db::LayerProperties ();
|
||||
return mp_private->last_props;
|
||||
} else {
|
||||
return mp_private->layers [i].first;
|
||||
}
|
||||
|
|
@ -600,7 +611,7 @@ LibrarySelectionComboBox::update_list ()
|
|||
for (db::LibraryManager::iterator l = db::LibraryManager::instance ().begin (); l != db::LibraryManager::instance ().end (); ++l) {
|
||||
|
||||
db::Library *lib = db::LibraryManager::instance ().lib (l->second);
|
||||
if (! m_tech_set || !lib->for_technologies ()|| lib->is_for_technology (m_tech)) {
|
||||
if (! m_tech_set || !lib->for_technologies () || lib->is_for_technology (m_tech)) {
|
||||
|
||||
std::string item_text = lib->get_name ();
|
||||
if (! lib->get_description ().empty ()) {
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@
|
|||
|
||||
#include "laybasicCommon.h"
|
||||
|
||||
#include "tlObject.h"
|
||||
|
||||
#include <QPushButton>
|
||||
#include <QComboBox>
|
||||
#include <QLabel>
|
||||
|
|
@ -170,7 +172,7 @@ private:
|
|||
* This combo box allows selecting a (physical) layer from a layout
|
||||
*/
|
||||
class LAYBASIC_PUBLIC LayerSelectionComboBox
|
||||
: public QComboBox
|
||||
: public QComboBox, public tl::Object
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
|
@ -249,6 +251,7 @@ protected slots:
|
|||
private:
|
||||
LayerSelectionComboBoxPrivateData *mp_private;
|
||||
|
||||
void on_layer_list_changed (int);
|
||||
void update_layer_list ();
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -43,11 +43,7 @@ std::string correct_path (const std::string &fn, const db::Layout &layout, const
|
|||
|
||||
// if a technology is given and the file can be found in the technology's base path, take it
|
||||
// from there.
|
||||
std::string tn = layout.meta_info_value ("technology");
|
||||
const db::Technology *tech = 0;
|
||||
if (! tn.empty ()) {
|
||||
tech = db::Technologies::instance ()->technology_by_name (tn);
|
||||
}
|
||||
const db::Technology *tech = layout.technology ();
|
||||
|
||||
if (tech && ! tech->base_path ().empty ()) {
|
||||
std::string new_fn = tl::combine_path (tech->base_path (), fn);
|
||||
|
|
|
|||
|
|
@ -74,11 +74,7 @@ MAGReader::read (db::Layout &layout, const db::LoadLayoutOptions &options)
|
|||
{
|
||||
prepare_layers ();
|
||||
|
||||
mp_klayout_tech = 0;
|
||||
std::string klayout_tech_name = layout.meta_info_value ("technology");
|
||||
if (! klayout_tech_name.empty () && db::Technologies::instance ()->has_technology (klayout_tech_name)) {
|
||||
mp_klayout_tech = db::Technologies::instance ()->technology_by_name (klayout_tech_name);
|
||||
}
|
||||
mp_klayout_tech = layout.technology ();
|
||||
|
||||
const db::MAGReaderOptions &specific_options = options.get_options<db::MAGReaderOptions> ();
|
||||
m_lambda = specific_options.lambda;
|
||||
|
|
|
|||
|
|
@ -145,7 +145,7 @@ private:
|
|||
std::map<std::string, std::string> m_use_lib_paths;
|
||||
db::VCplxTrans m_dbu_trans_inv;
|
||||
std::string m_tech;
|
||||
db::Technology *mp_klayout_tech;
|
||||
const db::Technology *mp_klayout_tech;
|
||||
|
||||
void do_read (db::Layout &layout, db::cell_index_type to_cell, tl::TextInputStream &stream);
|
||||
void do_read_part (db::Layout &layout, db::cell_index_type cell_index, tl::TextInputStream &stream);
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ MAGWriter::write_dummmy_top (const std::set<db::cell_index_type> &cell_set, cons
|
|||
|
||||
std::string tech = m_options.tech;
|
||||
if (tech.empty ()) {
|
||||
tech = layout.meta_info_value ("technology");
|
||||
tech = layout.technology_name ();
|
||||
}
|
||||
if (! tech.empty ()) {
|
||||
os << "tech " << make_string (tl::to_lower_case (tech)) << "\n";
|
||||
|
|
@ -177,7 +177,7 @@ MAGWriter::do_write_cell (db::cell_index_type ci, const std::vector <std::pair <
|
|||
|
||||
std::string tech = m_options.tech;
|
||||
if (tech.empty ()) {
|
||||
tech = layout.meta_info_value ("technology");
|
||||
tech = layout.technology_name ();
|
||||
}
|
||||
if (! tech.empty ()) {
|
||||
os << "tech " << make_string (tl::to_lower_case (tech)) << "\n";
|
||||
|
|
|
|||
Loading…
Reference in New Issue