mirror of https://github.com/KLayout/klayout.git
Merge branch 'master' into complex_drc_ops
This commit is contained in:
commit
45a8f7aa20
|
|
@ -24,6 +24,8 @@
|
||||||
#include "dbLoadLayoutOptions.h"
|
#include "dbLoadLayoutOptions.h"
|
||||||
#include "tlCommandLineParser.h"
|
#include "tlCommandLineParser.h"
|
||||||
|
|
||||||
|
#include "tlStream.h"
|
||||||
|
|
||||||
namespace bd
|
namespace bd
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
@ -153,13 +155,44 @@ GenericReaderOptions::add_options (tl::CommandLineOptions &cmd)
|
||||||
"layer is specified, all source layers addressed with the source specification are "
|
"layer is specified, all source layers addressed with the source specification are "
|
||||||
"combined into this target layer.\n"
|
"combined into this target layer.\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
"For clarity, source and target specifications can be enclosed in round or square brackets. "
|
||||||
|
"With square brackets, the default target is '*/*' which results in the expansion of a source "
|
||||||
|
"layer range.\n"
|
||||||
|
"\n"
|
||||||
|
"To clone layers, add a mapping statement beginning with a '+' character. While other mapping statements "
|
||||||
|
"redefine mappings established before, mapping statement starting with '+' will clone the layer (1:m mapping).\n"
|
||||||
|
"\n"
|
||||||
|
"You can cancel mappings established before by using an 'unmap' statement. Such a statement "
|
||||||
|
"begins with a '-' and lists the layers whose mapping is to be removed. This is useful for creating "
|
||||||
|
"'mapping holes' in sequences.\n"
|
||||||
|
"\n"
|
||||||
|
"If brackets are used, '+' (multi-mapping) and '-' (unmapping) needs to go before the brackets.\n"
|
||||||
|
"\n"
|
||||||
"Examples:\n"
|
"Examples:\n"
|
||||||
"\n"
|
"\n"
|
||||||
"* 1/0 2/0 3/0-255:17/0\n"
|
"* 1/0 2/0 3/0-255:17/0\n"
|
||||||
" Selects 1/0, 2/0 and maps layer 3, datatype 0 to 255 to layer 17, datatype 0\n"
|
" Selects 1/0, 2/0 and maps layer 3, datatype 0 to 255 to layer 17, datatype 0.\n"
|
||||||
|
" If clarity, the mapping can also be written with brackets like this: '(1/0) (2/0) (3/0-255:17/0)'.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"* A:1/0 B:2/0\n"
|
"* A:1/0 B:2/0\n"
|
||||||
" Maps named layer A to 1/0 and named layer B to 2/0"
|
" Maps named layer A to 1/0 and named layer B to 2/0.\n"
|
||||||
|
" If clarity, the mapping can also be written with brackets like this: '(A:1/0) (B:2/0)'.\n"
|
||||||
|
"\n"
|
||||||
|
"* [*/*] +(10/*:1000)/*\n"
|
||||||
|
" Includes all layers, but in addition copies all datatypes of layer 10 to 1000 while keeping the datatype.\n"
|
||||||
|
" Note the square bracket which implies range expansion and how the brackets give a visual aid for the "
|
||||||
|
" grouping of the mapping parts.\n"
|
||||||
|
"\n"
|
||||||
|
"* [*/*] -(10/*)\n"
|
||||||
|
" Includes all layers, but drops all datatypes from layer 10 through 'unmapping'.\n"
|
||||||
|
" Please note, that this specification requires -" + m_prefix + "s (skip unknown layers) because otherwise the "
|
||||||
|
" unmapped layers are still created through the unknown layer fallback path.\n"
|
||||||
|
)
|
||||||
|
<< tl::arg (group +
|
||||||
|
"--" + m_long_prefix + "layer-map-file=map", this, &GenericReaderOptions::set_layer_map_file, "Specifies the layer mapping for the input as a file",
|
||||||
|
"This option specifies the layer selection or mapping like -" + m_prefix + "m, but takes the mapping from the given file. "
|
||||||
|
"Each line in this file is read as one layer mapping expression. "
|
||||||
|
"Empty lines or lines starting with a hash (#) character or with double slashes (//) are ignored."
|
||||||
)
|
)
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
@ -604,12 +637,19 @@ void GenericReaderOptions::set_layer_map (const std::string &lm)
|
||||||
|
|
||||||
int l = 0;
|
int l = 0;
|
||||||
while (! ex.at_end ()) {
|
while (! ex.at_end ()) {
|
||||||
m_layer_map.map_expr (ex, l);
|
m_layer_map.add_expr (ex, l);
|
||||||
ex.test ("//");
|
ex.test ("//");
|
||||||
++l;
|
++l;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GenericReaderOptions::set_layer_map_file (const std::string &lm)
|
||||||
|
{
|
||||||
|
tl::InputStream file (lm);
|
||||||
|
tl::TextInputStream text (file);
|
||||||
|
m_layer_map = db::LayerMap::from_string_file_format (text.read_all ());
|
||||||
|
}
|
||||||
|
|
||||||
void GenericReaderOptions::set_read_named_layers (bool f)
|
void GenericReaderOptions::set_read_named_layers (bool f)
|
||||||
{
|
{
|
||||||
m_keep_layer_names = f;
|
m_keep_layer_names = f;
|
||||||
|
|
|
||||||
|
|
@ -134,6 +134,7 @@ private:
|
||||||
std::vector<std::string> m_magic_lib_path;
|
std::vector<std::string> m_magic_lib_path;
|
||||||
|
|
||||||
void set_layer_map (const std::string &lm);
|
void set_layer_map (const std::string &lm);
|
||||||
|
void set_layer_map_file (const std::string &lm);
|
||||||
void set_dbu (double dbu);
|
void set_dbu (double dbu);
|
||||||
void set_read_named_layers (bool f);
|
void set_read_named_layers (bool f);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ SOURCES = \
|
||||||
dbClipboard.cc \
|
dbClipboard.cc \
|
||||||
dbClipboardData.cc \
|
dbClipboardData.cc \
|
||||||
dbClip.cc \
|
dbClip.cc \
|
||||||
|
dbColdProxy.cc \
|
||||||
dbCommonReader.cc \
|
dbCommonReader.cc \
|
||||||
dbCompoundOperation.cc \
|
dbCompoundOperation.cc \
|
||||||
dbEdge.cc \
|
dbEdge.cc \
|
||||||
|
|
@ -219,6 +220,7 @@ HEADERS = \
|
||||||
dbClipboardData.h \
|
dbClipboardData.h \
|
||||||
dbClipboard.h \
|
dbClipboard.h \
|
||||||
dbClip.h \
|
dbClip.h \
|
||||||
|
dbColdProxy.h \
|
||||||
dbCommonReader.h \
|
dbCommonReader.h \
|
||||||
dbCompoundOperation.h \
|
dbCompoundOperation.h \
|
||||||
dbEdge.h \
|
dbEdge.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
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -35,7 +35,7 @@ namespace db
|
||||||
static const size_t null_id = std::numeric_limits<size_t>::max ();
|
static const size_t null_id = std::numeric_limits<size_t>::max ();
|
||||||
|
|
||||||
CommonReader::CommonReader ()
|
CommonReader::CommonReader ()
|
||||||
: m_cc_resolution (AddToCell)
|
: m_cc_resolution (AddToCell), m_create_layers (false)
|
||||||
{
|
{
|
||||||
// .. nothing yet ..
|
// .. nothing yet ..
|
||||||
}
|
}
|
||||||
|
|
@ -275,6 +275,46 @@ CommonReader::merge_cell_without_instances (db::Layout &layout, db::cell_index_t
|
||||||
layout.delete_cell (src_cell.cell_index ());
|
layout.delete_cell (src_cell.cell_index ());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const db::LayerMap &
|
||||||
|
CommonReader::read (db::Layout &layout, const db::LoadLayoutOptions &options)
|
||||||
|
{
|
||||||
|
init (options);
|
||||||
|
|
||||||
|
m_common_options.layer_map.prepare (layout);
|
||||||
|
|
||||||
|
layout.start_changes ();
|
||||||
|
try {
|
||||||
|
do_read (layout);
|
||||||
|
finish (layout);
|
||||||
|
layout.end_changes ();
|
||||||
|
} catch (...) {
|
||||||
|
layout.end_changes ();
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_layer_map_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
const db::LayerMap &
|
||||||
|
CommonReader::read (db::Layout &layout)
|
||||||
|
{
|
||||||
|
return read (layout, db::LoadLayoutOptions ());
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CommonReader::init (const LoadLayoutOptions &options)
|
||||||
|
{
|
||||||
|
m_common_options = options.get_options<db::CommonReaderOptions> ();
|
||||||
|
m_cc_resolution = m_common_options.cell_conflict_resolution;
|
||||||
|
m_create_layers = m_common_options.create_other_layers;
|
||||||
|
|
||||||
|
m_layer_map_out.clear ();
|
||||||
|
m_multi_mapping_placeholders.clear ();
|
||||||
|
m_layer_cache.clear ();
|
||||||
|
m_layers_created.clear ();
|
||||||
|
m_layer_names.clear ();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CommonReader::finish (db::Layout &layout)
|
CommonReader::finish (db::Layout &layout)
|
||||||
{
|
{
|
||||||
|
|
@ -382,6 +422,120 @@ CommonReader::finish (db::Layout &layout)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// resolve layer multi-mapping
|
||||||
|
|
||||||
|
for (std::map<std::set<unsigned int>, unsigned int>::const_iterator i = m_multi_mapping_placeholders.begin (); i != m_multi_mapping_placeholders.end (); ++i) {
|
||||||
|
|
||||||
|
if (i->first.size () > 1) {
|
||||||
|
|
||||||
|
bool discard_layer = i->first.find (i->second) == i->first.end ();
|
||||||
|
|
||||||
|
for (std::set<unsigned int>::const_iterator l = i->first.begin (); l != i->first.end (); ++l) {
|
||||||
|
|
||||||
|
// last one? this one will get a "move"
|
||||||
|
std::set<unsigned int>::const_iterator ll = l;
|
||||||
|
if (discard_layer && ++ll == i->first.end ()) {
|
||||||
|
layout.move_layer (i->second, *l);
|
||||||
|
layout.delete_layer (i->second);
|
||||||
|
} else {
|
||||||
|
layout.copy_layer (i->second, *l);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// rename layers created before if required
|
||||||
|
|
||||||
|
for (std::set<unsigned int>::const_iterator i = m_layers_created.begin (); i != m_layers_created.end (); ++i) {
|
||||||
|
|
||||||
|
const db::LayerProperties &lp = layout.get_properties (*i);
|
||||||
|
|
||||||
|
const tl::interval_map <db::ld_type, std::string> *dtmap = layer_names ().mapped (lp.layer);
|
||||||
|
const std::string *name = 0;
|
||||||
|
if (dtmap) {
|
||||||
|
name = dtmap->mapped (lp.datatype);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name) {
|
||||||
|
// need to rename: add a new madding to m_layer_map_out and adjust the layout's layer properties
|
||||||
|
db::LayerProperties lpp = lp;
|
||||||
|
join_layer_names (lpp.name, *name);
|
||||||
|
layout.set_properties (*i, lpp);
|
||||||
|
m_layer_map_out.map (LDPair (lp.layer, lp.datatype), *i, lpp);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair <bool, unsigned int>
|
||||||
|
CommonReader::open_dl (db::Layout &layout, const LDPair &dl)
|
||||||
|
{
|
||||||
|
std::map<db::LDPair, std::pair <bool, unsigned int> >::const_iterator lc = m_layer_cache.find (dl);
|
||||||
|
if (lc != m_layer_cache.end ()) {
|
||||||
|
return lc->second;
|
||||||
|
} else {
|
||||||
|
std::pair <bool, unsigned int> res = open_dl_uncached (layout, dl);
|
||||||
|
m_layer_cache.insert (std::make_pair (dl, res));
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair <bool, unsigned int>
|
||||||
|
CommonReader::open_dl_uncached (db::Layout &layout, const LDPair &dl)
|
||||||
|
{
|
||||||
|
const std::set<unsigned int> &li = common_options ().layer_map.logical (dl, layout);
|
||||||
|
if (li.empty ()) {
|
||||||
|
|
||||||
|
if (! m_create_layers) {
|
||||||
|
return std::make_pair (false, (unsigned int) 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// and create the layer
|
||||||
|
db::LayerProperties lp;
|
||||||
|
lp.layer = dl.layer;
|
||||||
|
lp.datatype = dl.datatype;
|
||||||
|
|
||||||
|
// resolve OASIS name if possible
|
||||||
|
const tl::interval_map <db::ld_type, std::string> *names_dmap = m_layer_names.mapped (dl.layer);
|
||||||
|
if (names_dmap != 0) {
|
||||||
|
const std::string *name = names_dmap->mapped (dl.datatype);
|
||||||
|
if (name != 0) {
|
||||||
|
lp.name = *name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int nl = layout.insert_layer (lp);
|
||||||
|
m_layer_map_out.map (dl, nl, lp);
|
||||||
|
|
||||||
|
m_layers_created.insert (nl);
|
||||||
|
|
||||||
|
return std::make_pair (true, nl);
|
||||||
|
|
||||||
|
} else if (li.size () == 1) {
|
||||||
|
|
||||||
|
m_layer_map_out.map (dl, *li.begin (), layout.get_properties (*li.begin ()));
|
||||||
|
|
||||||
|
return std::make_pair (true, *li.begin ());
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
for (std::set<unsigned int>::const_iterator i = li.begin (); i != li.end (); ++i) {
|
||||||
|
m_layer_map_out.mmap (dl, *i, layout.get_properties (*i));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::map<std::set<unsigned int>, unsigned int>::iterator mmp = m_multi_mapping_placeholders.find (li);
|
||||||
|
if (mmp == m_multi_mapping_placeholders.end ()) {
|
||||||
|
// create a placeholder layer
|
||||||
|
mmp = m_multi_mapping_placeholders.insert (std::make_pair (li, layout.insert_layer ())).first;
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::make_pair (true, mmp->second);
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------
|
// ---------------------------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,104 @@
|
||||||
namespace db
|
namespace db
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The CellConflictResolution enum
|
||||||
|
*/
|
||||||
|
enum CellConflictResolution
|
||||||
|
{
|
||||||
|
AddToCell = 0,
|
||||||
|
OverwriteCell = 1,
|
||||||
|
SkipNewCell = 2,
|
||||||
|
RenameCell = 3
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Structure that holds the GDS2 and OASIS specific options for the reader
|
||||||
|
*/
|
||||||
|
class DB_PUBLIC CommonReaderOptions
|
||||||
|
: public FormatSpecificReaderOptions
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief The constructor
|
||||||
|
*/
|
||||||
|
CommonReaderOptions ()
|
||||||
|
: create_other_layers (true),
|
||||||
|
enable_text_objects (true),
|
||||||
|
enable_properties (true),
|
||||||
|
cell_conflict_resolution (CellConflictResolution::AddToCell)
|
||||||
|
{
|
||||||
|
// .. nothing yet ..
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Specifies a layer mapping
|
||||||
|
*
|
||||||
|
* If a layer mapping is specified, only the given layers are read.
|
||||||
|
* Otherwise, all layers are read.
|
||||||
|
* Setting "create_other_layers" to true will make the reader
|
||||||
|
* create other layers for all layers not given in the layer map.
|
||||||
|
* Setting an empty layer map and create_other_layers to true effectively
|
||||||
|
* enables all layers for reading.
|
||||||
|
*/
|
||||||
|
db::LayerMap layer_map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A flag indicating that a new layers shall be created
|
||||||
|
*
|
||||||
|
* If this flag is set to true, layers not listed in the layer map a created
|
||||||
|
* too.
|
||||||
|
*/
|
||||||
|
bool create_other_layers;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A flag indicating whether to read text objects
|
||||||
|
*
|
||||||
|
* If this flag is set to true, text objects are read. Otherwise they are ignored.
|
||||||
|
*/
|
||||||
|
bool enable_text_objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A flag indicating whether to read user properties
|
||||||
|
*
|
||||||
|
* If this flag is set to true, user properties are read. Otherwise they are ignored.
|
||||||
|
*/
|
||||||
|
bool enable_properties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Specifies the cell merge behavior
|
||||||
|
*
|
||||||
|
* This enum controls how cells are read if a cell with the requested name already
|
||||||
|
* exists.
|
||||||
|
*
|
||||||
|
* AddToCell In this mode, instances or shapes are added to any existing cell
|
||||||
|
* OverwriteCell Overwrite existing cell. If the existing cell has children, those are removed unless used otherwise
|
||||||
|
* SkipNewCell Ignore the new cell and it's children
|
||||||
|
* RenameCell Rename the new cell
|
||||||
|
*
|
||||||
|
* If the existing opr the new cell is a ghost cell, AddToCell is applied always. In other words,
|
||||||
|
* ghost cells are always merged.
|
||||||
|
*/
|
||||||
|
CellConflictResolution cell_conflict_resolution;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Implementation of FormatSpecificReaderOptions
|
||||||
|
*/
|
||||||
|
virtual FormatSpecificReaderOptions *clone () const
|
||||||
|
{
|
||||||
|
return new CommonReaderOptions (*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Implementation of FormatSpecificReaderOptions
|
||||||
|
*/
|
||||||
|
virtual const std::string &format_name () const
|
||||||
|
{
|
||||||
|
static const std::string n ("Common");
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief A common reader base for GDS2 and OASIS providing common services for both readers
|
* @brief A common reader base for GDS2 and OASIS providing common services for both readers
|
||||||
*/
|
*/
|
||||||
|
|
@ -38,38 +136,13 @@ class DB_PUBLIC CommonReader
|
||||||
: public ReaderBase
|
: public ReaderBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/**
|
typedef tl::interval_map <db::ld_type, tl::interval_map <db::ld_type, std::string> > layer_name_map;
|
||||||
* @brief The CellConflictResolution enum
|
|
||||||
*/
|
|
||||||
enum CellConflictResolution
|
|
||||||
{
|
|
||||||
AddToCell = 0,
|
|
||||||
OverwriteCell = 1,
|
|
||||||
SkipNewCell = 2,
|
|
||||||
RenameCell = 3
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Constructor
|
* @brief Constructor
|
||||||
*/
|
*/
|
||||||
CommonReader ();
|
CommonReader ();
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Sets the cell name conflict resolution mode
|
|
||||||
*/
|
|
||||||
void set_cell_conflict_resolution (CellConflictResolution cc_resolution)
|
|
||||||
{
|
|
||||||
m_cc_resolution = cc_resolution;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Sets the cell name conflict resolution mode
|
|
||||||
*/
|
|
||||||
CellConflictResolution cell_conflict_resolution () const
|
|
||||||
{
|
|
||||||
return m_cc_resolution;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Make a cell from a name
|
* @brief Make a cell from a name
|
||||||
*/
|
*/
|
||||||
|
|
@ -132,9 +205,17 @@ public:
|
||||||
*/
|
*/
|
||||||
void finish (db::Layout &layout);
|
void finish (db::Layout &layout);
|
||||||
|
|
||||||
|
// Reimplementation of the ReaderBase interace
|
||||||
|
virtual const db::LayerMap &read (db::Layout &layout, const db::LoadLayoutOptions &options);
|
||||||
|
virtual const db::LayerMap &read (db::Layout &layout);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
friend class CommonReaderLayerMapping;
|
||||||
|
|
||||||
virtual void common_reader_error (const std::string &msg) = 0;
|
virtual void common_reader_error (const std::string &msg) = 0;
|
||||||
virtual void common_reader_warn (const std::string &msg) = 0;
|
virtual void common_reader_warn (const std::string &msg) = 0;
|
||||||
|
virtual void do_read (db::Layout &layout) = 0;
|
||||||
|
virtual void init (const LoadLayoutOptions &options);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Merge (and delete) the src_cell into target_cell
|
* @brief Merge (and delete) the src_cell into target_cell
|
||||||
|
|
@ -146,98 +227,69 @@ protected:
|
||||||
*/
|
*/
|
||||||
void merge_cell_without_instances (db::Layout &layout, db::cell_index_type target_cell_index, db::cell_index_type src_cell_index) const;
|
void merge_cell_without_instances (db::Layout &layout, db::cell_index_type target_cell_index, db::cell_index_type src_cell_index) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the common options
|
||||||
|
*/
|
||||||
|
db::CommonReaderOptions &common_options ()
|
||||||
|
{
|
||||||
|
return m_common_options;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the layer name map
|
||||||
|
*/
|
||||||
|
layer_name_map &layer_names ()
|
||||||
|
{
|
||||||
|
return m_layer_names;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enters the a layer with a given layer/datatype
|
||||||
|
*/
|
||||||
|
std::pair <bool, unsigned int> open_dl (db::Layout &layout, const LDPair &dl);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::map<size_t, std::pair<std::string, db::cell_index_type> > m_id_map;
|
std::map<size_t, std::pair<std::string, db::cell_index_type> > m_id_map;
|
||||||
std::map<std::string, std::pair<size_t, db::cell_index_type> > m_name_map;
|
std::map<std::string, std::pair<size_t, db::cell_index_type> > m_name_map;
|
||||||
std::map<size_t, std::string> m_name_for_id;
|
std::map<size_t, std::string> m_name_for_id;
|
||||||
CellConflictResolution m_cc_resolution;
|
CellConflictResolution m_cc_resolution;
|
||||||
|
bool m_create_layers;
|
||||||
|
db::CommonReaderOptions m_common_options;
|
||||||
|
db::LayerMap m_layer_map_out;
|
||||||
|
tl::interval_map <db::ld_type, tl::interval_map <db::ld_type, std::string> > m_layer_names;
|
||||||
|
std::map<db::LDPair, std::pair <bool, unsigned int> > m_layer_cache;
|
||||||
|
std::map<std::set<unsigned int>, unsigned int> m_multi_mapping_placeholders;
|
||||||
|
std::set<unsigned int> m_layers_created;
|
||||||
|
|
||||||
|
std::pair <bool, unsigned int> open_dl_uncached (db::Layout &layout, const LDPair &dl);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Structure that holds the GDS2 and OASIS specific options for the reader
|
* @brief A utility class that maps the layers for the proxy cell recovery
|
||||||
*/
|
*/
|
||||||
class DB_PUBLIC CommonReaderOptions
|
class CommonReaderLayerMapping
|
||||||
: public FormatSpecificReaderOptions
|
: public db::ImportLayerMapping
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/**
|
CommonReaderLayerMapping (db::CommonReader *reader, db::Layout *layout)
|
||||||
* @brief The constructor
|
: mp_reader (reader), mp_layout (layout)
|
||||||
*/
|
|
||||||
CommonReaderOptions ()
|
|
||||||
: create_other_layers (true),
|
|
||||||
enable_text_objects (true),
|
|
||||||
enable_properties (true),
|
|
||||||
cell_conflict_resolution (CommonReader::AddToCell)
|
|
||||||
{
|
{
|
||||||
// .. nothing yet ..
|
// .. nothing yet ..
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
std::pair<bool, unsigned int> map_layer (const db::LayerProperties &lprops)
|
||||||
* @brief Specifies a layer mapping
|
|
||||||
*
|
|
||||||
* If a layer mapping is specified, only the given layers are read.
|
|
||||||
* Otherwise, all layers are read.
|
|
||||||
* Setting "create_other_layers" to true will make the reader
|
|
||||||
* create other layers for all layers not given in the layer map.
|
|
||||||
* Setting an empty layer map and create_other_layers to true effectively
|
|
||||||
* enables all layers for reading.
|
|
||||||
*/
|
|
||||||
db::LayerMap layer_map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief A flag indicating that a new layers shall be created
|
|
||||||
*
|
|
||||||
* If this flag is set to true, layers not listed in the layer map a created
|
|
||||||
* too.
|
|
||||||
*/
|
|
||||||
bool create_other_layers;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief A flag indicating whether to read text objects
|
|
||||||
*
|
|
||||||
* If this flag is set to true, text objects are read. Otherwise they are ignored.
|
|
||||||
*/
|
|
||||||
bool enable_text_objects;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief A flag indicating whether to read user properties
|
|
||||||
*
|
|
||||||
* If this flag is set to true, user properties are read. Otherwise they are ignored.
|
|
||||||
*/
|
|
||||||
bool enable_properties;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Specifies the cell merge behavior
|
|
||||||
*
|
|
||||||
* This enum controls how cells are read if a cell with the requested name already
|
|
||||||
* exists.
|
|
||||||
*
|
|
||||||
* AddToCell In this mode, instances or shapes are added to any existing cell
|
|
||||||
* OverwriteCell Overwrite existing cell. If the existing cell has children, those are removed unless used otherwise
|
|
||||||
* SkipNewCell Ignore the new cell and it's children
|
|
||||||
* RenameCell Rename the new cell
|
|
||||||
*
|
|
||||||
* If the existing opr the new cell is a ghost cell, AddToCell is applied always. In other words,
|
|
||||||
* ghost cells are always merged.
|
|
||||||
*/
|
|
||||||
CommonReader::CellConflictResolution cell_conflict_resolution;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Implementation of FormatSpecificReaderOptions
|
|
||||||
*/
|
|
||||||
virtual FormatSpecificReaderOptions *clone () const
|
|
||||||
{
|
{
|
||||||
return new CommonReaderOptions (*this);
|
// named layers that are imported from a library are ignored
|
||||||
|
if (lprops.is_named ()) {
|
||||||
|
return std::make_pair (false, 0);
|
||||||
|
} else {
|
||||||
|
return mp_reader->open_dl (*mp_layout, LDPair (lprops.layer, lprops.datatype));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private:
|
||||||
* @brief Implementation of FormatSpecificReaderOptions
|
db::CommonReader *mp_reader;
|
||||||
*/
|
db::Layout *mp_layout;
|
||||||
virtual const std::string &format_name () const
|
|
||||||
{
|
|
||||||
static const std::string n ("Common");
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -174,9 +174,9 @@ TextGenerator::load_from_data (const char *data, size_t ndata, const std::string
|
||||||
m_description = description;
|
m_description = description;
|
||||||
m_name = name;
|
m_name = name;
|
||||||
|
|
||||||
std::pair<bool, unsigned int> l1 = map.logical (db::LDPair (1, 0));
|
std::pair<bool, unsigned int> l1 = map.first_logical (db::LDPair (1, 0));
|
||||||
std::pair<bool, unsigned int> l2 = map.logical (db::LDPair (2, 0));
|
std::pair<bool, unsigned int> l2 = map.first_logical (db::LDPair (2, 0));
|
||||||
std::pair<bool, unsigned int> l3 = map.logical (db::LDPair (3, 0));
|
std::pair<bool, unsigned int> l3 = map.first_logical (db::LDPair (3, 0));
|
||||||
|
|
||||||
if (l1.first && l2.first) {
|
if (l1.first && l2.first) {
|
||||||
read_from_layout (layout, l1.second, l2.second, l3.second);
|
read_from_layout (layout, l1.second, l2.second, l3.second);
|
||||||
|
|
@ -193,9 +193,9 @@ TextGenerator::load_from_file (const std::string &filename)
|
||||||
|
|
||||||
m_description = filename;
|
m_description = filename;
|
||||||
|
|
||||||
std::pair<bool, unsigned int> l1 = map.logical (db::LDPair (1, 0));
|
std::pair<bool, unsigned int> l1 = map.first_logical (db::LDPair (1, 0));
|
||||||
std::pair<bool, unsigned int> l2 = map.logical (db::LDPair (2, 0));
|
std::pair<bool, unsigned int> l2 = map.first_logical (db::LDPair (2, 0));
|
||||||
std::pair<bool, unsigned int> l3 = map.logical (db::LDPair (3, 0));
|
std::pair<bool, unsigned int> l3 = map.first_logical (db::LDPair (3, 0));
|
||||||
|
|
||||||
if (l1.first && l2.first) {
|
if (l1.first && l2.first) {
|
||||||
read_from_layout (layout, l1.second, l2.second, l3.second);
|
read_from_layout (layout, l1.second, l2.second, l3.second);
|
||||||
|
|
|
||||||
|
|
@ -24,11 +24,13 @@
|
||||||
#include "dbLayout.h"
|
#include "dbLayout.h"
|
||||||
#include "dbMemStatistics.h"
|
#include "dbMemStatistics.h"
|
||||||
#include "dbTrans.h"
|
#include "dbTrans.h"
|
||||||
|
#include "dbTechnology.h"
|
||||||
#include "dbShapeRepository.h"
|
#include "dbShapeRepository.h"
|
||||||
#include "dbPCellHeader.h"
|
#include "dbPCellHeader.h"
|
||||||
#include "dbPCellVariant.h"
|
#include "dbPCellVariant.h"
|
||||||
#include "dbPCellDeclaration.h"
|
#include "dbPCellDeclaration.h"
|
||||||
#include "dbLibraryProxy.h"
|
#include "dbLibraryProxy.h"
|
||||||
|
#include "dbColdProxy.h"
|
||||||
#include "dbLibraryManager.h"
|
#include "dbLibraryManager.h"
|
||||||
#include "dbLibrary.h"
|
#include "dbLibrary.h"
|
||||||
#include "dbRegion.h"
|
#include "dbRegion.h"
|
||||||
|
|
@ -84,6 +86,27 @@ private:
|
||||||
db::properties_id_type m_from, m_to;
|
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
|
struct SetLayoutDBU
|
||||||
: public LayoutOp
|
: 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));
|
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
|
// Implementation of the Layout class
|
||||||
|
|
||||||
|
|
@ -442,6 +524,187 @@ Layout::operator= (const Layout &d)
|
||||||
return *this;
|
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
|
void
|
||||||
Layout::mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, bool no_self, void *parent) const
|
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
|
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);
|
pcell_header_type *header = pcell_header (pcell_id);
|
||||||
tl_assert (header != 0);
|
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
|
// this variant must not exist yet for "get as" semantics
|
||||||
tl_assert (header->get_variant (*this, parameters) == 0);
|
tl_assert (header->get_variant (*this, parameters) == 0);
|
||||||
|
|
||||||
tl_assert (! (manager () && manager ()->transacting ()));
|
|
||||||
tl_assert (m_cell_ptrs [target_cell_index] != 0);
|
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);
|
pcell_variant_type *variant = new pcell_variant_type (target_cell_index, *this, pcell_id, parameters);
|
||||||
m_cells.push_back_ptr (variant);
|
replace_cell (target_cell_index, variant, retain_layout);
|
||||||
m_cell_ptrs [target_cell_index] = variant;
|
|
||||||
|
|
||||||
// produce the layout
|
if (! retain_layout) {
|
||||||
variant->update (layer_mapping);
|
// produce the layout unless we retained it
|
||||||
|
variant->update (layer_mapping);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cell_index_type
|
cell_index_type
|
||||||
|
|
@ -2168,10 +2456,29 @@ Layout::get_pcell_variant_cell (cell_index_type cell_index, const std::vector<tl
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Layout::get_context_info (cell_index_type cell_index, std::vector <std::string> &context_info) const
|
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::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::Layout *ly = this;
|
||||||
|
|
||||||
const db::LibraryProxy *lib_proxy;
|
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
|
// one level of library indirection
|
||||||
ly = &lib->layout ();
|
ly = &lib->layout ();
|
||||||
cptr = &ly->cell (lib_proxy->library_cell_index ());
|
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 ();
|
const std::vector<db::PCellParameterDeclaration> &pcp = pcell_decl->parameter_declarations ();
|
||||||
std::vector<db::PCellParameterDeclaration>::const_iterator pd = pcp.begin ();
|
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) {
|
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 ());
|
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 {
|
} 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;
|
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
|
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)
|
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;
|
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 ();
|
db::Cell *lib_cell = 0;
|
||||||
Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (lib_name);
|
|
||||||
if (! lib) {
|
Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (info.lib_name, m_tech_name);
|
||||||
return false;
|
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) {
|
if (lib_cell) {
|
||||||
get_lib_proxy_as (lib, lib_cell->cell_index (), cell_index, layer_mapping);
|
get_lib_proxy_as (lib, lib_cell->cell_index (), cell_index, layer_mapping);
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -2237,38 +2565,28 @@ Layout::recover_proxy_as (cell_index_type cell_index, std::vector <std::string>:
|
||||||
|
|
||||||
} else {
|
} 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::pair<bool, pcell_id_type> pc = pcell_by_name (info.pcell_name.c_str ());
|
||||||
|
|
||||||
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 ());
|
|
||||||
if (pc.first) {
|
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;
|
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);
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2279,55 +2597,54 @@ Layout::recover_proxy (std::vector <std::string>::const_iterator from, std::vect
|
||||||
return 0;
|
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 (info.lib_name, m_tech_name);
|
||||||
Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (lib_name);
|
|
||||||
if (! lib) {
|
db::Cell *lib_cell = 0;
|
||||||
return 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) {
|
if (lib_cell) {
|
||||||
cell_index_type cell_index = get_lib_proxy (lib, lib_cell->cell_index ());
|
return m_cell_ptrs [get_lib_proxy (lib, lib_cell->cell_index ())];
|
||||||
return &cell (cell_index);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
std::map<std::string, tl::Variant> parameters;
|
db::Cell *proxy = recover_proxy_no_lib (info);
|
||||||
|
if (proxy) {
|
||||||
while (from != to && (ex = tl::Extractor (from->c_str ())).test ("P(")) {
|
return proxy;
|
||||||
|
|
||||||
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 ());
|
return m_cell_ptrs [create_cold_proxy (info)];
|
||||||
if (pc.first) {
|
}
|
||||||
cell_index_type cell_index = get_pcell_variant (pc.second, pcell_declaration (pc.second)->map_parameters (parameters));
|
|
||||||
return &cell (cell_index);
|
|
||||||
}
|
|
||||||
|
|
||||||
} 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 ());
|
std::pair<bool, pcell_id_type> pc = pcell_by_name (info.pcell_name.c_str ());
|
||||||
if (cc.first) {
|
if (pc.first) {
|
||||||
return &cell (cc.second);
|
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
|
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);
|
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);
|
LibraryProxy *proxy = new LibraryProxy (target_cell_index, *this, lib->get_id (), cell_index);
|
||||||
m_cells.push_back_ptr (proxy);
|
replace_cell (target_cell_index, proxy, retain_layout);
|
||||||
m_cell_ptrs [target_cell_index] = proxy;
|
|
||||||
|
|
||||||
// produce the layout
|
if (! retain_layout) {
|
||||||
proxy->update (layer_mapping);
|
// produce the layout unless we retained it
|
||||||
|
proxy->update (layer_mapping);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cell_index_type
|
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));
|
manager ()->queue (this, new NewRemoveCellOp (new_index, m_cell_names [new_index], false /*new*/, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
// produce the layout
|
// produce the layout
|
||||||
proxy->update ();
|
proxy->update ();
|
||||||
|
|
||||||
return new_index;
|
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
|
void
|
||||||
Layout::redo (db::Op *op)
|
Layout::redo (db::Op *op)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -67,6 +67,7 @@ class Region;
|
||||||
class Edges;
|
class Edges;
|
||||||
class EdgePairs;
|
class EdgePairs;
|
||||||
class Texts;
|
class Texts;
|
||||||
|
class Technology;
|
||||||
class CellMapping;
|
class CellMapping;
|
||||||
class LayerMapping;
|
class LayerMapping;
|
||||||
|
|
||||||
|
|
@ -456,6 +457,20 @@ public:
|
||||||
virtual std::pair <bool, unsigned int> map_layer (const LayerProperties &lprops) = 0;
|
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
|
* @brief The layout object
|
||||||
*
|
*
|
||||||
|
|
@ -555,10 +570,36 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Clear the layout
|
* @brief Clears the layout
|
||||||
*/
|
*/
|
||||||
void clear ();
|
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
|
* @brief Accessor to the array repository
|
||||||
*/
|
*/
|
||||||
|
|
@ -843,8 +884,9 @@ public:
|
||||||
* @param parameters The PCell parameters
|
* @param parameters The PCell parameters
|
||||||
* @param cell_index The cell index which is to be replaced by the PCell variant proxy
|
* @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 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
|
* @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)
|
* @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)
|
* @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;
|
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.
|
* @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);
|
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.
|
* @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);
|
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
|
* @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;
|
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:
|
protected:
|
||||||
/**
|
/**
|
||||||
* @brief Establish the graph's internals according to the dirty flags
|
* @brief Establish the graph's internals according to the dirty flags
|
||||||
|
|
@ -1779,6 +1869,7 @@ private:
|
||||||
bool m_do_cleanup;
|
bool m_do_cleanup;
|
||||||
bool m_editable;
|
bool m_editable;
|
||||||
meta_info m_meta_info;
|
meta_info m_meta_info;
|
||||||
|
std::string m_tech_name;
|
||||||
tl::Mutex m_lock;
|
tl::Mutex m_lock;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -1832,6 +1923,11 @@ private:
|
||||||
* @brief Implementation of prune_cells and some prune_subcells variants
|
* @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);
|
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;
|
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) {
|
if (! lib) {
|
||||||
throw tl::Exception (tl::to_string (tr ("Not a valid library name: ")) + libname);
|
throw tl::Exception (tl::to_string (tr ("Not a valid library name: ")) + libname);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -228,7 +228,7 @@ public:
|
||||||
{
|
{
|
||||||
// get the layers which we have to look for
|
// get the layers which we have to look for
|
||||||
for (db::Layout::layer_iterator l = layout->begin_layers (); l != layout->end_layers (); ++l) {
|
for (db::Layout::layer_iterator l = layout->begin_layers (); l != layout->end_layers (); ++l) {
|
||||||
if (layers.is_empty () || layers.logical (*(*l).second).first) {
|
if (layers.is_empty () || layers.is_mapped (*(*l).second)) {
|
||||||
m_layers.push_back ((*l).first);
|
m_layers.push_back ((*l).first);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -191,11 +191,10 @@ Library::remap_to (db::Library *other)
|
||||||
|
|
||||||
if (! pn.first) {
|
if (! pn.first) {
|
||||||
|
|
||||||
// substitute by static layout cell
|
// substitute by a cold proxy
|
||||||
std::string name = r->first->cell_name (ci);
|
db::ProxyContextInfo info;
|
||||||
db::Cell *old_cell = r->first->take_cell (ci);
|
r->first->get_context_info (ci, info);
|
||||||
r->first->insert_cell (ci, name, new db::Cell (*old_cell));
|
r->first->create_cold_proxy_as (info, ci);
|
||||||
delete old_cell;
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
|
@ -203,11 +202,10 @@ Library::remap_to (db::Library *other)
|
||||||
const db::PCellDeclaration *new_pcell_decl = other->layout ().pcell_declaration (pn.second);
|
const db::PCellDeclaration *new_pcell_decl = other->layout ().pcell_declaration (pn.second);
|
||||||
if (! old_pcell_decl || ! new_pcell_decl) {
|
if (! old_pcell_decl || ! new_pcell_decl) {
|
||||||
|
|
||||||
// substitute by static layout cell
|
// substitute by a cold proxy
|
||||||
std::string name = r->first->cell_name (ci);
|
db::ProxyContextInfo info;
|
||||||
db::Cell *old_cell = r->first->take_cell (ci);
|
r->first->get_context_info (ci, info);
|
||||||
r->first->insert_cell (ci, name, new db::Cell (*old_cell));
|
r->first->create_cold_proxy_as (info, ci);
|
||||||
delete old_cell;
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
|
@ -232,11 +230,10 @@ Library::remap_to (db::Library *other)
|
||||||
|
|
||||||
if (! cn.first) {
|
if (! cn.first) {
|
||||||
|
|
||||||
// unlink this proxy: substitute by static layout cell
|
// substitute by a cold proxy
|
||||||
std::string name = r->first->cell_name (ci);
|
db::ProxyContextInfo info;
|
||||||
db::Cell *old_cell = r->first->take_cell (ci);
|
r->first->get_context_info (ci, info);
|
||||||
r->first->insert_cell (ci, name, new db::Cell (*old_cell));
|
r->first->create_cold_proxy_as (info, ci);
|
||||||
delete old_cell;
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@
|
||||||
#include "dbLibraryManager.h"
|
#include "dbLibraryManager.h"
|
||||||
#include "dbLibrary.h"
|
#include "dbLibrary.h"
|
||||||
#include "dbCommon.h"
|
#include "dbCommon.h"
|
||||||
|
#include "dbColdProxy.h"
|
||||||
|
|
||||||
#include "tlAssert.h"
|
#include "tlAssert.h"
|
||||||
#include "tlStaticObjects.h"
|
#include "tlStaticObjects.h"
|
||||||
|
|
@ -66,14 +67,39 @@ LibraryManager::~LibraryManager ()
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<bool, lib_id_type>
|
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);
|
iterator l;
|
||||||
if (l == m_lib_by_name.end ()) {
|
|
||||||
return std::make_pair (false, lib_id_type (0));
|
if (! for_technologies.empty ()) {
|
||||||
} else {
|
|
||||||
return std::make_pair (true, l->second);
|
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
|
void
|
||||||
|
|
@ -116,15 +142,44 @@ LibraryManager::register_lib (Library *library)
|
||||||
library->set_id (id);
|
library->set_id (id);
|
||||||
|
|
||||||
// if the new library replaces the old one, remap existing library proxies before deleting the library
|
// 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 ());
|
// (replacement is done only when all technologies are substituted)
|
||||||
if (ln != m_lib_by_name.end () && m_libs [ln->second]) {
|
lib_name_map::iterator l = m_lib_by_name.find (library->get_name ());
|
||||||
m_libs [ln->second]->remap_to (library);
|
bool found = false;
|
||||||
delete m_libs [ln->second];
|
while (l != m_lib_by_name.end () && l->first == library->get_name ()) {
|
||||||
m_libs [ln->second] = 0;
|
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 ();
|
changed_event ();
|
||||||
|
|
||||||
return id;
|
return id;
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
namespace db
|
namespace db
|
||||||
{
|
{
|
||||||
|
|
@ -50,7 +51,7 @@ class Library;
|
||||||
class DB_PUBLIC LibraryManager
|
class DB_PUBLIC LibraryManager
|
||||||
{
|
{
|
||||||
public:
|
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;
|
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.
|
* @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
|
* @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
|
* @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_lib_id = lib_id;
|
||||||
m_library_cell_index = lib_cell_index;
|
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);
|
db::Library *lib = db::LibraryManager::instance ().lib (m_lib_id);
|
||||||
if (lib) {
|
if (lib) {
|
||||||
lib->register_proxy (this, layout ());
|
lib->register_proxy (this, layout ());
|
||||||
|
|
|
||||||
|
|
@ -156,16 +156,14 @@ Manager::cancel ()
|
||||||
m_opened = false;
|
m_opened = false;
|
||||||
|
|
||||||
if (m_current->first.begin () != m_current->first.end ()) {
|
if (m_current->first.begin () != m_current->first.end ()) {
|
||||||
|
|
||||||
++m_current;
|
++m_current;
|
||||||
undo ();
|
undo ();
|
||||||
|
|
||||||
} else {
|
|
||||||
// empty transactions .. just delete
|
|
||||||
erase_transactions (m_current, m_transactions.end ());
|
|
||||||
m_current = m_transactions.end ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// wipe following history as we don't want the cancelled operation to be redoable
|
||||||
|
erase_transactions (m_current, m_transactions.end ());
|
||||||
|
m_current = m_transactions.end ();
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -122,21 +122,38 @@ extract_ld (const char *s, int &l, int &d, std::string &n)
|
||||||
|
|
||||||
std::pair <bool, unsigned int>
|
std::pair <bool, unsigned int>
|
||||||
NamedLayerReader::open_layer (db::Layout &layout, const std::string &n)
|
NamedLayerReader::open_layer (db::Layout &layout, const std::string &n)
|
||||||
|
{
|
||||||
|
return open_layer (layout, n, keep_layer_names (), create_layers ());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair <bool, unsigned int>
|
||||||
|
NamedLayerReader::open_layer (db::Layout &layout, const std::string &n, bool keep_layer_name, bool create_layer)
|
||||||
|
{
|
||||||
|
std::map<std::string, std::pair <bool, unsigned int> >::const_iterator lc = m_layer_cache.find (n);
|
||||||
|
if (lc != m_layer_cache.end ()) {
|
||||||
|
return lc->second;
|
||||||
|
} else {
|
||||||
|
std::pair <bool, unsigned int> res = open_layer_uncached (layout, n, keep_layer_name, create_layer);
|
||||||
|
m_layer_cache.insert (std::make_pair (n, res));
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair <bool, unsigned int>
|
||||||
|
NamedLayerReader::open_layer_uncached (db::Layout &layout, const std::string &n, bool keep_layer_name, bool create_layer)
|
||||||
{
|
{
|
||||||
int l = -1, d = -1;
|
int l = -1, d = -1;
|
||||||
std::string on;
|
std::string on;
|
||||||
|
|
||||||
std::pair<bool, unsigned int> ll (false, 0);
|
std::set<unsigned int> li = m_layer_map.logical (n, layout);
|
||||||
|
if (li.empty () && ! keep_layer_name) {
|
||||||
ll = m_layer_map.logical (n, layout);
|
|
||||||
if (! ll.first && !m_keep_layer_names) {
|
|
||||||
|
|
||||||
if (extract_plain_layer (n.c_str (), l)) {
|
if (extract_plain_layer (n.c_str (), l)) {
|
||||||
|
|
||||||
db::LayerProperties lp;
|
db::LayerProperties lp;
|
||||||
lp.layer = l;
|
lp.layer = l;
|
||||||
lp.datatype = 0;
|
lp.datatype = 0;
|
||||||
ll = m_layer_map.logical (lp, layout);
|
li = m_layer_map.logical (lp, layout);
|
||||||
|
|
||||||
} else if (extract_ld (n.c_str (), l, d, on)) {
|
} else if (extract_ld (n.c_str (), l, d, on)) {
|
||||||
|
|
||||||
|
|
@ -144,22 +161,35 @@ NamedLayerReader::open_layer (db::Layout &layout, const std::string &n)
|
||||||
lp.layer = l;
|
lp.layer = l;
|
||||||
lp.datatype = d;
|
lp.datatype = d;
|
||||||
lp.name = on;
|
lp.name = on;
|
||||||
ll = m_layer_map.logical (lp, layout);
|
li = m_layer_map.logical (lp, layout);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ll.first) {
|
if (! li.empty ()) {
|
||||||
|
|
||||||
// create the layer if it is not part of the layout yet.
|
for (std::set<unsigned int>::const_iterator i = li.begin (); i != li.end (); ++i) {
|
||||||
if (! layout.is_valid_layer (ll.second)) {
|
m_layer_map_out.mmap (n, *i, layout.get_properties (*i));
|
||||||
layout.insert_layer (ll.second, m_layer_map.mapping (ll.second));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ll;
|
if (li.size () == 1) {
|
||||||
|
|
||||||
} else if (! m_create_layers) {
|
return std::make_pair (true, *li.begin ());
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
std::map<std::set<unsigned int>, unsigned int>::iterator mmp = m_multi_mapping_placeholders.find (li);
|
||||||
|
if (mmp == m_multi_mapping_placeholders.end ()) {
|
||||||
|
// create a placeholder layer for later
|
||||||
|
mmp = m_multi_mapping_placeholders.insert (std::make_pair (li, layout.insert_layer ())).first;
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::make_pair (true, mmp->second);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (! create_layer) {
|
||||||
|
|
||||||
return std::pair<bool, unsigned int> (false, 0);
|
return std::pair<bool, unsigned int> (false, 0);
|
||||||
|
|
||||||
|
|
@ -188,21 +218,53 @@ NamedLayerReader::open_layer (db::Layout &layout, const std::string &n)
|
||||||
void
|
void
|
||||||
NamedLayerReader::map_layer (const std::string &name, unsigned int layer)
|
NamedLayerReader::map_layer (const std::string &name, unsigned int layer)
|
||||||
{
|
{
|
||||||
m_layer_map.map (name, layer);
|
m_layer_cache [name] = std::make_pair (true, layer);
|
||||||
|
m_layer_map_out.map (name, layer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
NamedLayerReader::prepare_layers ()
|
NamedLayerReader::prepare_layers (db::Layout &layout)
|
||||||
{
|
{
|
||||||
m_new_layers.clear ();
|
m_new_layers.clear ();
|
||||||
m_next_layer_index = m_layer_map.next_index ();
|
m_next_layer_index = m_layer_map.next_index ();
|
||||||
|
|
||||||
|
m_layer_map_out.clear ();
|
||||||
|
m_multi_mapping_placeholders.clear ();
|
||||||
|
m_layer_cache.clear ();
|
||||||
|
|
||||||
|
m_layer_map.prepare (layout);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
NamedLayerReader::finish_layers (db::Layout &layout)
|
NamedLayerReader::finish_layers (db::Layout &layout)
|
||||||
{
|
{
|
||||||
|
// resolve layer multi-mapping
|
||||||
|
|
||||||
|
for (std::map<std::set<unsigned int>, unsigned int>::const_iterator i = m_multi_mapping_placeholders.begin (); i != m_multi_mapping_placeholders.end (); ++i) {
|
||||||
|
|
||||||
|
if (i->first.size () > 1) {
|
||||||
|
|
||||||
|
bool discard_layer = i->first.find (i->second) == i->first.end ();
|
||||||
|
|
||||||
|
for (std::set<unsigned int>::const_iterator l = i->first.begin (); l != i->first.end (); ++l) {
|
||||||
|
|
||||||
|
// last one? this one will get a "move"
|
||||||
|
std::set<unsigned int>::const_iterator ll = l;
|
||||||
|
if (discard_layer && ++ll == i->first.end ()) {
|
||||||
|
layout.move_layer (i->second, *l);
|
||||||
|
layout.delete_layer (i->second);
|
||||||
|
} else {
|
||||||
|
layout.copy_layer (i->second, *l);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// assign layer numbers to new layers
|
// assign layer numbers to new layers
|
||||||
if (! m_new_layers.empty () && !m_keep_layer_names) {
|
if (! m_new_layers.empty () && ! m_keep_layer_names) {
|
||||||
|
|
||||||
std::set<std::pair<int, int> > used_ld;
|
std::set<std::pair<int, int> > used_ld;
|
||||||
for (db::Layout::layer_iterator l = layout.begin_layers (); l != layout.end_layers (); ++l) {
|
for (db::Layout::layer_iterator l = layout.begin_layers (); l != layout.end_layers (); ++l) {
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,7 @@ public:
|
||||||
*/
|
*/
|
||||||
NamedLayerReader ();
|
NamedLayerReader ();
|
||||||
|
|
||||||
|
protected:
|
||||||
/**
|
/**
|
||||||
* @brief Sets a value indicating whether to create new layers
|
* @brief Sets a value indicating whether to create new layers
|
||||||
*/
|
*/
|
||||||
|
|
@ -73,13 +74,21 @@ public:
|
||||||
void set_layer_map (const LayerMap &lm);
|
void set_layer_map (const LayerMap &lm);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Gets the layer map
|
* @brief Gets the input layer map
|
||||||
*/
|
*/
|
||||||
const LayerMap &layer_map ()
|
const LayerMap &layer_map ()
|
||||||
{
|
{
|
||||||
return m_layer_map;
|
return m_layer_map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the layer map
|
||||||
|
*/
|
||||||
|
const LayerMap &layer_map_out ()
|
||||||
|
{
|
||||||
|
return m_layer_map_out;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Sets a value indicating whether layer names are kept
|
* @brief Sets a value indicating whether layer names are kept
|
||||||
* If set to true, no name translation is performed and layers are
|
* If set to true, no name translation is performed and layers are
|
||||||
|
|
@ -96,7 +105,6 @@ public:
|
||||||
return m_keep_layer_names;
|
return m_keep_layer_names;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
|
||||||
/**
|
/**
|
||||||
* @brief Opens a new layer
|
* @brief Opens a new layer
|
||||||
* This method will create or locate a layer for a given name.
|
* This method will create or locate a layer for a given name.
|
||||||
|
|
@ -105,6 +113,14 @@ protected:
|
||||||
*/
|
*/
|
||||||
std::pair <bool, unsigned int> open_layer (db::Layout &layout, const std::string &name);
|
std::pair <bool, unsigned int> open_layer (db::Layout &layout, const std::string &name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Opens a new layer
|
||||||
|
* This method will create or locate a layer for a given name.
|
||||||
|
* The result's first attribute is true, if such a layer could be found
|
||||||
|
* or created. In this case, the second attribute is the layer index.
|
||||||
|
*/
|
||||||
|
std::pair <bool, unsigned int> open_layer (db::Layout &layout, const std::string &name, bool keep_layer_name, bool create_layer);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Force mapping of a name to a layer index
|
* @brief Force mapping of a name to a layer index
|
||||||
*/
|
*/
|
||||||
|
|
@ -121,7 +137,7 @@ protected:
|
||||||
* @brief Prepares reading
|
* @brief Prepares reading
|
||||||
* This method must be called before the reading is done.
|
* This method must be called before the reading is done.
|
||||||
*/
|
*/
|
||||||
void prepare_layers ();
|
void prepare_layers (db::Layout &layout);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_create_layers;
|
bool m_create_layers;
|
||||||
|
|
@ -129,6 +145,11 @@ private:
|
||||||
LayerMap m_layer_map;
|
LayerMap m_layer_map;
|
||||||
unsigned int m_next_layer_index;
|
unsigned int m_next_layer_index;
|
||||||
std::map <std::string, unsigned int> m_new_layers;
|
std::map <std::string, unsigned int> m_new_layers;
|
||||||
|
db::LayerMap m_layer_map_out;
|
||||||
|
std::map<std::string, std::pair <bool, unsigned int> > m_layer_cache;
|
||||||
|
std::map<std::set<unsigned int>, unsigned int> m_multi_mapping_placeholders;
|
||||||
|
|
||||||
|
std::pair <bool, unsigned int> open_layer_uncached (db::Layout &layout, const std::string &name, bool keep_layer_name, bool create_layer);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@
|
||||||
#include "gsiObject.h"
|
#include "gsiObject.h"
|
||||||
#include "dbLayout.h"
|
#include "dbLayout.h"
|
||||||
#include "tlVariant.h"
|
#include "tlVariant.h"
|
||||||
|
#include "tlObject.h"
|
||||||
|
|
||||||
namespace db
|
namespace db
|
||||||
{
|
{
|
||||||
|
|
@ -327,7 +328,8 @@ public:
|
||||||
* @brief A declaration for a PCell
|
* @brief A declaration for a PCell
|
||||||
*/
|
*/
|
||||||
class DB_PUBLIC PCellDeclaration
|
class DB_PUBLIC PCellDeclaration
|
||||||
: public gsi::ObjectBase
|
: public gsi::ObjectBase,
|
||||||
|
public tl::Object
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,33 @@
|
||||||
namespace db
|
namespace db
|
||||||
{
|
{
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------
|
||||||
|
|
||||||
|
DB_PUBLIC void
|
||||||
|
join_layer_names (std::string &s, const std::string &n)
|
||||||
|
{
|
||||||
|
if (s == n) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! s.empty ()) {
|
||||||
|
|
||||||
|
size_t i = s.find (n);
|
||||||
|
if (i != std::string::npos && (i == 0 || s.c_str ()[i - 1] == ';')) {
|
||||||
|
char after = s.c_str ()[i + n.size ()];
|
||||||
|
if (after == 0 || after == ';') {
|
||||||
|
// n is already contained in s
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s += ";";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
s += n;
|
||||||
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------
|
// ---------------------------------------------------------------
|
||||||
// ReaderBase implementation
|
// ReaderBase implementation
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,14 @@ public:
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Joins layer names into a single, combined layer
|
||||||
|
* @param s The first layer name and output
|
||||||
|
* @param n The name to add
|
||||||
|
*/
|
||||||
|
DB_PUBLIC void
|
||||||
|
join_layer_names (std::string &s, const std::string &n);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The generic reader base class
|
* @brief The generic reader base class
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -40,10 +40,9 @@ namespace db
|
||||||
/// A helper class to join two datatype map members
|
/// A helper class to join two datatype map members
|
||||||
struct LmapJoinOp1
|
struct LmapJoinOp1
|
||||||
{
|
{
|
||||||
void operator() (unsigned int &a, unsigned int b)
|
void operator() (std::set<unsigned int> &a, const std::set<unsigned int> &b)
|
||||||
{
|
{
|
||||||
// TODO: could also do?: throw an exception ..
|
a.insert (b.begin (), b.end ());
|
||||||
a = b;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -58,7 +57,27 @@ struct LmapJoinOp2
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Utility typedefs for the expression parser
|
/// A helper class to implement the unmap operation
|
||||||
|
struct LmapEraseDatatypeInterval
|
||||||
|
{
|
||||||
|
LmapEraseDatatypeInterval (unsigned int dfrom, unsigned int dto)
|
||||||
|
: m_dfrom (dfrom), m_dto (dto)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
void operator() (LayerMap::datatype_map &a, const LayerMap::datatype_map &)
|
||||||
|
{
|
||||||
|
if (is_static_ld (m_dfrom) && is_static_ld (m_dto)) {
|
||||||
|
a.erase (m_dfrom, m_dto + 1);
|
||||||
|
} else {
|
||||||
|
a.clear ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
unsigned int m_dfrom, m_dto;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Utility typedefs for the expression parser
|
||||||
typedef std::pair<ld_type, ld_type> ld_interval;
|
typedef std::pair<ld_type, ld_type> ld_interval;
|
||||||
|
|
||||||
/// Utility typedefs for the expression parser
|
/// Utility typedefs for the expression parser
|
||||||
|
|
@ -71,70 +90,104 @@ LayerMap::LayerMap ()
|
||||||
// .. nothing yet ..
|
// .. nothing yet ..
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<bool, unsigned int>
|
bool
|
||||||
|
LayerMap::is_mapped (const LDPair &p) const
|
||||||
|
{
|
||||||
|
const datatype_map *dm = m_ld_map.mapped (p.layer);
|
||||||
|
if (!dm) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const std::set<unsigned int> *l = dm->mapped (p.datatype);
|
||||||
|
return (l && ! l->empty ());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
LayerMap::is_mapped (const std::string &n) const
|
||||||
|
{
|
||||||
|
std::map<std::string, std::set<unsigned int> >::const_iterator m = m_name_map.find (n);
|
||||||
|
return m != m_name_map.end () && ! m->second.empty ();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
LayerMap::is_mapped (const db::LayerProperties &p) const
|
||||||
|
{
|
||||||
|
std::set<unsigned int> m;
|
||||||
|
if (p.layer >= 0 && p.datatype >= 0) {
|
||||||
|
if (is_mapped (db::LDPair (p.layer, p.datatype))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (! p.name.empty ()) {
|
||||||
|
return is_mapped (p.name);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::set<unsigned int>
|
||||||
LayerMap::logical (const LDPair &p) const
|
LayerMap::logical (const LDPair &p) const
|
||||||
{
|
{
|
||||||
return logical_internal (p, false);
|
return logical_internal (p, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<bool, unsigned int>
|
std::set<unsigned int>
|
||||||
LayerMap::logical (const std::string &n) const
|
LayerMap::logical (const std::string &n) const
|
||||||
{
|
{
|
||||||
return logical_internal (n, false);
|
return logical_internal (n, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<bool, unsigned int>
|
std::set<unsigned int>
|
||||||
LayerMap::logical (const db::LayerProperties &p) const
|
LayerMap::logical (const db::LayerProperties &p) const
|
||||||
{
|
{
|
||||||
return logical_internal (p, false);
|
return logical_internal (p, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<bool, unsigned int>
|
std::set<unsigned int>
|
||||||
LayerMap::logical_internal (const LDPair &p, bool allow_placeholder) const
|
LayerMap::logical_internal (const LDPair &p, bool allow_placeholder) const
|
||||||
{
|
{
|
||||||
const datatype_map *dm = m_ld_map.mapped (p.layer);
|
const datatype_map *dm = m_ld_map.mapped (p.layer);
|
||||||
if (dm) {
|
if (dm) {
|
||||||
const unsigned int *l = dm->mapped (p.datatype);
|
const std::set<unsigned int> *l = dm->mapped (p.datatype);
|
||||||
if (l && (allow_placeholder || ! is_placeholder (*l))) {
|
if (l && (allow_placeholder || ! is_placeholder (*l))) {
|
||||||
return std::make_pair (true, *l);
|
return *l;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return std::make_pair (false, 0);
|
return std::set<unsigned int> ();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<bool, unsigned int>
|
std::set<unsigned int>
|
||||||
LayerMap::logical_internal (const std::string &n, bool allow_placeholder) const
|
LayerMap::logical_internal (const std::string &n, bool allow_placeholder) const
|
||||||
{
|
{
|
||||||
std::map<std::string, unsigned int>::const_iterator m = m_name_map.find (n);
|
std::map<std::string, std::set<unsigned int> >::const_iterator m = m_name_map.find (n);
|
||||||
if (m != m_name_map.end () && (allow_placeholder || ! is_placeholder (m->second))) {
|
if (m != m_name_map.end () && (allow_placeholder || ! is_placeholder (m->second))) {
|
||||||
return std::make_pair (true, m->second);
|
return m->second;
|
||||||
} else {
|
} else {
|
||||||
return std::make_pair (false, 0);
|
return std::set<unsigned int> ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<bool, unsigned int>
|
std::set<unsigned int>
|
||||||
LayerMap::logical_internal (const db::LayerProperties &p, bool allow_placeholder) const
|
LayerMap::logical_internal (const db::LayerProperties &p, bool allow_placeholder) const
|
||||||
{
|
{
|
||||||
|
std::set<unsigned int> m;
|
||||||
if (p.layer >= 0 && p.datatype >= 0) {
|
if (p.layer >= 0 && p.datatype >= 0) {
|
||||||
std::pair<bool, unsigned int> m = logical_internal (db::LDPair (p.layer, p.datatype), allow_placeholder);
|
m = logical_internal (db::LDPair (p.layer, p.datatype), allow_placeholder);
|
||||||
if (m.first) {
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (! p.name.empty ()) {
|
if (m.empty () && ! p.name.empty ()) {
|
||||||
std::pair<bool, unsigned int> m = logical_internal (p.name, allow_placeholder);
|
m = logical_internal (p.name, allow_placeholder);
|
||||||
if (m.first) {
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return std::make_pair (false, 0);
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
LayerMap::is_placeholder (unsigned int l) const
|
LayerMap::is_placeholder (const std::set<unsigned int> &m) const
|
||||||
{
|
{
|
||||||
return (m_placeholders.size () > std::numeric_limits<unsigned int>::max () - l);
|
for (std::set<unsigned int>::const_iterator i = m.begin (); i != m.end (); ++i) {
|
||||||
|
if (m_placeholders.size () > std::numeric_limits<unsigned int>::max () - *i) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const db::LayerProperties *
|
const db::LayerProperties *
|
||||||
|
|
@ -148,39 +201,52 @@ LayerMap::target (unsigned int l) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<bool, unsigned int>
|
std::set<unsigned int>
|
||||||
LayerMap::logical (const db::LayerProperties &p, db::Layout &layout) const
|
LayerMap::logical (const db::LayerProperties &p, db::Layout &layout) const
|
||||||
{
|
{
|
||||||
std::pair<bool, unsigned int> l = logical_internal (p, true);
|
std::set<unsigned int> l = logical_internal (p, true);
|
||||||
if (l.first && is_placeholder (l.second)) {
|
if (is_placeholder (l)) {
|
||||||
return const_cast<LayerMap *> (this)->substitute_placeholder (p, l.second, layout);
|
return const_cast<LayerMap *> (this)->substitute_placeholder (p, l, layout);
|
||||||
} else {
|
} else {
|
||||||
return l;
|
return l;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<bool, unsigned int>
|
std::set<unsigned int>
|
||||||
LayerMap::logical (const db::LDPair &p, db::Layout &layout) const
|
LayerMap::logical (const db::LDPair &p, db::Layout &layout) const
|
||||||
{
|
{
|
||||||
std::pair<bool, unsigned int> l = logical_internal (p, true);
|
std::set<unsigned int> l = logical_internal (p, true);
|
||||||
if (l.first && is_placeholder (l.second)) {
|
if (is_placeholder (l)) {
|
||||||
return const_cast<LayerMap *> (this)->substitute_placeholder (db::LayerProperties (p.layer, p.datatype), l.second, layout);
|
return const_cast<LayerMap *> (this)->substitute_placeholder (db::LayerProperties (p.layer, p.datatype), l, layout);
|
||||||
} else {
|
} else {
|
||||||
return l;
|
return l;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<bool, unsigned int>
|
std::set<unsigned int>
|
||||||
LayerMap::substitute_placeholder (const db::LayerProperties &p, unsigned int ph, db::Layout &layout)
|
LayerMap::substitute_placeholder (const db::LayerProperties &p, const std::set<unsigned int> &m, db::Layout &layout)
|
||||||
{
|
{
|
||||||
const db::LayerProperties &lp_ph = m_placeholders [std::numeric_limits<unsigned int>::max () - ph];
|
std::set<unsigned int> res;
|
||||||
db::LayerProperties lp_new = p;
|
for (std::set<unsigned int>::const_iterator i = m.begin (); i != m.end (); ++i) {
|
||||||
lp_new.layer = db::ld_combine (p.layer, lp_ph.layer);
|
|
||||||
lp_new.datatype = db::ld_combine (p.datatype, lp_ph.datatype);
|
|
||||||
|
|
||||||
unsigned int l_new = layout.insert_layer (lp_new);
|
if (m_placeholders.size () > std::numeric_limits<unsigned int>::max () - *i) {
|
||||||
map (p, l_new, lp_new);
|
|
||||||
return std::make_pair (true, l_new);
|
const db::LayerProperties &lp_ph = m_placeholders [std::numeric_limits<unsigned int>::max () - *i];
|
||||||
|
db::LayerProperties lp_new = p;
|
||||||
|
lp_new.layer = db::ld_combine (p.layer, lp_ph.layer);
|
||||||
|
lp_new.datatype = db::ld_combine (p.datatype, lp_ph.datatype);
|
||||||
|
|
||||||
|
unsigned int l_new = layout.insert_layer (lp_new);
|
||||||
|
map (p, l_new, lp_new);
|
||||||
|
res.insert (l_new);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
res.insert (*i);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string format_interval (ld_type l1, ld_type l2)
|
static std::string format_interval (ld_type l1, ld_type l2)
|
||||||
|
|
@ -196,44 +262,93 @@ static std::string format_interval (ld_type l1, ld_type l2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::vector<std::pair<ld_type, ld_type> >
|
||||||
|
extract_dt_intervals (const LayerMap::datatype_map &dt_map, int ll, bool &has_others)
|
||||||
|
{
|
||||||
|
std::vector<std::pair<ld_type, ld_type> > res;
|
||||||
|
|
||||||
|
for (LayerMap::datatype_map::const_iterator d = dt_map.begin (); d != dt_map.end (); ) {
|
||||||
|
|
||||||
|
if (d->second.find (ll) != d->second.end ()) {
|
||||||
|
|
||||||
|
std::pair<ld_type, ld_type> dpi = d->first;
|
||||||
|
|
||||||
|
if (d->second.size () > 1) {
|
||||||
|
has_others = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
LayerMap::datatype_map::const_iterator dd = d;
|
||||||
|
++dd;
|
||||||
|
while (dd != dt_map.end () && dd->first.first == dpi.second && dd->second.find (ll) != dd->second.end ()) {
|
||||||
|
if (dd->second.size () > 1) {
|
||||||
|
has_others = true;
|
||||||
|
}
|
||||||
|
dpi.second = dd->first.second;
|
||||||
|
++dd;
|
||||||
|
}
|
||||||
|
|
||||||
|
d = dd;
|
||||||
|
|
||||||
|
res.push_back (dpi);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
++d;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
std::string
|
std::string
|
||||||
LayerMap::mapping_str (unsigned int ll) const
|
LayerMap::mapping_str (unsigned int ll) const
|
||||||
{
|
{
|
||||||
std::string s;
|
std::string s;
|
||||||
bool f1 = true;
|
bool f1 = true;
|
||||||
|
bool is_mmap = false;
|
||||||
|
|
||||||
for (ld_map::const_iterator l = m_ld_map.begin (); l != m_ld_map.end (); ++l) {
|
for (ld_map::const_iterator l = m_ld_map.begin (); l != m_ld_map.end (); ) {
|
||||||
|
|
||||||
|
std::pair<ld_type, ld_type> lti = l->first;
|
||||||
|
|
||||||
|
std::vector<std::pair<ld_type, ld_type> > dti = extract_dt_intervals (l->second, ll, is_mmap);
|
||||||
|
++l;
|
||||||
|
while (l != m_ld_map.end () && lti.second == l->first.first && extract_dt_intervals (l->second, ll, is_mmap) == dti) {
|
||||||
|
lti.second = l->first.second;
|
||||||
|
++l;
|
||||||
|
}
|
||||||
|
|
||||||
bool f2 = true;
|
bool f2 = true;
|
||||||
for (datatype_map::const_iterator d = l->second.begin (); d != l->second.end (); ++d) {
|
for (std::vector<std::pair<ld_type, ld_type> >::const_iterator d = dti.begin (); d != dti.end (); ++d) {
|
||||||
if (d->second == ll) {
|
|
||||||
|
|
||||||
// create a string representation
|
// create a string representation
|
||||||
if (!f2) {
|
if (!f2) {
|
||||||
s += ",";
|
s += ",";
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
if (!f1) {
|
|
||||||
s += ";";
|
|
||||||
}
|
|
||||||
f1 = false;
|
|
||||||
|
|
||||||
s += format_interval (l->first.first, l->first.second);
|
|
||||||
s += "/";
|
|
||||||
|
|
||||||
|
if (!f1) {
|
||||||
|
s += ";";
|
||||||
}
|
}
|
||||||
f2 = false;
|
f1 = false;
|
||||||
|
|
||||||
s += format_interval (d->first.first, d->first.second);
|
s += format_interval (lti.first, lti.second);
|
||||||
|
s += "/";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
f2 = false;
|
||||||
|
|
||||||
|
s += format_interval (d->first, d->second);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (std::map <std::string, unsigned int>::const_iterator l = m_name_map.begin (); l != m_name_map.end (); ++l) {
|
for (std::map <std::string, std::set<unsigned int> >::const_iterator l = m_name_map.begin (); l != m_name_map.end (); ++l) {
|
||||||
if (l->second == ll) {
|
|
||||||
|
if (l->second.find (ll) != l->second.end ()) {
|
||||||
|
|
||||||
|
if (l->second.size () > 1) {
|
||||||
|
is_mmap = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (!f1) {
|
if (!f1) {
|
||||||
s += ";";
|
s += ";";
|
||||||
|
|
@ -243,6 +358,7 @@ LayerMap::mapping_str (unsigned int ll) const
|
||||||
s += tl::to_word_or_quoted_string (l->first);
|
s += tl::to_word_or_quoted_string (l->first);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<unsigned int, LayerProperties>::const_iterator t = m_target_layers.find (ll);
|
std::map<unsigned int, LayerProperties>::const_iterator t = m_target_layers.find (ll);
|
||||||
|
|
@ -251,7 +367,11 @@ LayerMap::mapping_str (unsigned int ll) const
|
||||||
s += t->second.to_string (true);
|
s += t->second.to_string (true);
|
||||||
}
|
}
|
||||||
|
|
||||||
return s;
|
if (is_mmap) {
|
||||||
|
return "+" + s;
|
||||||
|
} else {
|
||||||
|
return s;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -300,11 +420,19 @@ LayerMap::prepare (db::Layout &layout)
|
||||||
// Now remap the indexes
|
// Now remap the indexes
|
||||||
for (ld_map::iterator l = m_ld_map.begin (); l != m_ld_map.end (); ++l) {
|
for (ld_map::iterator l = m_ld_map.begin (); l != m_ld_map.end (); ++l) {
|
||||||
for (datatype_map::iterator d = l->second.begin (); d != l->second.end (); ++d) {
|
for (datatype_map::iterator d = l->second.begin (); d != l->second.end (); ++d) {
|
||||||
d->second = real_layers [d->second];
|
std::set<unsigned int> dn;
|
||||||
|
for (std::set<unsigned int>::const_iterator i = d->second.begin (); i != d->second.end (); ++i) {
|
||||||
|
dn.insert (real_layers [*i]);
|
||||||
|
}
|
||||||
|
d->second = dn;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (std::map<std::string, unsigned int>::iterator n = m_name_map.begin (); n != m_name_map.end (); ++n) {
|
for (std::map<std::string, std::set<unsigned int> >::iterator n = m_name_map.begin (); n != m_name_map.end (); ++n) {
|
||||||
n->second = real_layers [n->second];
|
std::set<unsigned int> dn;
|
||||||
|
for (std::set<unsigned int>::const_iterator i = n->second.begin (); i != n->second.end (); ++i) {
|
||||||
|
dn.insert (real_layers [*i]);
|
||||||
|
}
|
||||||
|
n->second = dn;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<unsigned int, LayerProperties> old_target_layers;
|
std::map<unsigned int, LayerProperties> old_target_layers;
|
||||||
|
|
@ -329,11 +457,11 @@ LayerMap::get_layers () const
|
||||||
|
|
||||||
for (ld_map::const_iterator l = m_ld_map.begin (); l != m_ld_map.end (); ++l) {
|
for (ld_map::const_iterator l = m_ld_map.begin (); l != m_ld_map.end (); ++l) {
|
||||||
for (datatype_map::const_iterator d = l->second.begin (); d != l->second.end (); ++d) {
|
for (datatype_map::const_iterator d = l->second.begin (); d != l->second.end (); ++d) {
|
||||||
layers.insert (d->second);
|
layers.insert (d->second.begin (), d->second.end ());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const_iterator_names n = m_name_map.begin (); n != m_name_map.end (); ++n) {
|
for (const_iterator_names n = m_name_map.begin (); n != m_name_map.end (); ++n) {
|
||||||
layers.insert(n->second);
|
layers.insert(n->second.begin (), n->second.end ());
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::vector<unsigned int> (layers.begin (), layers.end ());
|
return std::vector<unsigned int> (layers.begin (), layers.end ());
|
||||||
|
|
@ -358,7 +486,7 @@ LayerMap::mapping (unsigned int ll) const
|
||||||
// no mapping is given. Use the lowest layer and datatype
|
// no mapping is given. Use the lowest layer and datatype
|
||||||
for (ld_map::const_iterator l = m_ld_map.begin (); l != m_ld_map.end (); ++l) {
|
for (ld_map::const_iterator l = m_ld_map.begin (); l != m_ld_map.end (); ++l) {
|
||||||
for (datatype_map::const_iterator d = l->second.begin (); d != l->second.end (); ++d) {
|
for (datatype_map::const_iterator d = l->second.begin (); d != l->second.end (); ++d) {
|
||||||
if (d->second == ll) {
|
if (d->second.find (ll) != d->second.end ()) {
|
||||||
p.layer = l->first.first;
|
p.layer = l->first.first;
|
||||||
p.datatype = d->first.first;
|
p.datatype = d->first.first;
|
||||||
break;
|
break;
|
||||||
|
|
@ -373,7 +501,7 @@ LayerMap::mapping (unsigned int ll) const
|
||||||
// no mapping is given. Use the lowest layer and datatype
|
// no mapping is given. Use the lowest layer and datatype
|
||||||
for (ld_map::const_iterator l = m_ld_map.begin (); l != m_ld_map.end (); ++l) {
|
for (ld_map::const_iterator l = m_ld_map.begin (); l != m_ld_map.end (); ++l) {
|
||||||
for (datatype_map::const_iterator d = l->second.begin (); d != l->second.end (); ++d) {
|
for (datatype_map::const_iterator d = l->second.begin (); d != l->second.end (); ++d) {
|
||||||
if (d->second == ll) {
|
if (d->second.find (ll) != d->second.end ()) {
|
||||||
p.layer = l->first.first;
|
p.layer = l->first.first;
|
||||||
p.datatype = d->first.first;
|
p.datatype = d->first.first;
|
||||||
break;
|
break;
|
||||||
|
|
@ -384,8 +512,8 @@ LayerMap::mapping (unsigned int ll) const
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p.name.empty ()) {
|
if (p.name.empty ()) {
|
||||||
for (std::map <std::string, unsigned int>::const_iterator l = m_name_map.begin (); l != m_name_map.end (); ++l) {
|
for (std::map <std::string, std::set<unsigned int> >::const_iterator l = m_name_map.begin (); l != m_name_map.end (); ++l) {
|
||||||
if (l->second == ll) {
|
if (l->second.find (ll) != l->second.end ()) {
|
||||||
p.name = l->first;
|
p.name = l->first;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -397,59 +525,59 @@ LayerMap::mapping (unsigned int ll) const
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
LayerMap::map (const LDPair &p, unsigned int l)
|
LayerMap::mmap (const LDPair &p, unsigned int l)
|
||||||
{
|
{
|
||||||
insert (p, p, l, (const LayerProperties *) 0);
|
insert (p, p, l, (const LayerProperties *) 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
LayerMap::map (const std::string &name, unsigned int l)
|
LayerMap::mmap (const std::string &name, unsigned int l)
|
||||||
{
|
{
|
||||||
insert (name, l, (const LayerProperties *) 0);
|
insert (name, l, (const LayerProperties *) 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
LayerMap::map (const LayerProperties &f, unsigned int l)
|
LayerMap::mmap (const LayerProperties &f, unsigned int l)
|
||||||
{
|
{
|
||||||
if (f.name.empty () || is_static_ld (f.layer) || is_static_ld (f.datatype)) {
|
if (f.name.empty () || is_static_ld (f.layer) || is_static_ld (f.datatype)) {
|
||||||
map (db::LDPair (f.layer, f.datatype), l);
|
mmap (db::LDPair (f.layer, f.datatype), l);
|
||||||
}
|
}
|
||||||
if (! f.name.empty ()) {
|
if (! f.name.empty ()) {
|
||||||
map (f.name, l);
|
mmap (f.name, l);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
LayerMap::map (const LDPair &p, unsigned int l, const LayerProperties &t)
|
LayerMap::mmap (const LDPair &p, unsigned int l, const LayerProperties &t)
|
||||||
{
|
{
|
||||||
insert (p, p, l, &t);
|
insert (p, p, l, &t);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
LayerMap::map (const std::string &name, unsigned int l, const LayerProperties &t)
|
LayerMap::mmap (const std::string &name, unsigned int l, const LayerProperties &t)
|
||||||
{
|
{
|
||||||
insert (name, l, &t);
|
insert (name, l, &t);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
LayerMap::map (const LayerProperties &f, unsigned int l, const LayerProperties &t)
|
LayerMap::mmap (const LayerProperties &f, unsigned int l, const LayerProperties &t)
|
||||||
{
|
{
|
||||||
if (f.name.empty () || is_static_ld (f.layer) || is_static_ld (f.datatype)) {
|
if (f.name.empty () || is_static_ld (f.layer) || is_static_ld (f.datatype)) {
|
||||||
map (db::LDPair (f.layer, f.datatype), l, t);
|
mmap (db::LDPair (f.layer, f.datatype), l, t);
|
||||||
}
|
}
|
||||||
if (! f.name.empty ()) {
|
if (! f.name.empty ()) {
|
||||||
map (f.name, l, t);
|
mmap (f.name, l, t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
LayerMap::map (const LDPair &p1, const LDPair &p2, unsigned int l)
|
LayerMap::mmap (const LDPair &p1, const LDPair &p2, unsigned int l)
|
||||||
{
|
{
|
||||||
insert (p1, p2, l, (const LayerProperties *) 0);
|
insert (p1, p2, l, (const LayerProperties *) 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
LayerMap::map (const LDPair &p1, const LDPair &p2, unsigned int l, const LayerProperties &lp)
|
LayerMap::mmap (const LDPair &p1, const LDPair &p2, unsigned int l, const LayerProperties &lp)
|
||||||
{
|
{
|
||||||
insert (p1, p2, l, &lp);
|
insert (p1, p2, l, &lp);
|
||||||
}
|
}
|
||||||
|
|
@ -495,18 +623,25 @@ parse_intervals (tl::Extractor &ex, ld_interval_vector &v)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
LayerMap::map_expr (const std::string &expr, unsigned int l)
|
LayerMap::mmap_expr (const std::string &expr, unsigned int l)
|
||||||
{
|
{
|
||||||
tl::Extractor ex (expr.c_str ());
|
tl::Extractor ex (expr.c_str ());
|
||||||
map_expr (ex, l);
|
mmap_expr (ex, l);
|
||||||
ex.expect_end ();
|
ex.expect_end ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
LayerMap::map_expr (tl::Extractor &ex, unsigned int l)
|
LayerMap::mmap_expr (tl::Extractor &ex, unsigned int l)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
|
||||||
|
bool round_bracket = false, square_bracket = false;
|
||||||
|
if (ex.test ("(")) {
|
||||||
|
round_bracket = true;
|
||||||
|
} else if (ex.test ("[")) {
|
||||||
|
square_bracket = true;
|
||||||
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
|
||||||
tl::Extractor ex_saved = ex;
|
tl::Extractor ex_saved = ex;
|
||||||
|
|
@ -515,7 +650,7 @@ LayerMap::map_expr (tl::Extractor &ex, unsigned int l)
|
||||||
ld_type n;
|
ld_type n;
|
||||||
if (! ex.try_read (n) && ex.try_read_word_or_quoted (name)) {
|
if (! ex.try_read (n) && ex.try_read_word_or_quoted (name)) {
|
||||||
|
|
||||||
m_name_map.insert (std::make_pair (name, l));
|
m_name_map [name].insert (l);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
|
@ -533,7 +668,9 @@ LayerMap::map_expr (tl::Extractor &ex, unsigned int l)
|
||||||
datatype_map dm;
|
datatype_map dm;
|
||||||
for (ld_interval_vector::const_iterator di = vd.begin (); di != vd.end (); ++di) {
|
for (ld_interval_vector::const_iterator di = vd.begin (); di != vd.end (); ++di) {
|
||||||
LmapJoinOp1 op1;
|
LmapJoinOp1 op1;
|
||||||
dm.add (di->first, di->second + 1, l, op1);
|
std::set<unsigned int> single;
|
||||||
|
single.insert (l);
|
||||||
|
dm.add (di->first, di->second + 1, single, op1);
|
||||||
}
|
}
|
||||||
for (ld_interval_vector::const_iterator li = vl.begin (); li != vl.end (); ++li) {
|
for (ld_interval_vector::const_iterator li = vl.begin (); li != vl.end (); ++li) {
|
||||||
LmapJoinOp2 op2;
|
LmapJoinOp2 op2;
|
||||||
|
|
@ -548,7 +685,15 @@ LayerMap::map_expr (tl::Extractor &ex, unsigned int l)
|
||||||
LayerProperties lp;
|
LayerProperties lp;
|
||||||
lp.read (ex, true);
|
lp.read (ex, true);
|
||||||
m_target_layers[l] = lp;
|
m_target_layers[l] = lp;
|
||||||
}
|
} else if (square_bracket) {
|
||||||
|
m_target_layers[l] = LayerProperties (db::any_ld (), db::any_ld ());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (round_bracket) {
|
||||||
|
ex.expect (")");
|
||||||
|
} else if (square_bracket) {
|
||||||
|
ex.expect ("]");
|
||||||
|
}
|
||||||
|
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
throw LayerSpecFormatException (ex.skip ());
|
throw LayerSpecFormatException (ex.skip ());
|
||||||
|
|
@ -566,7 +711,7 @@ LayerMap::insert (const std::string &name, unsigned int l, const LayerProperties
|
||||||
m_target_layers[l] = *target;
|
m_target_layers[l] = *target;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_name_map.insert (std::make_pair (name, l));
|
m_name_map [name].insert (l);
|
||||||
|
|
||||||
if (l >= m_next_index) {
|
if (l >= m_next_index) {
|
||||||
m_next_index = l + 1;
|
m_next_index = l + 1;
|
||||||
|
|
@ -580,13 +725,16 @@ LayerMap::insert (const LDPair &p1, const LDPair &p2, unsigned int l, const Laye
|
||||||
m_target_layers[l] = *target;
|
m_target_layers[l] = *target;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::set<unsigned int> single;
|
||||||
|
single.insert (l);
|
||||||
|
|
||||||
// create a single-interval list for the datatype range
|
// create a single-interval list for the datatype range
|
||||||
LayerMap::datatype_map dt;
|
LayerMap::datatype_map dt;
|
||||||
LmapJoinOp1 op1;
|
LmapJoinOp1 op1;
|
||||||
if (db::is_static_ld (p1.datatype) && db::is_static_ld (p2.datatype)) {
|
if (db::is_static_ld (p1.datatype) && db::is_static_ld (p2.datatype)) {
|
||||||
dt.add (p1.datatype, p2.datatype + 1, l, op1);
|
dt.add (p1.datatype, p2.datatype + 1, single, op1);
|
||||||
} else {
|
} else {
|
||||||
dt.add (0, std::numeric_limits<ld_type>::max (), l, op1);
|
dt.add (0, std::numeric_limits<ld_type>::max (), single, op1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// add this to the layers using the special join operator that
|
// add this to the layers using the special join operator that
|
||||||
|
|
@ -603,6 +751,117 @@ LayerMap::insert (const LDPair &p1, const LDPair &p2, unsigned int l, const Laye
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
LayerMap::unmap (const LDPair &f)
|
||||||
|
{
|
||||||
|
unmap (f, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
LayerMap::unmap (const std::string &name)
|
||||||
|
{
|
||||||
|
m_name_map.erase (name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
LayerMap::unmap (const LayerProperties &f)
|
||||||
|
{
|
||||||
|
if (f.name.empty () || is_static_ld (f.layer) || is_static_ld (f.datatype)) {
|
||||||
|
unmap (db::LDPair (f.layer, f.datatype));
|
||||||
|
}
|
||||||
|
if (! f.name.empty ()) {
|
||||||
|
unmap (f.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
LayerMap::unmap (const LDPair &p1, const LDPair &p2)
|
||||||
|
{
|
||||||
|
if (m_ld_map.begin () == m_ld_map.end ()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LmapEraseDatatypeInterval op (p1.datatype, p2.datatype);
|
||||||
|
if (db::is_static_ld (p1.layer) && db::is_static_ld (p2.layer)) {
|
||||||
|
m_ld_map.add (p1.layer, p2.layer + 1, LayerMap::datatype_map (), op);
|
||||||
|
} else {
|
||||||
|
m_ld_map.add (m_ld_map.begin ()->first.first, m_ld_map.end ()->first.second, LayerMap::datatype_map (), op);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
LayerMap::unmap_expr (const std::string &expr)
|
||||||
|
{
|
||||||
|
tl::Extractor ex (expr.c_str ());
|
||||||
|
unmap_expr (ex);
|
||||||
|
ex.expect_end ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
LayerMap::unmap_expr (tl::Extractor &ex)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
|
||||||
|
bool round_bracket = false, square_bracket = false;
|
||||||
|
if (ex.test ("(")) {
|
||||||
|
round_bracket = true;
|
||||||
|
} else if (ex.test ("[")) {
|
||||||
|
square_bracket = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
|
||||||
|
tl::Extractor ex_saved = ex;
|
||||||
|
|
||||||
|
std::string name;
|
||||||
|
ld_type n;
|
||||||
|
if (! ex.try_read (n) && ex.try_read_word_or_quoted (name)) {
|
||||||
|
|
||||||
|
m_name_map.erase (name);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
ex = ex_saved;
|
||||||
|
ld_interval_vector vl, vd;
|
||||||
|
|
||||||
|
parse_intervals (ex, vl);
|
||||||
|
|
||||||
|
if (ex.test ("/")) {
|
||||||
|
parse_intervals (ex, vd);
|
||||||
|
} else {
|
||||||
|
vd.push_back (ld_interval (0, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (ld_interval_vector::const_iterator li = vl.begin (); li != vl.end (); ++li) {
|
||||||
|
for (ld_interval_vector::const_iterator di = vd.begin (); di != vd.end (); ++di) {
|
||||||
|
unmap (LDPair (li->first, di->first), LDPair (li->second, di->second));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} while (ex.test (";") || ex.test (","));
|
||||||
|
|
||||||
|
if (ex.test (":")) {
|
||||||
|
// ignore target layers
|
||||||
|
LayerProperties lp;
|
||||||
|
lp.read (ex, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (round_bracket) {
|
||||||
|
ex.expect (")");
|
||||||
|
} else if (square_bracket) {
|
||||||
|
ex.expect ("]");
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (...) {
|
||||||
|
throw LayerSpecFormatException (ex.skip ());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
LayerMap::clear ()
|
LayerMap::clear ()
|
||||||
{
|
{
|
||||||
|
|
@ -646,6 +905,26 @@ LayerMap::to_string_file_format () const
|
||||||
return os.str ();
|
return os.str ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
LayerMap::add_expr (const std::string &expr, unsigned int l)
|
||||||
|
{
|
||||||
|
tl::Extractor ex (expr.c_str ());
|
||||||
|
add_expr (ex, l);
|
||||||
|
ex.expect_end ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
LayerMap::add_expr (tl::Extractor &ex, unsigned int l)
|
||||||
|
{
|
||||||
|
if (ex.test ("+")) {
|
||||||
|
mmap_expr (ex, l);
|
||||||
|
} else if (ex.test ("-")) {
|
||||||
|
unmap_expr (ex);
|
||||||
|
} else {
|
||||||
|
map_expr (ex, l);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
db::LayerMap
|
db::LayerMap
|
||||||
LayerMap::from_string_file_format (const std::string &s)
|
LayerMap::from_string_file_format (const std::string &s)
|
||||||
{
|
{
|
||||||
|
|
@ -668,7 +947,7 @@ LayerMap::from_string_file_format (const std::string &s)
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
if (! ex.at_end ()) {
|
if (! ex.at_end ()) {
|
||||||
lm.map_expr (ex, l);
|
lm.add_expr (ex, l);
|
||||||
if (ex.test ("#") || ex.test ("//")) {
|
if (ex.test ("#") || ex.test ("//")) {
|
||||||
// ignore comments
|
// ignore comments
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -703,7 +982,7 @@ namespace tl
|
||||||
while (! ex.test (")") && ! ex.at_end ()) {
|
while (! ex.test (")") && ! ex.at_end ()) {
|
||||||
std::string m;
|
std::string m;
|
||||||
ex.read_word_or_quoted (m);
|
ex.read_word_or_quoted (m);
|
||||||
t.map_expr (m, l);
|
t.add_expr (m, l);
|
||||||
++l;
|
++l;
|
||||||
ex.test (";");
|
ex.test (";");
|
||||||
}
|
}
|
||||||
|
|
@ -723,7 +1002,7 @@ namespace tl
|
||||||
while (! ex.test (")") && ! ex.at_end ()) {
|
while (! ex.test (")") && ! ex.at_end ()) {
|
||||||
std::string m;
|
std::string m;
|
||||||
ex.read_word_or_quoted (m);
|
ex.read_word_or_quoted (m);
|
||||||
t.map_expr (m, l);
|
t.add_expr (m, l);
|
||||||
++l;
|
++l;
|
||||||
ex.test (";");
|
ex.test (";");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
namespace db
|
namespace db
|
||||||
{
|
{
|
||||||
|
|
@ -161,6 +162,15 @@ struct DB_PUBLIC LDPair
|
||||||
* and effectively rename a layer or add layer name information to
|
* and effectively rename a layer or add layer name information to
|
||||||
* a GDS layer/datatype layer.
|
* a GDS layer/datatype layer.
|
||||||
*
|
*
|
||||||
|
* "Unmapping" can be used to create "holes" in ranges of layers.
|
||||||
|
* For example, by first mapping layers 1 to 100, datatype 0 and then
|
||||||
|
* unmapping layer 50, datatype 0, the layers 1 to 49 and 51 to 100, datatype 0
|
||||||
|
* are mapped.
|
||||||
|
*
|
||||||
|
* The layer map supports multi-mapping. That is, one input layer is
|
||||||
|
* mapped to multiple target layers. It also supports merging but
|
||||||
|
* mapping different input layers to a single target layer.
|
||||||
|
*
|
||||||
* A layer map object can be used as a standalone object or in
|
* A layer map object can be used as a standalone object or in
|
||||||
* conjunction with a layout object. As a standalone object, the
|
* conjunction with a layout object. As a standalone object, the
|
||||||
* logical layers (indexes) are simply consecutive numbers.
|
* logical layers (indexes) are simply consecutive numbers.
|
||||||
|
|
@ -178,24 +188,52 @@ class DB_PUBLIC LayerMap
|
||||||
: public gsi::ObjectBase
|
: public gsi::ObjectBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef tl::interval_map<ld_type, unsigned int> datatype_map;
|
typedef tl::interval_map<ld_type, std::set<unsigned int> > datatype_map;
|
||||||
typedef tl::interval_map<ld_type, datatype_map> ld_map;
|
typedef tl::interval_map<ld_type, datatype_map> ld_map;
|
||||||
typedef ld_map::const_iterator const_iterator_layers;
|
typedef ld_map::const_iterator const_iterator_layers;
|
||||||
typedef datatype_map::const_iterator const_iterator_datatypes;
|
typedef datatype_map::const_iterator const_iterator_datatypes;
|
||||||
typedef std::map<std::string, unsigned int>::const_iterator const_iterator_names;
|
typedef std::map<std::string, std::set<unsigned int> >::const_iterator const_iterator_names;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The constructor for an empty map
|
* @brief The constructor for an empty map
|
||||||
*/
|
*/
|
||||||
LayerMap ();
|
LayerMap ();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @brief Returns the first logical layer for a given layer specification
|
||||||
|
*/
|
||||||
|
template <class L>
|
||||||
|
std::pair<bool, unsigned int> first_logical (const L &p) const
|
||||||
|
{
|
||||||
|
std::set<unsigned int> r = logical (p);
|
||||||
|
if (r.empty ()) {
|
||||||
|
return std::make_pair (false, 0);
|
||||||
|
} else {
|
||||||
|
return std::make_pair (true, *r.begin ());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns the first logical layer for a given layer specification
|
||||||
|
*/
|
||||||
|
template <class L>
|
||||||
|
std::pair<bool, unsigned int> first_logical (const L &p, db::Layout &layout) const
|
||||||
|
{
|
||||||
|
std::set<unsigned int> r = logical (p, layout);
|
||||||
|
if (r.empty ()) {
|
||||||
|
return std::make_pair (false, 0);
|
||||||
|
} else {
|
||||||
|
return std::make_pair (true, *r.begin ());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
* @brief Query a layer mapping
|
* @brief Query a layer mapping
|
||||||
*
|
*
|
||||||
* @return A pair telling if the layer is mapped (first=true) and
|
* @return A pair telling if the layer is mapped (first=true) and
|
||||||
* the logical layer mapped (second) if this is the case.
|
* the logical layer mapped (second) if this is the case.
|
||||||
*/
|
*/
|
||||||
std::pair<bool, unsigned int> logical (const LDPair &p) const;
|
std::set<unsigned int> logical (const LDPair &p) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Query a layer mapping from a name
|
* @brief Query a layer mapping from a name
|
||||||
|
|
@ -203,7 +241,7 @@ public:
|
||||||
* @return A pair telling if the layer is mapped (first=true) and
|
* @return A pair telling if the layer is mapped (first=true) and
|
||||||
* the logical layer mapped (second) if this is the case.
|
* the logical layer mapped (second) if this is the case.
|
||||||
*/
|
*/
|
||||||
std::pair<bool, unsigned int> logical (const std::string &name) const;
|
std::set<unsigned int> logical (const std::string &name) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Query a layer mapping from a name or LDPair
|
* @brief Query a layer mapping from a name or LDPair
|
||||||
|
|
@ -213,7 +251,7 @@ public:
|
||||||
*
|
*
|
||||||
* @param p The layer that is looked for
|
* @param p The layer that is looked for
|
||||||
*/
|
*/
|
||||||
std::pair<bool, unsigned int> logical (const db::LayerProperties &p) const;
|
std::set<unsigned int> logical (const db::LayerProperties &p) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Query or install a layer mapping from a name or LDPair
|
* @brief Query or install a layer mapping from a name or LDPair
|
||||||
|
|
@ -227,14 +265,29 @@ public:
|
||||||
* the logical layers are placeholder values which will be replaced by
|
* the logical layers are placeholder values which will be replaced by
|
||||||
* true layers during this method if a new layer is requested.
|
* true layers during this method if a new layer is requested.
|
||||||
*/
|
*/
|
||||||
std::pair<bool, unsigned int> logical (const db::LayerProperties &p, db::Layout &layout) const;
|
std::set<unsigned int> logical (const db::LayerProperties &p, db::Layout &layout) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Query or install a layer mapping from a LDPair
|
* @brief Query or install a layer mapping from a LDPair
|
||||||
*
|
*
|
||||||
* See the version for LayerProperties about details.
|
* See the version for LayerProperties about details.
|
||||||
*/
|
*/
|
||||||
std::pair<bool, unsigned int> logical (const db::LDPair &p, db::Layout &layout) const;
|
std::set<unsigned int> logical (const db::LDPair &p, db::Layout &layout) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns a value indicating whether a layer (given by layer/datatype) is mapped
|
||||||
|
*/
|
||||||
|
bool is_mapped (const LDPair &p) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns a value indicating whether the given named layer is mapped
|
||||||
|
*/
|
||||||
|
bool is_mapped (const std::string &name) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns a value indicating whether a layer is mapped
|
||||||
|
*/
|
||||||
|
bool is_mapped (const db::LayerProperties &p) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Gets the target layer for a given logical layer
|
* @brief Gets the target layer for a given logical layer
|
||||||
|
|
@ -270,17 +323,81 @@ public:
|
||||||
std::vector<unsigned int> get_layers () const;
|
std::vector<unsigned int> get_layers () const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Map a ldpair to a logical layer
|
* @brief Single-map a physical to a logical layer
|
||||||
|
*
|
||||||
|
* "Single-mapping" substitutes a layer mapping. "Multimapping" (mmap_..)
|
||||||
|
* adds to a given mapping and allows generating 1:n mappings (m:n in fact).
|
||||||
*/
|
*/
|
||||||
void map (const LDPair &p, unsigned int l);
|
template <class S>
|
||||||
|
void map (const S &p, unsigned int l)
|
||||||
|
{
|
||||||
|
unmap (p);
|
||||||
|
mmap (p, l);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Map a name to a logical layer
|
* @brief Single-map a physical to a logical layer with a target layer
|
||||||
*/
|
*/
|
||||||
void map (const std::string &name, unsigned int l);
|
template <class S>
|
||||||
|
void map (const S &p, unsigned int l, const LayerProperties &t)
|
||||||
|
{
|
||||||
|
unmap (p);
|
||||||
|
mmap (p, l, t);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Map a name or LDPair to a logical layer
|
* @brief Single-map a physical layer interval with a target layer
|
||||||
|
*/
|
||||||
|
void map (const LDPair &p1, const LDPair &p2, unsigned int l)
|
||||||
|
{
|
||||||
|
unmap (p1, p2);
|
||||||
|
mmap (p1, p2, l);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Single-map a physical layer interval with a target layer
|
||||||
|
*/
|
||||||
|
void map (const LDPair &p1, const LDPair &p2, unsigned int l, const LayerProperties &t)
|
||||||
|
{
|
||||||
|
unmap (p1, p2);
|
||||||
|
mmap (p1, p2, l, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Single-map a physical layer interval (given by an expression)
|
||||||
|
*/
|
||||||
|
void map_expr (const std::string &expr, unsigned int l)
|
||||||
|
{
|
||||||
|
unmap_expr (expr);
|
||||||
|
mmap_expr (expr, l);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Same a map_expr with a string argument but taking the expression for a tl::Extractor
|
||||||
|
*/
|
||||||
|
void map_expr (tl::Extractor &ex, unsigned int l)
|
||||||
|
{
|
||||||
|
tl::Extractor ex1 = ex;
|
||||||
|
unmap_expr (ex1);
|
||||||
|
mmap_expr (ex, l);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Multi-map a ldpair to a logical layer
|
||||||
|
*
|
||||||
|
* "Multimapping" will not substitute but add to the mapping.
|
||||||
|
*/
|
||||||
|
void mmap (const LDPair &p, unsigned int l);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Multi-map a name to a logical layer
|
||||||
|
*
|
||||||
|
* "Multimapping" will not substitute but add to the mapping.
|
||||||
|
*/
|
||||||
|
void mmap (const std::string &name, unsigned int l);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Multi-map a name or LDPair to a logical layer
|
||||||
*
|
*
|
||||||
* The algorithm chooses the LDPair from the LayerProperties structure and/or
|
* The algorithm chooses the LDPair from the LayerProperties structure and/or
|
||||||
* the name if no LDPair is given. If the source LayerProperties structure does
|
* the name if no LDPair is given. If the source LayerProperties structure does
|
||||||
|
|
@ -289,26 +406,26 @@ public:
|
||||||
* @param f The source (where to derive the match expression from)
|
* @param f The source (where to derive the match expression from)
|
||||||
* @param l The logical layer to map to the match expression
|
* @param l The logical layer to map to the match expression
|
||||||
*/
|
*/
|
||||||
void map (const LayerProperties &f, unsigned int l);
|
void mmap (const LayerProperties &f, unsigned int l);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Map a ldpair to a logical layer with a target layer
|
* @brief Multi-map a ldpair to a logical layer with a target layer
|
||||||
*
|
*
|
||||||
* The target layer specifies which layer to create for the
|
* The target layer specifies which layer to create for the
|
||||||
* corresponding input.
|
* corresponding input.
|
||||||
*/
|
*/
|
||||||
void map (const LDPair &p, unsigned int l, const LayerProperties &t);
|
void mmap (const LDPair &p, unsigned int l, const LayerProperties &t);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Map a name to a logical layer with a target layer
|
* @brief Multi-map a name to a logical layer with a target layer
|
||||||
*
|
*
|
||||||
* The target layer specifies which layer to create for the
|
* The target layer specifies which layer to create for the
|
||||||
* corresponding input.
|
* corresponding input.
|
||||||
*/
|
*/
|
||||||
void map (const std::string &name, unsigned int l, const LayerProperties &t);
|
void mmap (const std::string &name, unsigned int l, const LayerProperties &t);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Map a name or LDPair to a logical layer with a target layer
|
* @brief Multi-map a name or LDPair to a logical layer with a target layer
|
||||||
*
|
*
|
||||||
* The algorithm chooses the LDPair from the LayerProperties structure or
|
* The algorithm chooses the LDPair from the LayerProperties structure or
|
||||||
* the name if no LDPair is given. If the source LayerProperties structure does
|
* the name if no LDPair is given. If the source LayerProperties structure does
|
||||||
|
|
@ -318,23 +435,23 @@ public:
|
||||||
* @param l The logical layer to map to the match expression
|
* @param l The logical layer to map to the match expression
|
||||||
* @param t The target layer to use for the mapped layer
|
* @param t The target layer to use for the mapped layer
|
||||||
*/
|
*/
|
||||||
void map (const LayerProperties &f, unsigned int l, const LayerProperties &t);
|
void mmap (const LayerProperties &f, unsigned int l, const LayerProperties &t);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Map a range of ldpair's to a logical layer
|
* @brief Multi-map a range of ldpair's to a logical layer
|
||||||
*
|
*
|
||||||
* The range is given by two pairs p1,p2. The layers
|
* The range is given by two pairs p1,p2. The layers
|
||||||
* mapped are [p1.l,p2.l], the datatypes mapped are [p1.d,p2.d].
|
* mapped are [p1.l,p2.l], the datatypes mapped are [p1.d,p2.d].
|
||||||
*/
|
*/
|
||||||
void map (const LDPair &p1, const LDPair &p2, unsigned int l);
|
void mmap (const LDPair &p1, const LDPair &p2, unsigned int l);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Map a range of ldpair's to a logical layer with a target layer
|
* @brief Multi-map a range of ldpair's to a logical layer with a target layer
|
||||||
*
|
*
|
||||||
* The range is given by two pairs p1,p2. The layers
|
* The range is given by two pairs p1,p2. The layers
|
||||||
* mapped are [p1.l,p2.l], the datatypes mapped are [p1.d,p2.d].
|
* mapped are [p1.l,p2.l], the datatypes mapped are [p1.d,p2.d].
|
||||||
*/
|
*/
|
||||||
void map (const LDPair &p1, const LDPair &p2, unsigned int l, const LayerProperties &t);
|
void mmap (const LDPair &p1, const LDPair &p2, unsigned int l, const LayerProperties &t);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Map a range given by a string expression to a logical layer
|
* @brief Map a range given by a string expression to a logical layer
|
||||||
|
|
@ -364,12 +481,61 @@ public:
|
||||||
* This method will throw a LayerSpecFormatException if
|
* This method will throw a LayerSpecFormatException if
|
||||||
* something is wrong with the format string
|
* something is wrong with the format string
|
||||||
*/
|
*/
|
||||||
void map_expr (const std::string &expr, unsigned int l);
|
void mmap_expr (const std::string &expr, unsigned int l);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Same a map_expr with a string argument but taking the expression for a tl::Extractor
|
* @brief Same a map_expr with a string argument but taking the expression for a tl::Extractor
|
||||||
*/
|
*/
|
||||||
void map_expr (tl::Extractor &ex, unsigned int l);
|
void mmap_expr (tl::Extractor &ex, unsigned int l);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Unmaps a LDPair
|
||||||
|
*/
|
||||||
|
void unmap (const LDPair &f);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Unmaps the layer with the given name
|
||||||
|
*/
|
||||||
|
void unmap (const std::string &name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Unmaps a layer with the given layer properties
|
||||||
|
*/
|
||||||
|
void unmap (const LayerProperties &f);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Removes any mapping for a range of ldpair's
|
||||||
|
*
|
||||||
|
* The range is given by two pairs p1,p2. The layers
|
||||||
|
* between [p1.l,p2.l] and with datatypes between [p1.d,p2.d] are unmapped.
|
||||||
|
*/
|
||||||
|
void unmap (const LDPair &p1, const LDPair &p2);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Removes any mapping for the layers given by the expression
|
||||||
|
*/
|
||||||
|
void unmap_expr (const std::string &expr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Removes any mapping for the layers given by the expression
|
||||||
|
*/
|
||||||
|
void unmap_expr (tl::Extractor &ex);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Generic expression mapping
|
||||||
|
*
|
||||||
|
* This generic mapping function takes a mapping expression. If it starts with "+",
|
||||||
|
* "mmap" is used, if it starts with "-", "unmap" is used. Otherwise, "map" is used.
|
||||||
|
*/
|
||||||
|
void add_expr (const std::string &expr, unsigned int l);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Generic expression mapping
|
||||||
|
*
|
||||||
|
* This generic mapping function takes a mapping expression. If it starts with "+",
|
||||||
|
* "mmap" is used, if it starts with "-", "unmap" is used. Otherwise, "map" is used.
|
||||||
|
*/
|
||||||
|
void add_expr (tl::Extractor &ex, unsigned int l);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Prepares a layer mapping object for reading
|
* @brief Prepares a layer mapping object for reading
|
||||||
|
|
@ -454,7 +620,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ld_map m_ld_map;
|
ld_map m_ld_map;
|
||||||
std::map<std::string, unsigned int> m_name_map;
|
std::map<std::string, std::set<unsigned int> > m_name_map;
|
||||||
std::map<unsigned int, LayerProperties> m_target_layers;
|
std::map<unsigned int, LayerProperties> m_target_layers;
|
||||||
std::vector<LayerProperties> m_placeholders;
|
std::vector<LayerProperties> m_placeholders;
|
||||||
unsigned int m_next_index;
|
unsigned int m_next_index;
|
||||||
|
|
@ -462,12 +628,12 @@ private:
|
||||||
void insert (const LDPair &p1, const LDPair &p2, unsigned int l, const LayerProperties *t);
|
void insert (const LDPair &p1, const LDPair &p2, unsigned int l, const LayerProperties *t);
|
||||||
void insert (const std::string &name, unsigned int l, const LayerProperties *t);
|
void insert (const std::string &name, unsigned int l, const LayerProperties *t);
|
||||||
|
|
||||||
std::pair<bool, unsigned int> logical_internal (const LDPair &p, bool allow_placeholder) const;
|
std::set<unsigned int> logical_internal (const LDPair &p, bool allow_placeholder) const;
|
||||||
std::pair<bool, unsigned int> logical_internal (const std::string &name, bool allow_placeholder) const;
|
std::set<unsigned int> logical_internal (const std::string &name, bool allow_placeholder) const;
|
||||||
std::pair<bool, unsigned int> logical_internal (const db::LayerProperties &p, bool allow_placeholder) const;
|
std::set<unsigned int> logical_internal (const db::LayerProperties &p, bool allow_placeholder) const;
|
||||||
|
|
||||||
std::pair<bool, unsigned int> substitute_placeholder (const db::LayerProperties &p, unsigned int ph, db::Layout &layout);
|
std::set<unsigned int> substitute_placeholder (const db::LayerProperties &p, const std::set<unsigned int> &ph, db::Layout &layout);
|
||||||
bool is_placeholder (unsigned int l) const;
|
bool is_placeholder (const std::set<unsigned int> &l) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -85,12 +85,12 @@ static void set_properties_enabled (db::LoadLayoutOptions *options, bool l)
|
||||||
options->get_options<db::CommonReaderOptions> ().enable_properties = l;
|
options->get_options<db::CommonReaderOptions> ().enable_properties = l;
|
||||||
}
|
}
|
||||||
|
|
||||||
static db::CommonReader::CellConflictResolution get_cell_conflict_resolution (const db::LoadLayoutOptions *options)
|
static db::CellConflictResolution get_cell_conflict_resolution (const db::LoadLayoutOptions *options)
|
||||||
{
|
{
|
||||||
return options->get_options<db::CommonReaderOptions> ().cell_conflict_resolution;
|
return options->get_options<db::CommonReaderOptions> ().cell_conflict_resolution;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_cell_conflict_resolution (db::LoadLayoutOptions *options, db::CommonReader::CellConflictResolution cc)
|
static void set_cell_conflict_resolution (db::LoadLayoutOptions *options, db::CellConflictResolution cc)
|
||||||
{
|
{
|
||||||
options->get_options<db::CommonReaderOptions> ().cell_conflict_resolution = cc;
|
options->get_options<db::CommonReaderOptions> ().cell_conflict_resolution = cc;
|
||||||
}
|
}
|
||||||
|
|
@ -188,18 +188,18 @@ gsi::ClassExt<db::LoadLayoutOptions> common_reader_options (
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
gsi::EnumIn<db::LoadLayoutOptions, db::CommonReader::CellConflictResolution> decl_dbCommonReader_CellConflictResolution ("db", "CellConflictResolution",
|
gsi::EnumIn<db::LoadLayoutOptions, db::CellConflictResolution> decl_dbCommonReader_CellConflictResolution ("db", "CellConflictResolution",
|
||||||
gsi::enum_const ("AddToCell", db::CommonReader::AddToCell,
|
gsi::enum_const ("AddToCell", db::AddToCell,
|
||||||
"@brief Add content to existing cell\n"
|
"@brief Add content to existing cell\n"
|
||||||
"This is the mode use in before version 0.27. Content of new cells is simply added to existing cells with the same name."
|
"This is the mode use in before version 0.27. Content of new cells is simply added to existing cells with the same name."
|
||||||
) +
|
) +
|
||||||
gsi::enum_const ("OverwriteCell", db::CommonReader::OverwriteCell,
|
gsi::enum_const ("OverwriteCell", db::OverwriteCell,
|
||||||
"@brief The old cell is overwritten entirely (including child cells which are not used otherwise)\n"
|
"@brief The old cell is overwritten entirely (including child cells which are not used otherwise)\n"
|
||||||
) +
|
) +
|
||||||
gsi::enum_const ("SkipNewCell", db::CommonReader::SkipNewCell,
|
gsi::enum_const ("SkipNewCell", db::SkipNewCell,
|
||||||
"@brief The new cell is skipped entirely (including child cells which are not used otherwise)\n"
|
"@brief The new cell is skipped entirely (including child cells which are not used otherwise)\n"
|
||||||
) +
|
) +
|
||||||
gsi::enum_const ("RenameCell", db::CommonReader::RenameCell,
|
gsi::enum_const ("RenameCell", db::RenameCell,
|
||||||
"@brief The new cell will be renamed to become unique\n"
|
"@brief The new cell will be renamed to become unique\n"
|
||||||
),
|
),
|
||||||
"@brief This enum specifies how cell conflicts are handled if a layout read into another layout and a cell name conflict arises. "
|
"@brief This enum specifies how cell conflicts are handled if a layout read into another layout and a cell name conflict arises. "
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@
|
||||||
#include "dbLayoutUtils.h"
|
#include "dbLayoutUtils.h"
|
||||||
#include "dbLayerMapping.h"
|
#include "dbLayerMapping.h"
|
||||||
#include "dbCellMapping.h"
|
#include "dbCellMapping.h"
|
||||||
|
#include "dbTechnology.h"
|
||||||
#include "tlStream.h"
|
#include "tlStream.h"
|
||||||
|
|
||||||
namespace gsi
|
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)
|
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) {
|
if (! lib) {
|
||||||
return 0;
|
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)
|
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) {
|
if (! lib) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -988,6 +989,21 @@ Class<db::Layout> decl_Layout ("db", "Layout",
|
||||||
"\n"
|
"\n"
|
||||||
"This method has been introduced in version 0.25."
|
"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,
|
gsi::method ("is_editable?", &db::Layout::is_editable,
|
||||||
"@brief Returns a value indicating whether the layout is editable.\n"
|
"@brief Returns a value indicating whether the layout is editable.\n"
|
||||||
"@return True, if 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 ();
|
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 ()
|
static std::vector<std::string> library_names ()
|
||||||
|
|
@ -57,6 +62,15 @@ static std::vector<std::string> library_names ()
|
||||||
return r;
|
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)
|
static void register_lib (db::Library *lib, const std::string &name)
|
||||||
{
|
{
|
||||||
lib->set_name (name);
|
lib->set_name (name);
|
||||||
|
|
@ -110,22 +124,45 @@ LibraryClass decl_Library ("db", "Library",
|
||||||
gsi::constructor ("new", &new_lib,
|
gsi::constructor ("new", &new_lib,
|
||||||
"@brief Creates a new, empty library"
|
"@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"
|
"@brief Gets a library by name\n"
|
||||||
"Returns the library object for the given name. If the name is not a valid\n"
|
"Returns the library object for the given name. If the name is not a valid\n"
|
||||||
"library name, nil is returned.\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,
|
gsi::method ("library_names", &library_names,
|
||||||
"@brief Returns a list of the names of all libraries registered in the system.\n"
|
"@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"),
|
gsi::method_ext ("register", ®ister_lib, gsi::arg ("name"),
|
||||||
"@brief Registers the library with the given name\n"
|
"@brief Registers the library with the given name\n"
|
||||||
"\n"
|
"\n"
|
||||||
"This method can be called in the constructor to register the library after \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"
|
"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"
|
"\n"
|
||||||
"This method will set the libraries' name.\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,
|
gsi::method_ext ("delete", &delete_lib,
|
||||||
"@brief Deletes the library\n"
|
"@brief Deletes the library\n"
|
||||||
|
|
|
||||||
|
|
@ -36,17 +36,23 @@ namespace gsi
|
||||||
static bool
|
static bool
|
||||||
lm_is_mapped (const db::LayerMap *layer_map, const db::LayerProperties &lp)
|
lm_is_mapped (const db::LayerMap *layer_map, const db::LayerProperties &lp)
|
||||||
{
|
{
|
||||||
return layer_map->logical (lp).first;
|
return layer_map->is_mapped (lp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
lm_logical (const db::LayerMap *layer_map, const db::LayerProperties &lp)
|
lm_logical (const db::LayerMap *layer_map, const db::LayerProperties &lp)
|
||||||
{
|
{
|
||||||
std::pair<bool, unsigned int> lm = layer_map->logical (lp);
|
std::set<unsigned int> lm = layer_map->logical (lp);
|
||||||
return lm.first ? int (lm.second) : -1;
|
return lm.empty () ? -1 : int (*lm.begin ());
|
||||||
}
|
}
|
||||||
|
|
||||||
static db::LayerProperties
|
static std::set<unsigned int>
|
||||||
|
lm_logicals (const db::LayerMap *layer_map, const db::LayerProperties &lp)
|
||||||
|
{
|
||||||
|
return layer_map->logical (lp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static db::LayerProperties
|
||||||
lm_mapping (const db::LayerMap *layer_map, unsigned int l)
|
lm_mapping (const db::LayerMap *layer_map, unsigned int l)
|
||||||
{
|
{
|
||||||
return layer_map->mapping (l);
|
return layer_map->mapping (l);
|
||||||
|
|
@ -82,16 +88,74 @@ namespace gsi
|
||||||
layer_map->map_expr (s, l);
|
layer_map->map_expr (s, l);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
lm_mmap (db::LayerMap *layer_map, const db::LayerProperties &lp, unsigned int l)
|
||||||
|
{
|
||||||
|
layer_map->mmap (lp, l);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
lm_mmap_with_target (db::LayerMap *layer_map, const db::LayerProperties &lp, unsigned int l, const db::LayerProperties &t)
|
||||||
|
{
|
||||||
|
layer_map->mmap (lp, l, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
lm_mmap_interval (db::LayerMap *layer_map, const db::LayerProperties &lp1, const db::LayerProperties &lp2, unsigned int l)
|
||||||
|
{
|
||||||
|
layer_map->mmap (ldpair_from_lp (lp1), ldpair_from_lp (lp2), l);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
lm_mmap_interval_with_target (db::LayerMap *layer_map, const db::LayerProperties &lp1, const db::LayerProperties &lp2, unsigned int l, const db::LayerProperties &t)
|
||||||
|
{
|
||||||
|
layer_map->mmap (ldpair_from_lp (lp1), ldpair_from_lp (lp2), l, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
lm_mmap_string (db::LayerMap *layer_map, std::string &s, unsigned int l)
|
||||||
|
{
|
||||||
|
layer_map->mmap_expr (s, l);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
lm_unmap (db::LayerMap *layer_map, const db::LayerProperties &lp)
|
||||||
|
{
|
||||||
|
layer_map->unmap (lp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
lm_unmap_interval (db::LayerMap *layer_map, const db::LayerProperties &lp1, const db::LayerProperties &lp2)
|
||||||
|
{
|
||||||
|
layer_map->unmap (ldpair_from_lp (lp1), ldpair_from_lp (lp2));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
lm_unmap_string (db::LayerMap *layer_map, std::string &s)
|
||||||
|
{
|
||||||
|
layer_map->unmap_expr (s);
|
||||||
|
}
|
||||||
|
|
||||||
Class<db::LayerMap> decl_LayerMap ("db", "LayerMap",
|
Class<db::LayerMap> decl_LayerMap ("db", "LayerMap",
|
||||||
gsi::method_ext ("is_mapped?", &lm_is_mapped, gsi::arg ("layer"),
|
gsi::method_ext ("is_mapped?", &lm_is_mapped, gsi::arg ("layer"),
|
||||||
"@brief Check, if a given physical layer is mapped\n"
|
"@brief Check, if a given physical layer is mapped\n"
|
||||||
"@param layer The physical layer specified with an \\LayerInfo object.\n"
|
"@param layer The physical layer specified with an \\LayerInfo object.\n"
|
||||||
"@return True, if the layer is mapped."
|
"@return True, if the layer is mapped."
|
||||||
) +
|
) +
|
||||||
gsi::method_ext ("logical", &lm_logical, gsi::arg ("layer"),
|
gsi::method_ext ("#logical", &lm_logical, gsi::arg ("layer"),
|
||||||
"@brief Returns the logical layer (the layer index in the layout object) for a given physical layer.n"
|
"@brief Returns the logical layer (the layer index in the layout object) for a given physical layer.n"
|
||||||
"@param layer The physical layer specified with an \\LayerInfo object.\n"
|
"@param layer The physical layer specified with an \\LayerInfo object.\n"
|
||||||
"@return The logical layer index or -1 if the layer is not mapped."
|
"@return The logical layer index or -1 if the layer is not mapped."
|
||||||
|
"\n"
|
||||||
|
"This method is deprecated with version 0.27 as in this version, layers can be mapped to multiple targets which "
|
||||||
|
"this method can't capture. Use \\logicals instead.\n"
|
||||||
|
) +
|
||||||
|
gsi::method_ext ("logicals", &lm_logicals, gsi::arg ("layer"),
|
||||||
|
"@brief Returns the logical layers for a given physical layer.n"
|
||||||
|
"@param layer The physical layer specified with an \\LayerInfo object.\n"
|
||||||
|
"@return This list of logical layers this physical layer as mapped to or empty if there is no mapping."
|
||||||
|
"\n"
|
||||||
|
"This method has been introduced in version 0.27.\n"
|
||||||
) +
|
) +
|
||||||
gsi::method ("mapping_str", &db::LayerMap::mapping_str, gsi::arg ("log_layer"),
|
gsi::method ("mapping_str", &db::LayerMap::mapping_str, gsi::arg ("log_layer"),
|
||||||
"@brief Returns the mapping string for a given logical layer\n"
|
"@brief Returns the mapping string for a given logical layer\n"
|
||||||
|
|
@ -162,11 +226,84 @@ namespace gsi
|
||||||
"separated by a hyphen. Examples are: \"1/2\", \"1-5/0\", \"1,2,5/0\",\n"
|
"separated by a hyphen. Examples are: \"1/2\", \"1-5/0\", \"1,2,5/0\",\n"
|
||||||
"\"1/5;5/6\".\n"
|
"\"1/5;5/6\".\n"
|
||||||
"\n"
|
"\n"
|
||||||
"A target layer can be specified with the \":<target>\" notation where "
|
"layer/datatype wildcards can be specified with \"*\". When \"*\" is used\n"
|
||||||
"the target is a valid layer specification string (i.e. \"1/0\").\n"
|
"for the upper limit, it is equivalent to \"all layer above\". When used\n"
|
||||||
|
"alone, it is equivalent to \"all layers\". Examples: \"1 / *\", \"* / 10-*\"\n"
|
||||||
|
"\n"
|
||||||
|
"Named layers are specified simply by specifying the name, if\n"
|
||||||
|
"necessary in single or double quotes (if the name begins with a digit or\n"
|
||||||
|
"contains non-word characters). layer/datatype and name descriptions can\n"
|
||||||
|
"be mixed, i.e. \"AA;1/5\" (meaning: name \"AA\" or layer 1/datatype 5).\n"
|
||||||
|
"\n"
|
||||||
|
"A target layer can be specified with the \":<target>\" notation, where\n"
|
||||||
|
"target is a valid string for a LayerProperties() object.\n"
|
||||||
|
"\n"
|
||||||
|
"A target can include relative layer/datatype specifications and wildcards.\n"
|
||||||
|
"For example, \"1-10/0: *+1/0\" will add 1 to the original layer number.\n"
|
||||||
|
"\"1-10/0-50: * / *\" will use the original layers.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Target mapping has been added in version 0.20.\n"
|
"Target mapping has been added in version 0.20.\n"
|
||||||
) +
|
) +
|
||||||
|
gsi::method_ext ("mmap", &lm_mmap, gsi::arg ("phys_layer"), gsi::arg ("log_layer"),
|
||||||
|
"@brief Maps a physical layer to a logical one and adds to existing mappings\n"
|
||||||
|
"\n"
|
||||||
|
"This method acts like the corresponding 'map' method, but adds the logical layer to the receivers of the "
|
||||||
|
"given physical one. Hence this method implements 1:n mapping capabilities.\n"
|
||||||
|
"For backward compatibility, 'map' still substitutes mapping.\n"
|
||||||
|
"\n"
|
||||||
|
"Multi-mapping has been added in version 0.27.\n"
|
||||||
|
) +
|
||||||
|
gsi::method_ext ("mmap", &lm_mmap_with_target, gsi::arg ("phys_layer"), gsi::arg ("log_layer"), gsi::arg ("target_layer"),
|
||||||
|
"@brief Maps a physical layer to a logical one, adds to existing mappings and specifies a target layer\n"
|
||||||
|
"\n"
|
||||||
|
"This method acts like the corresponding 'map' method, but adds the logical layer to the receivers of the "
|
||||||
|
"given physical one. Hence this method implements 1:n mapping capabilities.\n"
|
||||||
|
"For backward compatibility, 'map' still substitutes mapping.\n"
|
||||||
|
"\n"
|
||||||
|
"Multi-mapping has been added in version 0.27.\n"
|
||||||
|
) +
|
||||||
|
gsi::method_ext ("mmap", &lm_mmap_interval, gsi::arg ("pl_start"), gsi::arg ("pl_stop"), gsi::arg ("log_layer"),
|
||||||
|
"@brief Maps a physical layer from the given interval to a logical one and adds to existing mappings\n"
|
||||||
|
"\n"
|
||||||
|
"This method acts like the corresponding 'map' method, but adds the logical layer to the receivers of the "
|
||||||
|
"given physical one. Hence this method implements 1:n mapping capabilities.\n"
|
||||||
|
"For backward compatibility, 'map' still substitutes mapping.\n"
|
||||||
|
"\n"
|
||||||
|
"Multi-mapping has been added in version 0.27.\n"
|
||||||
|
) +
|
||||||
|
gsi::method_ext ("mmap", &lm_mmap_interval_with_target, gsi::arg ("pl_start"), gsi::arg ("pl_stop"), gsi::arg ("log_layer"), gsi::arg ("layer_properties"),
|
||||||
|
"@brief Maps a physical layer from the given interval to a logical one, adds to existing mappings and specifies a target layer\n"
|
||||||
|
"\n"
|
||||||
|
"This method acts like the corresponding 'map' method, but adds the logical layer to the receivers of the "
|
||||||
|
"given physical one. Hence this method implements 1:n mapping capabilities.\n"
|
||||||
|
"For backward compatibility, 'map' still substitutes mapping.\n"
|
||||||
|
"\n"
|
||||||
|
"Multi-mapping has been added in version 0.27.\n"
|
||||||
|
) +
|
||||||
|
gsi::method_ext ("mmap", &lm_mmap_string, gsi::arg ("map_expr"), gsi::arg ("log_layer"),
|
||||||
|
"@brief Maps a physical layer given by an expression to a logical one and adds to existing mappings\n"
|
||||||
|
"\n"
|
||||||
|
"This method acts like the corresponding 'map' method, but adds the logical layer to the receivers of the "
|
||||||
|
"given physical one. Hence this method implements 1:n mapping capabilities.\n"
|
||||||
|
"For backward compatibility, 'map' still substitutes mapping.\n"
|
||||||
|
"\n"
|
||||||
|
"Multi-mapping has been added in version 0.27.\n"
|
||||||
|
) +
|
||||||
|
gsi::method_ext ("unmap", &lm_unmap, gsi::arg ("phys_layer"),
|
||||||
|
"@brief Unmaps the given layer\n"
|
||||||
|
"Unmapping will remove the specific layer from the mapping. This method allows generating "
|
||||||
|
"'mapping holes' by first mapping a range and then unmapping parts of it.\n"
|
||||||
|
"\n"
|
||||||
|
"This method has been introduced in version 0.27."
|
||||||
|
) +
|
||||||
|
gsi::method_ext ("unmap", &lm_unmap_interval, gsi::arg ("pl_start"), gsi::arg ("pl_stop"),
|
||||||
|
"@brief Unmaps the layers from the given interval\n"
|
||||||
|
"This method has been introduced in version 0.27."
|
||||||
|
) +
|
||||||
|
gsi::method_ext ("unmap", &lm_unmap_string, gsi::arg ("expr"),
|
||||||
|
"@brief Unmaps the layers from the given expression\n"
|
||||||
|
"This method has been introduced in version 0.27."
|
||||||
|
) +
|
||||||
gsi::method ("clear", &db::LayerMap::clear,
|
gsi::method ("clear", &db::LayerMap::clear,
|
||||||
"@brief Clears the map\n"
|
"@brief Clears the map\n"
|
||||||
) +
|
) +
|
||||||
|
|
@ -221,7 +358,28 @@ namespace gsi
|
||||||
"ly.read(\"input.gds\", lo)\n"
|
"ly.read(\"input.gds\", lo)\n"
|
||||||
"@/code\n"
|
"@/code\n"
|
||||||
"\n"
|
"\n"
|
||||||
"The LayerMap class has been introduced in version 0.18."
|
"1:n mapping is supported: a physical layer can be mapped to multiple logical layers using 'mmap' instead of 'map'. When using this variant, "
|
||||||
|
"mapping acts additive.\n"
|
||||||
|
"The following example will map layer 1, datatypes 0 to 255 to logical layer 0, and layer 1, datatype 17 to logical layers "
|
||||||
|
"0 plus 1:"
|
||||||
|
"\n"
|
||||||
|
"@code"
|
||||||
|
"lm = RBA::LayerMap::new\n"
|
||||||
|
"lm.map(\"1/0-255\", 0) # (can be 'mmap' too)\n"
|
||||||
|
"lm.mmap(\"1/17\", 1)\n"
|
||||||
|
"@/code\n"
|
||||||
|
"\n"
|
||||||
|
"'unmapping' allows removing a mapping. This allows creating 'holes' in mapping ranges. The followin example maps "
|
||||||
|
"layer 1, datatypes 0 to 16 and 18 to 255 to logical layer 0:"
|
||||||
|
"\n"
|
||||||
|
"@code"
|
||||||
|
"lm = RBA::LayerMap::new\n"
|
||||||
|
"lm.map(\"1/0-255\", 0)\n"
|
||||||
|
"lm.unmap(\"1/17\")\n"
|
||||||
|
"@/code\n"
|
||||||
|
"\n"
|
||||||
|
"The LayerMap class has been introduced in version 0.18. Target layer have been introduced in version 0.20. "
|
||||||
|
"1:n mapping and unmapping has been introduced in version 0.27."
|
||||||
);
|
);
|
||||||
|
|
||||||
// NOTE: the contribution comes from format specific extensions.
|
// NOTE: the contribution comes from format specific extensions.
|
||||||
|
|
|
||||||
|
|
@ -20,9 +20,12 @@
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#include "dbLayout.h"
|
#include "dbLayout.h"
|
||||||
|
#include "dbLibraryManager.h"
|
||||||
|
#include "dbLibrary.h"
|
||||||
|
#include "dbColdProxy.h"
|
||||||
|
#include "dbLibraryProxy.h"
|
||||||
|
#include "dbTextWriter.h"
|
||||||
#include "tlString.h"
|
#include "tlString.h"
|
||||||
#include "tlUnitTest.h"
|
#include "tlUnitTest.h"
|
||||||
|
|
||||||
|
|
@ -464,3 +467,176 @@ TEST(4)
|
||||||
prop_id = g.properties_repository ().properties_id (ps);
|
prop_id = g.properties_repository ().properties_id (ps);
|
||||||
EXPECT_EQ (el.property_ids_dirty, true);
|
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");
|
||||||
|
|
||||||
|
if (l.is_editable ()) {
|
||||||
|
|
||||||
|
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");
|
||||||
|
|
||||||
|
if (l.is_editable ()) {
|
||||||
|
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,86 @@ TEST(3)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(4)
|
||||||
|
{
|
||||||
|
tl::weak_ptr<LIBT_A> lib_a1 (new LIBT_A ());
|
||||||
|
lib_a1->add_technology ("X");
|
||||||
|
|
||||||
|
tl::weak_ptr<LIBT_A> lib_a2 (new LIBT_A ());
|
||||||
|
lib_a2->add_technology ("Y");
|
||||||
|
|
||||||
|
tl::weak_ptr<LIBT_A> lib_a3 (new LIBT_A ());
|
||||||
|
lib_a3->add_technology ("X");
|
||||||
|
|
||||||
|
tl::weak_ptr<LIBT_A> lib_a4 (new LIBT_A ());
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").first, false);
|
||||||
|
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Z").first, false);
|
||||||
|
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").first, false);
|
||||||
|
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").first, false);
|
||||||
|
|
||||||
|
db::LibraryManager::instance ().register_lib (lib_a1.get ());
|
||||||
|
|
||||||
|
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").first, false);
|
||||||
|
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Z").first, false);
|
||||||
|
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").first, false);
|
||||||
|
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 ());
|
||||||
|
|
||||||
|
db::LibraryManager::instance ().register_lib (lib_a2.get ());
|
||||||
|
|
||||||
|
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").first, false);
|
||||||
|
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Z").first, false);
|
||||||
|
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").first, false);
|
||||||
|
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 ());
|
||||||
|
|
||||||
|
db::LibraryManager::instance ().register_lib (lib_a3.get ());
|
||||||
|
// lib_a3 replaces lib_a1
|
||||||
|
EXPECT_EQ (lib_a1.get () == 0, true);
|
||||||
|
|
||||||
|
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").first, false);
|
||||||
|
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Z").first, false);
|
||||||
|
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").first, false);
|
||||||
|
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 ());
|
||||||
|
|
||||||
|
db::LibraryManager::instance ().register_lib (lib_a4.get ());
|
||||||
|
|
||||||
|
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").first, true);
|
||||||
|
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").second, lib_a4->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_a4->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 ());
|
||||||
|
|
||||||
|
// because we switch to editable mode in between we have to clear the repository explicitly. Otherwise it's being cleared
|
||||||
|
// on next entry of TEST which will cause a segmentation fault if editable mode is different then.
|
||||||
|
if (lib_a1.get ()) { db::LibraryManager::instance ().delete_lib (lib_a1.get ()); }
|
||||||
|
if (lib_a2.get ()) { db::LibraryManager::instance ().delete_lib (lib_a2.get ()); }
|
||||||
|
if (lib_a3.get ()) { db::LibraryManager::instance ().delete_lib (lib_a3.get ()); }
|
||||||
|
if (lib_a4.get ()) { db::LibraryManager::instance ().delete_lib (lib_a4.get ()); }
|
||||||
|
|
||||||
|
} catch (...) {
|
||||||
|
|
||||||
|
// because we switch to editable mode in between we have to clear the repository explicitly. Otherwise it's being cleared
|
||||||
|
// on next entry of TEST which will cause a segmentation fault if editable mode is different then.
|
||||||
|
if (lib_a1.get ()) { db::LibraryManager::instance ().delete_lib (lib_a1.get ()); }
|
||||||
|
if (lib_a2.get ()) { db::LibraryManager::instance ().delete_lib (lib_a2.get ()); }
|
||||||
|
if (lib_a3.get ()) { db::LibraryManager::instance ().delete_lib (lib_a3.get ()); }
|
||||||
|
if (lib_a4.get ()) { db::LibraryManager::instance ().delete_lib (lib_a4.get ()); }
|
||||||
|
throw;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,16 +29,16 @@ TEST(1)
|
||||||
db::LayerMap lm;
|
db::LayerMap lm;
|
||||||
|
|
||||||
lm.map (db::LDPair (1, 5), 17);
|
lm.map (db::LDPair (1, 5), 17);
|
||||||
EXPECT_EQ (lm.logical (db::LDPair (1, 6)).first, false);
|
EXPECT_EQ (lm.first_logical (db::LDPair (1, 6)).first, false);
|
||||||
EXPECT_EQ (lm.logical (db::LDPair (1, 5)).first, true);
|
EXPECT_EQ (lm.first_logical (db::LDPair (1, 5)).first, true);
|
||||||
EXPECT_EQ (lm.logical (db::LDPair (1, 5)).second, (unsigned int) 17);
|
EXPECT_EQ (lm.first_logical (db::LDPair (1, 5)).second, (unsigned int) 17);
|
||||||
|
|
||||||
lm.map (db::LDPair (1, 0), db::LDPair (5,0), 18);
|
lm.map (db::LDPair (1, 0), db::LDPair (5,0), 18);
|
||||||
EXPECT_EQ (lm.logical (db::LDPair (2, 0)).first, true);
|
EXPECT_EQ (lm.first_logical (db::LDPair (2, 0)).first, true);
|
||||||
EXPECT_EQ (lm.logical (db::LDPair (2, 0)).second, (unsigned int) 18);
|
EXPECT_EQ (lm.first_logical (db::LDPair (2, 0)).second, (unsigned int) 18);
|
||||||
EXPECT_EQ (lm.logical (db::LDPair (0, 0)).first, false);
|
EXPECT_EQ (lm.first_logical (db::LDPair (0, 0)).first, false);
|
||||||
|
|
||||||
EXPECT_EQ (lm.mapping_str (18), "1/0;2-5/0");
|
EXPECT_EQ (lm.mapping_str (18), "1-5/0");
|
||||||
EXPECT_EQ (lm.mapping_str (17), "1/5");
|
EXPECT_EQ (lm.mapping_str (17), "1/5");
|
||||||
|
|
||||||
lm.map (db::LDPair (2, 2), 18);
|
lm.map (db::LDPair (2, 2), 18);
|
||||||
|
|
@ -62,18 +62,37 @@ TEST(1)
|
||||||
|
|
||||||
lm.map_expr ("XP;10/7-8 : XN", 13);
|
lm.map_expr ("XP;10/7-8 : XN", 13);
|
||||||
EXPECT_EQ (lm.mapping_str (13), "10/7-8;XP : XN");
|
EXPECT_EQ (lm.mapping_str (13), "10/7-8;XP : XN");
|
||||||
EXPECT_EQ (lm.logical ("XP").second, (unsigned int) 13);
|
EXPECT_EQ (lm.first_logical ("XP").second, (unsigned int) 13);
|
||||||
EXPECT_EQ (lm.logical ("XP").first, true);
|
EXPECT_EQ (lm.first_logical ("XP").first, true);
|
||||||
EXPECT_EQ (lm.logical (db::LDPair(10, 6)).first, false);
|
EXPECT_EQ (lm.first_logical (db::LDPair(10, 6)).first, false);
|
||||||
EXPECT_EQ (lm.logical (db::LDPair(10, 7)).first, true);
|
EXPECT_EQ (lm.first_logical (db::LDPair(10, 7)).first, true);
|
||||||
EXPECT_EQ (lm.logical (db::LDPair(10, 7)).second, (unsigned int) 13);
|
EXPECT_EQ (lm.first_logical (db::LDPair(10, 7)).second, (unsigned int) 13);
|
||||||
|
|
||||||
EXPECT_EQ (lm.mapping (13).to_string (), "XN (10/7)");
|
EXPECT_EQ (lm.mapping (13).to_string (), "XN (10/7)");
|
||||||
|
|
||||||
lm.clear ();
|
lm.clear ();
|
||||||
EXPECT_EQ (lm.logical (db::LDPair(10, 7)).first, false);
|
EXPECT_EQ (lm.first_logical (db::LDPair(10, 7)).first, false);
|
||||||
lm.map_expr ("'XP';10/7-8 : XN", 13);
|
lm.map_expr ("'XP';10/7-8 : XN", 13);
|
||||||
EXPECT_EQ (lm.mapping_str (13), "10/7-8;XP : XN");
|
EXPECT_EQ (lm.mapping_str (13), "10/7-8;XP : XN");
|
||||||
|
|
||||||
|
// brackets, "add_expr"
|
||||||
|
lm.clear ();
|
||||||
|
lm.add_expr ("[1-10/*]", 1);
|
||||||
|
EXPECT_EQ (lm.mapping_str (1), "1-10/* : */*");
|
||||||
|
lm.add_expr ("-(5/*)", 0);
|
||||||
|
EXPECT_EQ (lm.mapping_str (1), "1-4/*;6-10/* : */*");
|
||||||
|
|
||||||
|
lm.clear ();
|
||||||
|
lm.add_expr ("[1/15]", 1);
|
||||||
|
lm.add_expr ("+(1/5:1001/5)", 1);
|
||||||
|
// NOTE: the target is taken from the second expression (the last one wins)
|
||||||
|
EXPECT_EQ (lm.mapping_str (1), "1/5,15 : 1001/5");
|
||||||
|
|
||||||
|
lm.clear ();
|
||||||
|
lm.add_expr ("+(1/5:1001/5)", 1);
|
||||||
|
lm.add_expr ("[1/15]", 1);
|
||||||
|
// NOTE: the target is taken from the second expression (the last one wins)
|
||||||
|
EXPECT_EQ (lm.mapping_str (1), "1/5,15 : */*");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(2)
|
TEST(2)
|
||||||
|
|
@ -349,55 +368,55 @@ TEST(6)
|
||||||
EXPECT_EQ (layers_to_string (ly), "1/0,3/10");
|
EXPECT_EQ (layers_to_string (ly), "1/0,3/10");
|
||||||
|
|
||||||
std::pair<bool, unsigned int> p;
|
std::pair<bool, unsigned int> p;
|
||||||
p = lm.logical (db::LayerProperties (1, 0));
|
p = lm.first_logical (db::LayerProperties (1, 0));
|
||||||
EXPECT_EQ (p.first, true);
|
EXPECT_EQ (p.first, true);
|
||||||
EXPECT_EQ (p.second, (unsigned int) 0);
|
EXPECT_EQ (p.second, (unsigned int) 0);
|
||||||
|
|
||||||
p = lm.logical (db::LayerProperties (2, 0));
|
p = lm.first_logical (db::LayerProperties (2, 0));
|
||||||
EXPECT_EQ (p.first, false);
|
EXPECT_EQ (p.first, false);
|
||||||
|
|
||||||
p = lm.logical (db::LayerProperties (3, 0));
|
p = lm.first_logical (db::LayerProperties (3, 0));
|
||||||
EXPECT_EQ (p.first, false);
|
EXPECT_EQ (p.first, false);
|
||||||
|
|
||||||
p = lm.logical (db::LayerProperties (3, 10));
|
p = lm.first_logical (db::LayerProperties (3, 10));
|
||||||
EXPECT_EQ (p.first, true);
|
EXPECT_EQ (p.first, true);
|
||||||
EXPECT_EQ (p.second, (unsigned int) 1);
|
EXPECT_EQ (p.second, (unsigned int) 1);
|
||||||
|
|
||||||
p = lm.logical (db::LayerProperties (3, 99));
|
p = lm.first_logical (db::LayerProperties (3, 99));
|
||||||
EXPECT_EQ (p.first, true);
|
EXPECT_EQ (p.first, true);
|
||||||
EXPECT_EQ (p.second, (unsigned int) 1);
|
EXPECT_EQ (p.second, (unsigned int) 1);
|
||||||
|
|
||||||
EXPECT_EQ (layers_to_string (ly), "1/0,3/10");
|
EXPECT_EQ (layers_to_string (ly), "1/0,3/10");
|
||||||
|
|
||||||
// this will create layer 2/0 in the layout
|
// this will create layer 2/0 in the layout
|
||||||
p = lm.logical (db::LayerProperties (2, 0), ly);
|
p = lm.first_logical (db::LayerProperties (2, 0), ly);
|
||||||
EXPECT_EQ (p.first, true);
|
EXPECT_EQ (p.first, true);
|
||||||
EXPECT_EQ (p.second, (unsigned int) 2);
|
EXPECT_EQ (p.second, (unsigned int) 2);
|
||||||
|
|
||||||
EXPECT_EQ (layers_to_string (ly), "1/0,3/10,2/0");
|
EXPECT_EQ (layers_to_string (ly), "1/0,3/10,2/0");
|
||||||
|
|
||||||
p = lm.logical (db::LayerProperties (2, 0));
|
p = lm.first_logical (db::LayerProperties (2, 0));
|
||||||
EXPECT_EQ (p.first, true);
|
EXPECT_EQ (p.first, true);
|
||||||
EXPECT_EQ (p.second, (unsigned int) 2);
|
EXPECT_EQ (p.second, (unsigned int) 2);
|
||||||
|
|
||||||
p = lm.logical (db::LayerProperties (2, 0), ly);
|
p = lm.first_logical (db::LayerProperties (2, 0), ly);
|
||||||
EXPECT_EQ (p.first, true);
|
EXPECT_EQ (p.first, true);
|
||||||
EXPECT_EQ (p.second, (unsigned int) 2);
|
EXPECT_EQ (p.second, (unsigned int) 2);
|
||||||
|
|
||||||
EXPECT_EQ (layers_to_string (ly), "1/0,3/10,2/0");
|
EXPECT_EQ (layers_to_string (ly), "1/0,3/10,2/0");
|
||||||
|
|
||||||
// this will create layer 2/42 in the layout
|
// this will create layer 2/42 in the layout
|
||||||
p = lm.logical (db::LayerProperties (2, 42), ly);
|
p = lm.first_logical (db::LayerProperties (2, 42), ly);
|
||||||
EXPECT_EQ (p.first, true);
|
EXPECT_EQ (p.first, true);
|
||||||
EXPECT_EQ (p.second, (unsigned int) 3);
|
EXPECT_EQ (p.second, (unsigned int) 3);
|
||||||
|
|
||||||
EXPECT_EQ (layers_to_string (ly), "1/0,3/10,2/0,2/42");
|
EXPECT_EQ (layers_to_string (ly), "1/0,3/10,2/0,2/42");
|
||||||
|
|
||||||
p = lm.logical (db::LayerProperties (2, 42));
|
p = lm.first_logical (db::LayerProperties (2, 42));
|
||||||
EXPECT_EQ (p.first, true);
|
EXPECT_EQ (p.first, true);
|
||||||
EXPECT_EQ (p.second, (unsigned int) 3);
|
EXPECT_EQ (p.second, (unsigned int) 3);
|
||||||
|
|
||||||
p = lm.logical (db::LayerProperties (2, 42), ly);
|
p = lm.first_logical (db::LayerProperties (2, 42), ly);
|
||||||
EXPECT_EQ (p.first, true);
|
EXPECT_EQ (p.first, true);
|
||||||
EXPECT_EQ (p.second, (unsigned int) 3);
|
EXPECT_EQ (p.second, (unsigned int) 3);
|
||||||
|
|
||||||
|
|
@ -429,19 +448,132 @@ TEST(7)
|
||||||
EXPECT_EQ (layers_to_string (ly), "85/0,185/0,,");
|
EXPECT_EQ (layers_to_string (ly), "85/0,185/0,,");
|
||||||
|
|
||||||
std::pair<bool, unsigned int> p;
|
std::pair<bool, unsigned int> p;
|
||||||
p = lm.logical (db::LayerProperties (85, 0));
|
p = lm.first_logical (db::LayerProperties (85, 0));
|
||||||
EXPECT_EQ (p.first, false);
|
EXPECT_EQ (p.first, false);
|
||||||
EXPECT_EQ (p.second, (unsigned int) 0);
|
EXPECT_EQ (p.second, (unsigned int) 0);
|
||||||
|
|
||||||
p = lm.logical (db::LayerProperties (185, 0));
|
p = lm.first_logical (db::LayerProperties (185, 0));
|
||||||
EXPECT_EQ (p.first, false);
|
EXPECT_EQ (p.first, false);
|
||||||
EXPECT_EQ (p.second, (unsigned int) 0);
|
EXPECT_EQ (p.second, (unsigned int) 0);
|
||||||
|
|
||||||
p = lm.logical (db::LayerProperties (10000, 0));
|
p = lm.first_logical (db::LayerProperties (10000, 0));
|
||||||
EXPECT_EQ (p.first, true);
|
EXPECT_EQ (p.first, true);
|
||||||
EXPECT_EQ (p.second, (unsigned int) 1);
|
EXPECT_EQ (p.second, (unsigned int) 1);
|
||||||
|
|
||||||
p = lm.logical (db::LayerProperties (10001, 0));
|
p = lm.first_logical (db::LayerProperties (10001, 0));
|
||||||
EXPECT_EQ (p.first, true);
|
EXPECT_EQ (p.first, true);
|
||||||
EXPECT_EQ (p.second, (unsigned int) 0);
|
EXPECT_EQ (p.second, (unsigned int) 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::string set2string (const std::set<unsigned int> &set)
|
||||||
|
{
|
||||||
|
std::string s;
|
||||||
|
for (std::set<unsigned int>::const_iterator i = set.begin (); i != set.end (); ++i) {
|
||||||
|
if (i != set.begin ()) {
|
||||||
|
s += ",";
|
||||||
|
}
|
||||||
|
s += tl::to_string (*i);
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
// multi-mapping, unmapping
|
||||||
|
TEST(8)
|
||||||
|
{
|
||||||
|
db::LayerMap lm;
|
||||||
|
|
||||||
|
unsigned int n = 0;
|
||||||
|
|
||||||
|
// refinement
|
||||||
|
// all
|
||||||
|
lm.mmap_expr ("*/*", n++);
|
||||||
|
EXPECT_EQ (lm.mapping_str (0), "*/*");
|
||||||
|
EXPECT_EQ (lm.to_string (),
|
||||||
|
"layer_map('*/*')"
|
||||||
|
);
|
||||||
|
EXPECT_EQ (db::LayerMap::from_string_file_format (lm.to_string_file_format ()).to_string (), lm.to_string ());
|
||||||
|
|
||||||
|
// some
|
||||||
|
lm.mmap_expr ("*/1-10", n++);
|
||||||
|
EXPECT_EQ (lm.to_string (),
|
||||||
|
"layer_map('+*/*';'+*/1-10')"
|
||||||
|
);
|
||||||
|
EXPECT_EQ (db::LayerMap::from_string_file_format (lm.to_string_file_format ()).to_string (), lm.to_string ());
|
||||||
|
|
||||||
|
// others
|
||||||
|
lm.mmap_expr ("*/5,15", n++);
|
||||||
|
|
||||||
|
EXPECT_EQ (lm.to_string (),
|
||||||
|
"layer_map('+*/*';'+*/1-10';'+*/5,15')"
|
||||||
|
);
|
||||||
|
EXPECT_EQ (db::LayerMap::from_string_file_format (lm.to_string_file_format ()).to_string (), lm.to_string ());
|
||||||
|
|
||||||
|
EXPECT_EQ (set2string (lm.logical (db::LDPair (0, 1000))), "0");
|
||||||
|
EXPECT_EQ (set2string (lm.logical (db::LDPair (1, 1000))), "0");
|
||||||
|
EXPECT_EQ (set2string (lm.logical (db::LDPair (0, 5))), "0,1,2");
|
||||||
|
EXPECT_EQ (set2string (lm.logical (db::LDPair (0, 15))), "0,2");
|
||||||
|
EXPECT_EQ (set2string (lm.logical (db::LDPair (0, 10))), "0,1");
|
||||||
|
|
||||||
|
// NOTE: the leading "+" indicates that the listed layers may go somewhere else, so we can't plainly map them
|
||||||
|
EXPECT_EQ (lm.mapping_str (0), "+*/*");
|
||||||
|
EXPECT_EQ (lm.mapping_str (1), "+*/1-10");
|
||||||
|
EXPECT_EQ (lm.mapping_str (2), "+*/5,15");
|
||||||
|
EXPECT_EQ (lm.mapping_str (3), "");
|
||||||
|
|
||||||
|
lm = db::LayerMap ();
|
||||||
|
n = 0;
|
||||||
|
|
||||||
|
// refinement
|
||||||
|
// all
|
||||||
|
lm.mmap_expr ("*/*", n++);
|
||||||
|
EXPECT_EQ (lm.mapping_str (0), "*/*");
|
||||||
|
EXPECT_EQ (lm.to_string (),
|
||||||
|
"layer_map('*/*')"
|
||||||
|
);
|
||||||
|
EXPECT_EQ (db::LayerMap::from_string_file_format (lm.to_string_file_format ()).to_string (), lm.to_string ());
|
||||||
|
|
||||||
|
// some
|
||||||
|
lm.mmap_expr ("1-10/*", n++);
|
||||||
|
EXPECT_EQ (lm.to_string (),
|
||||||
|
"layer_map('+*/*';'+1-10/*')"
|
||||||
|
);
|
||||||
|
EXPECT_EQ (db::LayerMap::from_string_file_format (lm.to_string_file_format ()).to_string (), lm.to_string ());
|
||||||
|
|
||||||
|
// others
|
||||||
|
lm.mmap_expr ("5,15/*", n++);
|
||||||
|
|
||||||
|
EXPECT_EQ (lm.to_string (),
|
||||||
|
"layer_map('+*/*';'+1-10/*';'+5/*;15/*')"
|
||||||
|
);
|
||||||
|
EXPECT_EQ (db::LayerMap::from_string_file_format (lm.to_string_file_format ()).to_string (), lm.to_string ());
|
||||||
|
|
||||||
|
EXPECT_EQ (set2string (lm.logical (db::LDPair (1000, 0))), "0");
|
||||||
|
EXPECT_EQ (set2string (lm.logical (db::LDPair (1000, 1))), "0");
|
||||||
|
EXPECT_EQ (set2string (lm.logical (db::LDPair (5, 0))), "0,1,2");
|
||||||
|
EXPECT_EQ (set2string (lm.logical (db::LDPair (15, 0))), "0,2");
|
||||||
|
EXPECT_EQ (set2string (lm.logical (db::LDPair (10, 0))), "0,1");
|
||||||
|
|
||||||
|
// NOTE: the leading "+" indicates that the listed layers may go somewhere else, so we can't plainly map them
|
||||||
|
EXPECT_EQ (lm.mapping_str (0), "+*/*");
|
||||||
|
EXPECT_EQ (lm.mapping_str (1), "+1-10/*");
|
||||||
|
EXPECT_EQ (lm.mapping_str (2), "+5/*;15/*");
|
||||||
|
EXPECT_EQ (lm.mapping_str (3), "");
|
||||||
|
|
||||||
|
lm = db::LayerMap ();
|
||||||
|
n = 0;
|
||||||
|
|
||||||
|
lm.mmap_expr ("*/*", n++);
|
||||||
|
EXPECT_EQ (lm.mapping_str (0), "*/*");
|
||||||
|
EXPECT_EQ (lm.to_string (),
|
||||||
|
"layer_map('*/*')"
|
||||||
|
);
|
||||||
|
EXPECT_EQ (db::LayerMap::from_string_file_format (lm.to_string_file_format ()).to_string (), lm.to_string ());
|
||||||
|
|
||||||
|
// some
|
||||||
|
lm.mmap_expr ("1-10/0-20", n++);
|
||||||
|
EXPECT_EQ (lm.to_string (),
|
||||||
|
"layer_map('+*/*';'+1-10/0-20')"
|
||||||
|
);
|
||||||
|
EXPECT_EQ (db::LayerMap::from_string_file_format (lm.to_string_file_format ()).to_string (), lm.to_string ());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -69,8 +69,8 @@ static void configure_from_line_edit (lay::Dispatcher *dispatcher, QLineEdit *le
|
||||||
// ------------------------------------------------------------------
|
// ------------------------------------------------------------------
|
||||||
// EditorOptionsGeneric implementation
|
// EditorOptionsGeneric implementation
|
||||||
|
|
||||||
EditorOptionsGeneric::EditorOptionsGeneric (lay::Dispatcher *dispatcher)
|
EditorOptionsGeneric::EditorOptionsGeneric (lay::LayoutView *view, lay::Dispatcher *dispatcher)
|
||||||
: EditorOptionsPage (dispatcher)
|
: EditorOptionsPage (view, dispatcher)
|
||||||
{
|
{
|
||||||
mp_ui = new Ui::EditorOptionsGeneric ();
|
mp_ui = new Ui::EditorOptionsGeneric ();
|
||||||
mp_ui->setupUi (this);
|
mp_ui->setupUi (this);
|
||||||
|
|
@ -206,8 +206,8 @@ EditorOptionsGeneric::setup (lay::Dispatcher *root)
|
||||||
// ------------------------------------------------------------------
|
// ------------------------------------------------------------------
|
||||||
// EditorOptionsText implementation
|
// EditorOptionsText implementation
|
||||||
|
|
||||||
EditorOptionsText::EditorOptionsText (lay::Dispatcher *dispatcher)
|
EditorOptionsText::EditorOptionsText (lay::LayoutView *view, lay::Dispatcher *dispatcher)
|
||||||
: lay::EditorOptionsPage (dispatcher)
|
: lay::EditorOptionsPage (view, dispatcher)
|
||||||
{
|
{
|
||||||
mp_ui = new Ui::EditorOptionsText ();
|
mp_ui = new Ui::EditorOptionsText ();
|
||||||
mp_ui->setupUi (this);
|
mp_ui->setupUi (this);
|
||||||
|
|
@ -284,8 +284,8 @@ EditorOptionsText::setup (lay::Dispatcher *root)
|
||||||
// ------------------------------------------------------------------
|
// ------------------------------------------------------------------
|
||||||
// EditorOptionsPath implementation
|
// EditorOptionsPath implementation
|
||||||
|
|
||||||
EditorOptionsPath::EditorOptionsPath (lay::Dispatcher *dispatcher)
|
EditorOptionsPath::EditorOptionsPath (lay::LayoutView *view, lay::Dispatcher *dispatcher)
|
||||||
: lay::EditorOptionsPage (dispatcher)
|
: lay::EditorOptionsPage (view, dispatcher)
|
||||||
{
|
{
|
||||||
mp_ui = new Ui::EditorOptionsPath ();
|
mp_ui = new Ui::EditorOptionsPath ();
|
||||||
mp_ui->setupUi (this);
|
mp_ui->setupUi (this);
|
||||||
|
|
@ -385,8 +385,8 @@ EditorOptionsPath::setup (lay::Dispatcher *root)
|
||||||
// ------------------------------------------------------------------
|
// ------------------------------------------------------------------
|
||||||
// EditorOptionsInst implementation
|
// EditorOptionsInst implementation
|
||||||
|
|
||||||
EditorOptionsInst::EditorOptionsInst (lay::Dispatcher *dispatcher)
|
EditorOptionsInst::EditorOptionsInst (lay::LayoutView *view, lay::Dispatcher *dispatcher)
|
||||||
: lay::EditorOptionsPage (dispatcher)
|
: lay::EditorOptionsPage (view, dispatcher)
|
||||||
{
|
{
|
||||||
mp_ui = new Ui::EditorOptionsInst ();
|
mp_ui = new Ui::EditorOptionsInst ();
|
||||||
mp_ui->setupUi (this);
|
mp_ui->setupUi (this);
|
||||||
|
|
@ -440,14 +440,13 @@ EditorOptionsInst::update_cell_edits ()
|
||||||
}
|
}
|
||||||
|
|
||||||
db::Layout *layout = 0;
|
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
|
// find the layout the cell has to be looked up: that is either the layout of the current instance or
|
||||||
// the library selected
|
// the library selected
|
||||||
if (mp_ui->lib_cbx->current_library ()) {
|
if (mp_ui->lib_cbx->current_library ()) {
|
||||||
layout = &mp_ui->lib_cbx->current_library ()->layout ();
|
layout = &mp_ui->lib_cbx->current_library ()->layout ();
|
||||||
} else if (view && view->cellview (m_cv_index).is_valid ()) {
|
} else if (view ()->cellview (m_cv_index).is_valid ()) {
|
||||||
layout = &view->cellview (m_cv_index)->layout ();
|
layout = &view ()->cellview (m_cv_index)->layout ();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! layout) {
|
if (! layout) {
|
||||||
|
|
@ -485,7 +484,7 @@ EditorOptionsInst::browse_cell ()
|
||||||
{
|
{
|
||||||
BEGIN_PROTECTED
|
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
|
// find the layout the cell has to be looked up: that is either the layout of the current instance or
|
||||||
// the library selected
|
// the library selected
|
||||||
|
|
@ -495,7 +494,7 @@ BEGIN_PROTECTED
|
||||||
lib = mp_ui->lib_cbx->current_library ();
|
lib = mp_ui->lib_cbx->current_library ();
|
||||||
layout = &lib->layout ();
|
layout = &lib->layout ();
|
||||||
} else {
|
} 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);
|
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));
|
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)
|
EditorOptionsInst::setup (lay::Dispatcher *root)
|
||||||
{
|
{
|
||||||
m_cv_index = -1;
|
m_cv_index = view ()->active_cellview_index ();
|
||||||
if (lay::LayoutView::current ()) {
|
|
||||||
m_cv_index = lay::LayoutView::current ()->active_cellview_index ();
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
mp_ui->lib_cbx->blockSignals (true);
|
mp_ui->lib_cbx->blockSignals (true);
|
||||||
|
|
||||||
|
std::string techname;
|
||||||
|
|
||||||
mp_ui->lib_cbx->update_list ();
|
mp_ui->lib_cbx->update_list ();
|
||||||
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 ()) {
|
||||||
mp_ui->lib_cbx->set_technology_filter (lay::LayoutView::current ()->cellview (m_cv_index)->tech_name (), true);
|
techname = view ()->cellview (m_cv_index)->tech_name ();
|
||||||
} else {
|
|
||||||
mp_ui->lib_cbx->set_technology_filter (std::string (), false);
|
|
||||||
}
|
}
|
||||||
|
mp_ui->lib_cbx->set_technology_filter (techname, ! techname.empty ());
|
||||||
|
|
||||||
// cell name
|
// cell name
|
||||||
std::string s;
|
std::string s;
|
||||||
|
|
@ -606,7 +617,7 @@ EditorOptionsInst::setup (lay::Dispatcher *root)
|
||||||
// library
|
// library
|
||||||
std::string l;
|
std::string l;
|
||||||
root->config_get (cfg_edit_inst_lib_name, 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);
|
mp_ui->lib_cbx->blockSignals (false);
|
||||||
update_cell_edits ();
|
update_cell_edits ();
|
||||||
|
|
@ -667,8 +678,8 @@ EditorOptionsInst::setup (lay::Dispatcher *root)
|
||||||
// ------------------------------------------------------------------
|
// ------------------------------------------------------------------
|
||||||
// EditorOptionsInstPCellParam implementation
|
// EditorOptionsInstPCellParam implementation
|
||||||
|
|
||||||
EditorOptionsInstPCellParam::EditorOptionsInstPCellParam (lay::Dispatcher *dispatcher)
|
EditorOptionsInstPCellParam::EditorOptionsInstPCellParam (lay::LayoutView *view, lay::Dispatcher *dispatcher)
|
||||||
: lay::EditorOptionsPage (dispatcher), mp_pcell_parameters (0), mp_placeholder_label (0)
|
: lay::EditorOptionsPage (view, dispatcher), mp_pcell_parameters (0), mp_placeholder_label (0)
|
||||||
{
|
{
|
||||||
mp_ui = new Ui::EditorOptionsInstPCellParam ();
|
mp_ui = new Ui::EditorOptionsInstPCellParam ();
|
||||||
mp_ui->setupUi (this);
|
mp_ui->setupUi (this);
|
||||||
|
|
@ -693,11 +704,11 @@ EditorOptionsInstPCellParam::apply (lay::Dispatcher *root)
|
||||||
std::string param;
|
std::string param;
|
||||||
db::Layout *layout = 0;
|
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) {
|
if (lib) {
|
||||||
layout = &lib->layout ();
|
layout = &lib->layout ();
|
||||||
} else if (m_cv_index >= 0 && lay::LayoutView::current () && lay::LayoutView::current ()->cellview (m_cv_index).is_valid ()) {
|
} else if (m_cv_index >= 0 && view ()->cellview (m_cv_index).is_valid ()) {
|
||||||
layout = &lay::LayoutView::current ()->cellview (m_cv_index)->layout ();
|
layout = &view ()->cellview (m_cv_index)->layout ();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ok = true;
|
bool ok = true;
|
||||||
|
|
@ -717,13 +728,16 @@ EditorOptionsInstPCellParam::apply (lay::Dispatcher *root)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
EditorOptionsInstPCellParam::technology_changed (const std::string &)
|
||||||
|
{
|
||||||
|
setup (dispatcher ());
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
EditorOptionsInstPCellParam::setup (lay::Dispatcher *root)
|
EditorOptionsInstPCellParam::setup (lay::Dispatcher *root)
|
||||||
{
|
{
|
||||||
m_cv_index = -1;
|
m_cv_index = view ()->active_cellview_index ();
|
||||||
if (lay::LayoutView::current ()) {
|
|
||||||
m_cv_index = lay::LayoutView::current ()->active_cellview_index ();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool needs_update = (mp_pcell_parameters == 0);
|
bool needs_update = (mp_pcell_parameters == 0);
|
||||||
|
|
||||||
|
|
@ -743,7 +757,7 @@ EditorOptionsInstPCellParam::setup (lay::Dispatcher *root)
|
||||||
needs_update = true;
|
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
|
// pcell parameters
|
||||||
std::string param;
|
std::string param;
|
||||||
|
|
@ -752,8 +766,8 @@ EditorOptionsInstPCellParam::setup (lay::Dispatcher *root)
|
||||||
db::Layout *layout = 0;
|
db::Layout *layout = 0;
|
||||||
if (lib) {
|
if (lib) {
|
||||||
layout = &lib->layout ();
|
layout = &lib->layout ();
|
||||||
} else if (m_cv_index >= 0 && lay::LayoutView::current () && lay::LayoutView::current ()->cellview (m_cv_index).is_valid ()) {
|
} else if (m_cv_index >= 0 && view ()->cellview (m_cv_index).is_valid ()) {
|
||||||
layout = &lay::LayoutView::current ()->cellview (m_cv_index)->layout ();
|
layout = &view ()->cellview (m_cv_index)->layout ();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<tl::Variant> pv;
|
std::vector<tl::Variant> pv;
|
||||||
|
|
@ -820,15 +834,14 @@ void
|
||||||
EditorOptionsInstPCellParam::update_pcell_parameters (const std::vector <tl::Variant> ¶meters)
|
EditorOptionsInstPCellParam::update_pcell_parameters (const std::vector <tl::Variant> ¶meters)
|
||||||
{
|
{
|
||||||
db::Layout *layout = 0;
|
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
|
// find the layout the cell has to be looked up: that is either the layout of the current instance or
|
||||||
// the library selected
|
// 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) {
|
if (lib) {
|
||||||
layout = &lib->layout ();
|
layout = &lib->layout ();
|
||||||
} else if (view) {
|
} else {
|
||||||
const lay::CellView &cv = view->cellview (m_cv_index);
|
const lay::CellView &cv = view ()->cellview (m_cv_index);
|
||||||
if (cv.is_valid ()) {
|
if (cv.is_valid ()) {
|
||||||
layout = &cv->layout ();
|
layout = &cv->layout ();
|
||||||
}
|
}
|
||||||
|
|
@ -856,10 +869,10 @@ EditorOptionsInstPCellParam::update_pcell_parameters (const std::vector <tl::Var
|
||||||
mp_pcell_parameters = 0;
|
mp_pcell_parameters = 0;
|
||||||
mp_placeholder_label = 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 = 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 (), m_cv_index, layout->pcell_declaration (pc.second), parameters);
|
||||||
this->layout ()->addWidget (mp_pcell_parameters);
|
this->layout ()->addWidget (mp_pcell_parameters);
|
||||||
|
|
||||||
mp_pcell_parameters->set_state (pcp_state);
|
mp_pcell_parameters->set_state (pcp_state);
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,7 @@ namespace lay
|
||||||
{
|
{
|
||||||
class PluginDeclaration;
|
class PluginDeclaration;
|
||||||
class Dispatcher;
|
class Dispatcher;
|
||||||
|
class LayoutView;
|
||||||
class Plugin;
|
class Plugin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -68,7 +69,7 @@ class EditorOptionsGeneric
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
EditorOptionsGeneric (lay::Dispatcher *dispatcher);
|
EditorOptionsGeneric (lay::LayoutView *view, lay::Dispatcher *dispatcher);
|
||||||
~EditorOptionsGeneric ();
|
~EditorOptionsGeneric ();
|
||||||
|
|
||||||
virtual std::string title () const;
|
virtual std::string title () const;
|
||||||
|
|
@ -91,7 +92,7 @@ class EditorOptionsText
|
||||||
: public lay::EditorOptionsPage
|
: public lay::EditorOptionsPage
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
EditorOptionsText (lay::Dispatcher *dispatcher);
|
EditorOptionsText (lay::LayoutView *view, lay::Dispatcher *dispatcher);
|
||||||
~EditorOptionsText ();
|
~EditorOptionsText ();
|
||||||
|
|
||||||
virtual std::string title () const;
|
virtual std::string title () const;
|
||||||
|
|
@ -112,7 +113,7 @@ class EditorOptionsPath
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
EditorOptionsPath (lay::Dispatcher *dispatcher);
|
EditorOptionsPath (lay::LayoutView *view, lay::Dispatcher *dispatcher);
|
||||||
~EditorOptionsPath ();
|
~EditorOptionsPath ();
|
||||||
|
|
||||||
virtual std::string title () const;
|
virtual std::string title () const;
|
||||||
|
|
@ -136,7 +137,7 @@ class EditorOptionsInst
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
EditorOptionsInst (lay::Dispatcher *root);
|
EditorOptionsInst (lay::LayoutView *view, lay::Dispatcher *root);
|
||||||
~EditorOptionsInst ();
|
~EditorOptionsInst ();
|
||||||
|
|
||||||
virtual std::string title () const;
|
virtual std::string title () const;
|
||||||
|
|
@ -154,6 +155,9 @@ private:
|
||||||
Ui::EditorOptionsInst *mp_ui;
|
Ui::EditorOptionsInst *mp_ui;
|
||||||
edt::PCellParametersPage *mp_pcell_parameters;
|
edt::PCellParametersPage *mp_pcell_parameters;
|
||||||
int m_cv_index;
|
int m_cv_index;
|
||||||
|
|
||||||
|
virtual void technology_changed (const std::string &);
|
||||||
|
virtual void active_cellview_changed ();
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -165,7 +169,7 @@ class EditorOptionsInstPCellParam
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
EditorOptionsInstPCellParam (lay::Dispatcher *root);
|
EditorOptionsInstPCellParam (lay::LayoutView *view, lay::Dispatcher *root);
|
||||||
~EditorOptionsInstPCellParam ();
|
~EditorOptionsInstPCellParam ();
|
||||||
|
|
||||||
virtual std::string title () const;
|
virtual std::string title () const;
|
||||||
|
|
@ -184,6 +188,7 @@ private:
|
||||||
std::string m_lib_name, m_cell_name;
|
std::string m_lib_name, m_cell_name;
|
||||||
|
|
||||||
void update_pcell_parameters (const std::vector <tl::Variant> ¶meters);
|
void update_pcell_parameters (const std::vector <tl::Variant> ¶meters);
|
||||||
|
virtual void technology_changed (const std::string &);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -810,7 +810,7 @@ InstPropertiesPage::update_pcell_parameters ()
|
||||||
|
|
||||||
mp_pcell_parameters = new PCellParametersPage (pcell_tab);
|
mp_pcell_parameters = new PCellParametersPage (pcell_tab);
|
||||||
connect (mp_pcell_parameters, SIGNAL (edited ()), this, SIGNAL (edited ()));
|
connect (mp_pcell_parameters, SIGNAL (edited ()), this, SIGNAL (edited ()));
|
||||||
mp_pcell_parameters->setup (&cv->layout (), mp_service->view (), pos->cv_index (), layout->pcell_declaration (pc.second), parameters);
|
mp_pcell_parameters->setup (mp_service->view (), pos->cv_index (), layout->pcell_declaration (pc.second), parameters);
|
||||||
pcell_tab->layout ()->addWidget (mp_pcell_parameters);
|
pcell_tab->layout ()->addWidget (mp_pcell_parameters);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@
|
||||||
#include "edtPropertiesPageUtils.h"
|
#include "edtPropertiesPageUtils.h"
|
||||||
#include "layWidgets.h"
|
#include "layWidgets.h"
|
||||||
#include "layQtTools.h"
|
#include "layQtTools.h"
|
||||||
|
#include "layLayoutView.h"
|
||||||
#include "tlScriptError.h"
|
#include "tlScriptError.h"
|
||||||
|
|
||||||
#include <QFrame>
|
#include <QFrame>
|
||||||
|
|
@ -40,7 +41,7 @@
|
||||||
namespace edt
|
namespace edt
|
||||||
{
|
{
|
||||||
|
|
||||||
static void set_value (const db::PCellParameterDeclaration &p, const db::Layout * /*layout*/, QWidget *widget, const tl::Variant &value)
|
static void set_value (const db::PCellParameterDeclaration &p, QWidget *widget, const tl::Variant &value)
|
||||||
{
|
{
|
||||||
if (p.get_choices ().empty ()) {
|
if (p.get_choices ().empty ()) {
|
||||||
|
|
||||||
|
|
@ -153,8 +154,7 @@ PCellParametersPage::PCellParametersPage (QWidget *parent, bool dense)
|
||||||
void
|
void
|
||||||
PCellParametersPage::init ()
|
PCellParametersPage::init ()
|
||||||
{
|
{
|
||||||
mp_pcell_decl = 0;
|
mp_pcell_decl.reset (0);
|
||||||
mp_layout = 0;
|
|
||||||
mp_view = 0;
|
mp_view = 0;
|
||||||
m_cv_index = 0;
|
m_cv_index = 0;
|
||||||
mp_parameters_area = 0;
|
mp_parameters_area = 0;
|
||||||
|
|
@ -183,10 +183,9 @@ PCellParametersPage::init ()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
PCellParametersPage::setup (const db::Layout *layout, lay::LayoutView *view, int cv_index, const db::PCellDeclaration *pcell_decl, const db::pcell_parameters_type ¶meters)
|
PCellParametersPage::setup (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;
|
mp_view = view;
|
||||||
m_cv_index = cv_index;
|
m_cv_index = cv_index;
|
||||||
m_parameters = parameters;
|
m_parameters = parameters;
|
||||||
|
|
@ -385,7 +384,7 @@ PCellParametersPage::setup (const db::Layout *layout, lay::LayoutView *view, int
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
set_value (*p, mp_layout, m_widgets.back (), value);
|
set_value (*p, m_widgets.back (), value);
|
||||||
|
|
||||||
++row;
|
++row;
|
||||||
if (inner_frame == main_frame) {
|
if (inner_frame == main_frame) {
|
||||||
|
|
@ -457,137 +456,144 @@ std::vector<tl::Variant>
|
||||||
PCellParametersPage::get_parameters (bool *ok)
|
PCellParametersPage::get_parameters (bool *ok)
|
||||||
{
|
{
|
||||||
std::vector<tl::Variant> parameters;
|
std::vector<tl::Variant> parameters;
|
||||||
bool edit_error = true;
|
|
||||||
|
|
||||||
int r = 0;
|
try {
|
||||||
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) {
|
|
||||||
|
|
||||||
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 ()) {
|
bool edit_error = true;
|
||||||
parameters.push_back (m_parameters [r]);
|
|
||||||
} else {
|
|
||||||
parameters.push_back (p->get_default ());
|
|
||||||
}
|
|
||||||
|
|
||||||
} 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 ()) {
|
if (r < (int) m_parameters.size ()) {
|
||||||
|
parameters.push_back (m_parameters [r]);
|
||||||
switch (p->get_type ()) {
|
} else {
|
||||||
|
parameters.push_back (p->get_default ());
|
||||||
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 {
|
} else {
|
||||||
|
|
||||||
QComboBox *cb = dynamic_cast<QComboBox*> (m_widgets [r]);
|
parameters.push_back (tl::Variant ());
|
||||||
if (cb && cb->currentIndex () >= 0 && cb->currentIndex () < int (p->get_choices ().size ())) {
|
|
||||||
parameters.back () = p->get_choices () [cb->currentIndex ()];
|
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) {
|
if (! edit_error) {
|
||||||
throw tl::Exception (tl::to_string (tr ("There are errors. See the highlighted edit fields for details.")));
|
throw tl::Exception (tl::to_string (tr ("There are errors. See the highlighted edit fields for details.")));
|
||||||
}
|
}
|
||||||
|
|
||||||
// coerce the parameters
|
// coerce the parameters
|
||||||
mp_pcell_decl->coerce_parameters (*mp_layout, parameters);
|
if (mp_view->cellview (m_cv_index).is_valid ()) {
|
||||||
|
mp_pcell_decl->coerce_parameters (mp_view->cellview (m_cv_index)->layout (), parameters);
|
||||||
|
}
|
||||||
set_parameters (parameters);
|
set_parameters (parameters);
|
||||||
|
|
||||||
mp_error_label->hide ();
|
mp_error_label->hide ();
|
||||||
|
|
@ -628,12 +634,16 @@ PCellParametersPage::get_parameters (bool *ok)
|
||||||
void
|
void
|
||||||
PCellParametersPage::set_parameters (const std::vector<tl::Variant> ¶meters)
|
PCellParametersPage::set_parameters (const std::vector<tl::Variant> ¶meters)
|
||||||
{
|
{
|
||||||
|
if (! mp_pcell_decl) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// write the changed value back
|
// write the changed value back
|
||||||
size_t r = 0;
|
size_t r = 0;
|
||||||
const std::vector<db::PCellParameterDeclaration> &pcp = mp_pcell_decl->parameter_declarations ();
|
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) {
|
for (std::vector<db::PCellParameterDeclaration>::const_iterator p = pcp.begin (); p != pcp.end (); ++p, ++r) {
|
||||||
if (r < parameters.size () && m_widgets [r]) {
|
if (r < parameters.size () && m_widgets [r]) {
|
||||||
set_value (*p, mp_layout, m_widgets [r], parameters [r]);
|
set_value (*p, m_widgets [r], parameters [r]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,7 @@ public:
|
||||||
* @param pcell_decl The PCell declaration
|
* @param pcell_decl The PCell declaration
|
||||||
* @param parameters The parameter values to show (if empty, the default values are used)
|
* @param parameters The parameter values to show (if empty, the default values are used)
|
||||||
*/
|
*/
|
||||||
void setup (const db::Layout *layout, lay::LayoutView *view, int cv_index, const db::PCellDeclaration *pcell_decl, const db::pcell_parameters_type ¶meters);
|
void setup (lay::LayoutView *view, int cv_index, const db::PCellDeclaration *pcell_decl, const db::pcell_parameters_type ¶meters);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Gets the pages current state
|
* @brief Gets the pages current state
|
||||||
|
|
@ -104,7 +104,7 @@ public:
|
||||||
*/
|
*/
|
||||||
const db::PCellDeclaration *pcell_decl () const
|
const db::PCellDeclaration *pcell_decl () const
|
||||||
{
|
{
|
||||||
return mp_pcell_decl;
|
return mp_pcell_decl.get ();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -122,9 +122,8 @@ private:
|
||||||
QScrollArea *mp_parameters_area;
|
QScrollArea *mp_parameters_area;
|
||||||
QLabel *mp_error_label;
|
QLabel *mp_error_label;
|
||||||
QLabel *mp_error_icon;
|
QLabel *mp_error_icon;
|
||||||
const db::PCellDeclaration *mp_pcell_decl;
|
tl::weak_ptr<db::PCellDeclaration> mp_pcell_decl;
|
||||||
std::vector<QWidget *> m_widgets;
|
std::vector<QWidget *> m_widgets;
|
||||||
const db::Layout *mp_layout;
|
|
||||||
lay::LayoutView *mp_view;
|
lay::LayoutView *mp_view;
|
||||||
int m_cv_index;
|
int m_cv_index;
|
||||||
db::pcell_parameters_type m_parameters;
|
db::pcell_parameters_type m_parameters;
|
||||||
|
|
|
||||||
|
|
@ -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",
|
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])]));
|
&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
|
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",
|
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])]));
|
&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
|
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",
|
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])]));
|
&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 EditorOptionsInstPCellParam (view, dispatcher));
|
||||||
ret.push_back (new EditorOptionsInst (dispatcher));
|
ret.push_back (new EditorOptionsInst (view, dispatcher));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Svc>
|
template <class Svc>
|
||||||
|
|
@ -327,10 +327,10 @@ public:
|
||||||
return false;
|
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
|
// 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);
|
pages.push_back (generic_opt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@
|
||||||
#include "layLayerTreeModel.h"
|
#include "layLayerTreeModel.h"
|
||||||
#include "dbLibraryManager.h"
|
#include "dbLibraryManager.h"
|
||||||
#include "dbLibrary.h"
|
#include "dbLibrary.h"
|
||||||
|
#include "tlLog.h"
|
||||||
|
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
#include <QHeaderView>
|
#include <QHeaderView>
|
||||||
|
|
@ -55,7 +56,7 @@ RecentConfigurationPage::init ()
|
||||||
ly->addWidget (mp_tree_widget);
|
ly->addWidget (mp_tree_widget);
|
||||||
|
|
||||||
connect (mp_tree_widget, SIGNAL (itemClicked (QTreeWidgetItem *, int)), this, SLOT (item_clicked (QTreeWidgetItem *)));
|
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 ()));
|
mp_tree_widget->setColumnCount (int (m_cfg.size ()));
|
||||||
|
|
||||||
|
|
@ -89,16 +90,24 @@ RecentConfigurationPage::get_stored_values () const
|
||||||
std::string serialized_list = dispatcher ()->config_get (m_recent_cfg_name);
|
std::string serialized_list = dispatcher ()->config_get (m_recent_cfg_name);
|
||||||
|
|
||||||
std::list<std::vector<std::string> > values;
|
std::list<std::vector<std::string> > values;
|
||||||
tl::Extractor ex (serialized_list.c_str ());
|
|
||||||
while (! ex.at_end ()) {
|
|
||||||
|
|
||||||
values.push_back (std::vector<std::string> ());
|
try {
|
||||||
while (! ex.at_end () && ! ex.test (";")) {
|
|
||||||
values.back ().push_back (std::string ());
|
tl::Extractor ex (serialized_list.c_str ());
|
||||||
ex.read_word_or_quoted (values.back ().back ());
|
while (! ex.at_end ()) {
|
||||||
ex.test (",");
|
|
||||||
|
values.push_back (std::vector<std::string> ());
|
||||||
|
while (! ex.at_end () && ! ex.test (";")) {
|
||||||
|
values.back ().push_back (std::string ());
|
||||||
|
ex.read_word_or_quoted (values.back ().back ());
|
||||||
|
ex.test (",");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} catch (tl::Exception &ex) {
|
||||||
|
tl::error << tl::to_string (tr ("Error reading configuration item ")) << m_recent_cfg_name << ": " << ex.msg ();
|
||||||
|
values.clear ();
|
||||||
}
|
}
|
||||||
|
|
||||||
return values;
|
return values;
|
||||||
|
|
@ -158,7 +167,11 @@ RecentConfigurationPage::render_to (QTreeWidgetItem *item, int column, const std
|
||||||
case RecentConfigurationPage::Bool:
|
case RecentConfigurationPage::Bool:
|
||||||
{
|
{
|
||||||
bool f = false;
|
bool f = false;
|
||||||
tl::from_string (values [column], f);
|
try {
|
||||||
|
tl::from_string (values [column], f);
|
||||||
|
} catch (tl::Exception &ex) {
|
||||||
|
tl::error << tl::to_string (tr ("Configuration error (ArrayFlag/Bool): ")) << ex.msg ();
|
||||||
|
}
|
||||||
static QString checkmark = QString::fromUtf8 ("\xe2\x9c\x93");
|
static QString checkmark = QString::fromUtf8 ("\xe2\x9c\x93");
|
||||||
item->setText (column, f ? checkmark : QString ()); // "checkmark"
|
item->setText (column, f ? checkmark : QString ()); // "checkmark"
|
||||||
}
|
}
|
||||||
|
|
@ -166,10 +179,15 @@ RecentConfigurationPage::render_to (QTreeWidgetItem *item, int column, const std
|
||||||
|
|
||||||
case RecentConfigurationPage::Layer:
|
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 = lp_iter_from_string (mp_view, values [column]);
|
lay::LayerPropertiesConstIterator l;
|
||||||
|
try {
|
||||||
|
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 ()) {
|
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]));
|
item->setText (column, tl::to_qstring (values [column]));
|
||||||
} else {
|
} else {
|
||||||
item->setIcon (column, QIcon ());
|
item->setIcon (column, QIcon ());
|
||||||
|
|
@ -199,7 +217,11 @@ RecentConfigurationPage::render_to (QTreeWidgetItem *item, int column, const std
|
||||||
int flag_column = 0;
|
int flag_column = 0;
|
||||||
for (std::list<ConfigurationDescriptor>::const_iterator c = m_cfg.begin (); c != m_cfg.end (); ++c, ++flag_column) {
|
for (std::list<ConfigurationDescriptor>::const_iterator c = m_cfg.begin (); c != m_cfg.end (); ++c, ++flag_column) {
|
||||||
if (c->rendering == RecentConfigurationPage::ArrayFlag) {
|
if (c->rendering == RecentConfigurationPage::ArrayFlag) {
|
||||||
tl::from_string (values [flag_column], is_array);
|
try {
|
||||||
|
tl::from_string (values [flag_column], is_array);
|
||||||
|
} catch (tl::Exception &ex) {
|
||||||
|
tl::error << tl::to_string (tr ("Configuration error (IntIfArray/DoubleIfArray): ")) << ex.msg ();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -219,7 +241,11 @@ RecentConfigurationPage::render_to (QTreeWidgetItem *item, int column, const std
|
||||||
const db::Library *lib = 0;
|
const db::Library *lib = 0;
|
||||||
for (std::list<ConfigurationDescriptor>::const_iterator c = m_cfg.begin (); c != m_cfg.end (); ++c, ++libname_column) {
|
for (std::list<ConfigurationDescriptor>::const_iterator c = m_cfg.begin (); c != m_cfg.end (); ++c, ++libname_column) {
|
||||||
if (c->rendering == RecentConfigurationPage::CellLibraryName) {
|
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -254,7 +280,11 @@ RecentConfigurationPage::render_to (QTreeWidgetItem *item, int column, const std
|
||||||
case RecentConfigurationPage::PCellParameters:
|
case RecentConfigurationPage::PCellParameters:
|
||||||
{
|
{
|
||||||
std::map<std::string, tl::Variant> pcp;
|
std::map<std::string, tl::Variant> pcp;
|
||||||
pcp = pcell_parameters_from_string (values [column]);
|
try {
|
||||||
|
pcp = pcell_parameters_from_string (values [column]);
|
||||||
|
} catch (tl::Exception &ex) {
|
||||||
|
tl::error << tl::to_string (tr ("Configuration error (PCellParameters): ")) << ex.msg ();
|
||||||
|
}
|
||||||
std::string r;
|
std::string r;
|
||||||
for (std::map<std::string, tl::Variant>::const_iterator p = pcp.begin (); p != pcp.end (); ++p) {
|
for (std::map<std::string, tl::Variant>::const_iterator p = pcp.begin (); p != pcp.end (); ++p) {
|
||||||
if (p != pcp.begin ()) {
|
if (p != pcp.begin ()) {
|
||||||
|
|
@ -278,6 +308,12 @@ RecentConfigurationPage::layers_changed (int)
|
||||||
update_list (get_stored_values ());
|
update_list (get_stored_values ());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RecentConfigurationPage::technology_changed (const std::string &)
|
||||||
|
{
|
||||||
|
update_list (get_stored_values ());
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
RecentConfigurationPage::update_list (const std::list<std::vector<std::string> > &stored_values)
|
RecentConfigurationPage::update_list (const std::list<std::vector<std::string> > &stored_values)
|
||||||
{
|
{
|
||||||
|
|
@ -327,7 +363,7 @@ RecentConfigurationPage::item_clicked (QTreeWidgetItem *item)
|
||||||
ex.read (cv_index);
|
ex.read (cv_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
mp_view->set_or_request_current_layer (cv_index, lp);
|
view ()->set_or_request_current_layer (cv_index, lp);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
dispatcher ()->config_set (c->cfg_name, v);
|
dispatcher ()->config_set (c->cfg_name, v);
|
||||||
|
|
@ -349,11 +385,11 @@ RecentConfigurationPage::commit_recent (lay::Dispatcher *root)
|
||||||
|
|
||||||
std::string s;
|
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 ();
|
int cv_index = view ()->current_layer ()->cellview_index ();
|
||||||
const lay::CellView &cv = mp_view->cellview (cv_index);
|
const lay::CellView &cv = view ()->cellview (cv_index);
|
||||||
int li = mp_view->current_layer ()->layer_index ();
|
int li = view ()->current_layer ()->layer_index ();
|
||||||
if (cv.is_valid () && cv->layout ().is_valid_layer (li)) {
|
if (cv.is_valid () && cv->layout ().is_valid_layer (li)) {
|
||||||
s = cv->layout ().get_properties (li).to_string ();
|
s = cv->layout ().get_properties (li).to_string ();
|
||||||
if (cv_index > 0) {
|
if (cv_index > 0) {
|
||||||
|
|
|
||||||
|
|
@ -46,8 +46,7 @@ class EditorOptionsPages;
|
||||||
* @brief The base class for a object properties page
|
* @brief The base class for a object properties page
|
||||||
*/
|
*/
|
||||||
class RecentConfigurationPage
|
class RecentConfigurationPage
|
||||||
: public lay::EditorOptionsPage,
|
: public lay::EditorOptionsPage
|
||||||
public tl::Object
|
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
|
|
@ -79,7 +78,7 @@ public:
|
||||||
|
|
||||||
template <class Iter>
|
template <class Iter>
|
||||||
RecentConfigurationPage (lay::LayoutView *view, lay::Dispatcher *dispatcher, const std::string &recent_cfg_name, Iter begin_cfg, Iter end_cfg)
|
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 ();
|
init ();
|
||||||
}
|
}
|
||||||
|
|
@ -96,7 +95,6 @@ private slots:
|
||||||
void item_clicked (QTreeWidgetItem *item);
|
void item_clicked (QTreeWidgetItem *item);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
lay::LayoutView *mp_view;
|
|
||||||
std::string m_recent_cfg_name;
|
std::string m_recent_cfg_name;
|
||||||
std::list<ConfigurationDescriptor> m_cfg;
|
std::list<ConfigurationDescriptor> m_cfg;
|
||||||
QTreeWidget *mp_tree_widget;
|
QTreeWidget *mp_tree_widget;
|
||||||
|
|
@ -107,6 +105,7 @@ private:
|
||||||
void set_stored_values (const std::list<std::vector<std::string> > &values) const;
|
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 render_to (QTreeWidgetItem *item, int column, const std::vector<std::string> &values, RecentConfigurationPage::ConfigurationRendering rendering);
|
||||||
void layers_changed (int);
|
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 ();
|
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
|
// find the layout the cell has to be looked up: that is either the layout of the current instance or
|
||||||
// the library selected
|
// 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);
|
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
|
// find the layout the cell has to be looked up: that is either the layout of the current instance or
|
||||||
// the library selected
|
// the library selected
|
||||||
|
|
|
||||||
|
|
@ -173,5 +173,58 @@
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
<h2>Multi-mapping and unmapping</h2>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Layer mapping table support an advanced feature which is to duplicate input layers to
|
||||||
|
a number of output layers (1:n) mapping.
|
||||||
|
The feature is enabled by prepending a "+" to the mapping statement. The following
|
||||||
|
statement will first select layer 5/0 and additionally copy it to layer 1000/0:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre>5/0
|
||||||
|
+5/0: 1000/0
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Unmapping removes the mapping for a specific layer or range. It is specified by prepending "-"
|
||||||
|
to the mapping expression. The following statement will map all datatypes of layer 5 to 0 except
|
||||||
|
for datatype 10 which is not considered.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre>5/*: 5/0
|
||||||
|
-5/10
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Unmapping cancels the mappings specified previously, so the order of statements becomes important
|
||||||
|
when using unmapping and multi-mapping.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2>Brackets</h2>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Square brackets can be used to imply mapping to the original layer. When putting square brackets
|
||||||
|
around a mapping expression, the default target is "*/*", which means expansion to the original layer.
|
||||||
|
Hence the following statements are identical:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre>[1-10/*]
|
||||||
|
1-10/* : */*
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
When combining this with "+" for multi-mapping, put "+" in front of the bracket.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
You can put round brackets around mapping expressions for visual clarity, specifically when
|
||||||
|
combining them with "-" (unmapping) or "+" (multi-mapping):
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre>-(1-10/*)
|
||||||
|
+(17/0 : 1017/0)
|
||||||
|
</pre>
|
||||||
|
|
||||||
</doc>
|
</doc>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -122,7 +122,7 @@ LibraryController::sync_files ()
|
||||||
m_file_watcher->enable (false);
|
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
|
// build a list of paths vs. technology
|
||||||
std::vector<std::pair<std::string, std::string> > paths;
|
std::vector<std::pair<std::string, std::string> > paths;
|
||||||
|
|
@ -174,11 +174,11 @@ LibraryController::sync_files ()
|
||||||
QFileInfo fi (tl::to_qstring (lib_path));
|
QFileInfo fi (tl::to_qstring (lib_path));
|
||||||
|
|
||||||
bool needs_load = false;
|
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 ()) {
|
if (ll == m_lib_files.end ()) {
|
||||||
needs_load = true;
|
needs_load = true;
|
||||||
} else {
|
} else {
|
||||||
if (fi.lastModified () > ll->second.second) {
|
if (fi.lastModified () > ll->second.time) {
|
||||||
needs_load = true;
|
needs_load = true;
|
||||||
} else {
|
} else {
|
||||||
new_lib_files.insert (*ll);
|
new_lib_files.insert (*ll);
|
||||||
|
|
@ -189,7 +189,9 @@ LibraryController::sync_files ()
|
||||||
|
|
||||||
std::auto_ptr<db::Library> lib (new db::Library ());
|
std::auto_ptr<db::Library> lib (new db::Library ());
|
||||||
lib->set_description (filename);
|
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 ()));
|
lib->set_name (tl::to_string (QFileInfo (*im).baseName ()));
|
||||||
|
|
||||||
tl::log << "Reading library '" << lib_path << "'";
|
tl::log << "Reading library '" << lib_path << "'";
|
||||||
|
|
@ -205,8 +207,19 @@ LibraryController::sync_files ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tl::log << "Registering as '" << lib->get_name () << "' for tech '" << p->second << "'";
|
if (! p->second.empty ()) {
|
||||||
new_lib_files.insert (std::make_pair (lib_path, std::make_pair (lib->get_name (), fi.lastModified ())));
|
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 ());
|
db::LibraryManager::instance ().register_lib (lib.release ());
|
||||||
|
|
||||||
|
|
@ -230,14 +243,14 @@ LibraryController::sync_files ()
|
||||||
|
|
||||||
std::set<std::string> new_names;
|
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) {
|
for (std::map<std::string, LibInfo>::const_iterator lf = new_lib_files.begin (); lf != new_lib_files.end (); ++lf) {
|
||||||
new_names.insert (lf->second.first);
|
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) {
|
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.first) == new_names.end ()) {
|
if (new_names.find (lf->second.name) == new_names.end ()) {
|
||||||
try {
|
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) {
|
if (li.first) {
|
||||||
db::LibraryManager::instance ().delete_lib (db::LibraryManager::instance ().lib (li.second));
|
db::LibraryManager::instance ().delete_lib (db::LibraryManager::instance ().lib (li.second));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -119,9 +119,17 @@ private slots:
|
||||||
void sync_with_external_sources ();
|
void sync_with_external_sources ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
struct LibInfo
|
||||||
|
{
|
||||||
|
LibInfo () : name (), time (), tech () { }
|
||||||
|
std::string name;
|
||||||
|
QDateTime time;
|
||||||
|
std::set<std::string> tech;
|
||||||
|
};
|
||||||
|
|
||||||
tl::FileSystemWatcher *m_file_watcher;
|
tl::FileSystemWatcher *m_file_watcher;
|
||||||
tl::DeferredMethod<LibraryController> dm_sync_files;
|
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 ();
|
void sync_files ();
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -2506,7 +2506,7 @@ void
|
||||||
MainWindow::cm_new_layout ()
|
MainWindow::cm_new_layout ()
|
||||||
{
|
{
|
||||||
std::string technology = m_initial_technology;
|
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;
|
static double s_new_cell_window_size = 2.0;
|
||||||
|
|
||||||
double dbu = 0.0;
|
double dbu = 0.0;
|
||||||
|
|
|
||||||
|
|
@ -504,7 +504,7 @@ SearchReplaceResults::export_layout (db::Layout &layout)
|
||||||
std::map<unsigned int, db::LayerProperties>::const_iterator lm = m_lp_map.find (layer);
|
std::map<unsigned int, db::LayerProperties>::const_iterator lm = m_lp_map.find (layer);
|
||||||
if (lm != m_lp_map.end ()) {
|
if (lm != m_lp_map.end ()) {
|
||||||
|
|
||||||
std::pair<bool, unsigned int> ll = insert_lm.logical (lm->second);
|
std::pair<bool, unsigned int> ll = insert_lm.first_logical (lm->second);
|
||||||
if (! ll.first) {
|
if (! ll.first) {
|
||||||
layer = layout.insert_layer (lm->second);
|
layer = layout.insert_layer (lm->second);
|
||||||
insert_lm.map (lm->second, layer, lm->second);
|
insert_lm.map (lm->second, layer, lm->second);
|
||||||
|
|
|
||||||
|
|
@ -285,15 +285,29 @@ bool
|
||||||
TechnologyController::menu_activated (const std::string &symbol) const
|
TechnologyController::menu_activated (const std::string &symbol) const
|
||||||
{
|
{
|
||||||
if (symbol == "technology_selector:apply_technology") {
|
if (symbol == "technology_selector:apply_technology") {
|
||||||
|
|
||||||
if (lay::LayoutView::current () && lay::LayoutView::current ()->active_cellview ().is_valid ()) {
|
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) {
|
if (mp_mw) {
|
||||||
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;
|
return true;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
return lay::PluginDeclaration::menu_activated (symbol);
|
return lay::PluginDeclaration::menu_activated (symbol);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,8 @@
|
||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>446</width>
|
<width>536</width>
|
||||||
<height>205</height>
|
<height>290</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
|
|
@ -29,6 +29,19 @@
|
||||||
<property name="spacing">
|
<property name="spacing">
|
||||||
<number>6</number>
|
<number>6</number>
|
||||||
</property>
|
</property>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="QPushButton" name="load_pb">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Load File</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item row="2" column="0">
|
<item row="2" column="0">
|
||||||
<widget class="QLabel" name="help_label">
|
<widget class="QLabel" name="help_label">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
|
|
@ -45,103 +58,114 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="1">
|
<item row="3" column="0" colspan="3">
|
||||||
<widget class="QPushButton" name="load_pb">
|
<widget class="QTabWidget" name="tabs">
|
||||||
<property name="sizePolicy">
|
<property name="currentIndex">
|
||||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
<number>0</number>
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Load File</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="3" column="0" rowspan="6" colspan="2">
|
|
||||||
<widget class="QListWidget" name="layer_lv">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Expanding" vsizetype="Ignored">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="dragEnabled">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<property name="dragDropMode">
|
|
||||||
<enum>QAbstractItemView::InternalMove</enum>
|
|
||||||
</property>
|
|
||||||
<property name="selectionMode">
|
|
||||||
<enum>QAbstractItemView::ExtendedSelection</enum>
|
|
||||||
</property>
|
|
||||||
<property name="uniformItemSizes">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<property name="sortingEnabled">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="3" column="2">
|
|
||||||
<widget class="QToolButton" name="add_pb">
|
|
||||||
<property name="toolTip">
|
|
||||||
<string>Add a new layer to the list</string>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Add</string>
|
|
||||||
</property>
|
|
||||||
<property name="icon">
|
|
||||||
<iconset resource="../lay/layResources.qrc">
|
|
||||||
<normaloff>:/add.png</normaloff>:/add.png</iconset>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="4" column="2">
|
|
||||||
<widget class="QToolButton" name="delete_pb">
|
|
||||||
<property name="toolTip">
|
|
||||||
<string>Delete the selected layers from the list</string>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Delete</string>
|
|
||||||
</property>
|
|
||||||
<property name="icon">
|
|
||||||
<iconset resource="../lay/layResources.qrc">
|
|
||||||
<normaloff>:/clear.png</normaloff>:/clear.png</iconset>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="6" column="2" rowspan="3">
|
|
||||||
<spacer>
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Vertical</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>20</width>
|
|
||||||
<height>5</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
<item row="5" column="2">
|
|
||||||
<widget class="QToolButton" name="edit_pb">
|
|
||||||
<property name="toolTip">
|
|
||||||
<string>Edit the current layer</string>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Edit</string>
|
|
||||||
</property>
|
|
||||||
<property name="icon">
|
|
||||||
<iconset resource="../lay/layResources.qrc">
|
|
||||||
<normaloff>:/edit.png</normaloff>:/edit.png</iconset>
|
|
||||||
</property>
|
</property>
|
||||||
|
<widget class="QWidget" name="tab">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>List</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<item row="0" column="0" rowspan="4">
|
||||||
|
<widget class="QListWidget" name="layer_lv">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Ignored">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="dragEnabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="dragDropMode">
|
||||||
|
<enum>QAbstractItemView::InternalMove</enum>
|
||||||
|
</property>
|
||||||
|
<property name="selectionMode">
|
||||||
|
<enum>QAbstractItemView::ExtendedSelection</enum>
|
||||||
|
</property>
|
||||||
|
<property name="uniformItemSizes">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="sortingEnabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QToolButton" name="add_pb">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Add a new layer to the list</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Add</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="../../lay/lay/layResources.qrc">
|
||||||
|
<normaloff>:/add.png</normaloff>:/add.png</iconset>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QToolButton" name="delete_pb">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Delete the selected layers from the list</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Delete</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="../../lay/lay/layResources.qrc">
|
||||||
|
<normaloff>:/clear.png</normaloff>:/clear.png</iconset>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="QToolButton" name="edit_pb">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Edit the current layer</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Edit</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="../../lay/lay/layResources.qrc">
|
||||||
|
<normaloff>:/edit.png</normaloff>:/edit.png</iconset>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="1">
|
||||||
|
<spacer>
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>5</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QWidget" name="tab_2">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>Text</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_2">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QPlainTextEdit" name="text_edit"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<resources>
|
<resources>
|
||||||
<include location="../lay/layResources.qrc"/>
|
<include location="../../lay/lay/layResources.qrc"/>
|
||||||
</resources>
|
</resources>
|
||||||
<connections/>
|
<connections/>
|
||||||
</ui>
|
</ui>
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,8 @@ LayoutHandle::LayoutHandle (db::Layout *layout, const std::string &filename)
|
||||||
m_dirty (false),
|
m_dirty (false),
|
||||||
m_save_options_valid (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
|
// layouts in the managed layouts space participate in spare proxy cleanup
|
||||||
layout->do_cleanup (true);
|
layout->do_cleanup (true);
|
||||||
|
|
||||||
|
|
@ -108,6 +110,12 @@ LayoutHandle::~LayoutHandle ()
|
||||||
file_watcher ().remove_file (filename ());
|
file_watcher ().remove_file (filename ());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
LayoutHandle::on_technology_changed ()
|
||||||
|
{
|
||||||
|
technology_changed_event ();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
LayoutHandle::layout_changed ()
|
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 *
|
const db::Technology *
|
||||||
LayoutHandle::technology () const
|
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)
|
LayoutHandle::apply_technology (const std::string &tn)
|
||||||
{
|
{
|
||||||
set_tech_name (tn);
|
set_tech_name (tn);
|
||||||
|
|
@ -223,16 +238,8 @@ LayoutHandle::apply_technology (const std::string &tn)
|
||||||
void
|
void
|
||||||
LayoutHandle::set_tech_name (const std::string &tn)
|
LayoutHandle::set_tech_name (const std::string &tn)
|
||||||
{
|
{
|
||||||
if (tn != m_tech_name) {
|
if (mp_layout && tn != tech_name ()) {
|
||||||
if (db::Technologies::instance ()->has_technology (tn)) {
|
mp_layout->set_technology_name (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 ();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -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 there is no technology given and the reader reports one, use this one
|
||||||
if (technology.empty ()) {
|
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 ()) {
|
if (! tech_from_reader.empty ()) {
|
||||||
set_tech_name (tech_from_reader);
|
set_tech_name (tech_from_reader);
|
||||||
}
|
}
|
||||||
|
|
@ -373,7 +380,7 @@ LayoutHandle::load ()
|
||||||
db::LayerMap new_lmap = reader.read (layout (), m_load_options);
|
db::LayerMap new_lmap = reader.read (layout (), m_load_options);
|
||||||
|
|
||||||
// Attach the technology from the reader if it reports one
|
// 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 ()) {
|
if (! tech_from_reader.empty ()) {
|
||||||
set_tech_name (tech_from_reader);
|
set_tech_name (tech_from_reader);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -115,10 +115,7 @@ public:
|
||||||
*
|
*
|
||||||
* An empty name indicates the default technology should be used.
|
* An empty name indicates the default technology should be used.
|
||||||
*/
|
*/
|
||||||
const std::string &tech_name () const
|
const std::string &tech_name () const;
|
||||||
{
|
|
||||||
return m_tech_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Applies the given technology
|
* @brief Applies the given technology
|
||||||
|
|
@ -300,12 +297,13 @@ private:
|
||||||
int m_ref_count;
|
int m_ref_count;
|
||||||
std::string m_name;
|
std::string m_name;
|
||||||
std::string m_filename;
|
std::string m_filename;
|
||||||
std::string m_tech_name;
|
|
||||||
bool m_dirty;
|
bool m_dirty;
|
||||||
db::SaveLayoutOptions m_save_options;
|
db::SaveLayoutOptions m_save_options;
|
||||||
bool m_save_options_valid;
|
bool m_save_options_valid;
|
||||||
db::LoadLayoutOptions m_load_options;
|
db::LoadLayoutOptions m_load_options;
|
||||||
|
|
||||||
|
void on_technology_changed ();
|
||||||
|
|
||||||
static std::map <std::string, LayoutHandle *> ms_dict;
|
static std::map <std::string, LayoutHandle *> ms_dict;
|
||||||
static tl::FileSystemWatcher *mp_file_watcher;
|
static tl::FileSystemWatcher *mp_file_watcher;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@
|
||||||
#include "tlInternational.h"
|
#include "tlInternational.h"
|
||||||
#include "layEditorOptionsPage.h"
|
#include "layEditorOptionsPage.h"
|
||||||
#include "layEditorOptionsPages.h"
|
#include "layEditorOptionsPages.h"
|
||||||
|
#include "layLayoutView.h"
|
||||||
|
|
||||||
namespace lay
|
namespace lay
|
||||||
{
|
{
|
||||||
|
|
@ -31,10 +32,10 @@ namespace lay
|
||||||
// ------------------------------------------------------------------
|
// ------------------------------------------------------------------
|
||||||
// EditorOptionsPage implementation
|
// EditorOptionsPage implementation
|
||||||
|
|
||||||
EditorOptionsPage::EditorOptionsPage (lay::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)
|
: QWidget (0), mp_owner (0), m_active (true), mp_plugin_declaration (0), mp_dispatcher (dispatcher), mp_view (view)
|
||||||
{
|
{
|
||||||
// nothing yet ..
|
attach_events ();
|
||||||
}
|
}
|
||||||
|
|
||||||
EditorOptionsPage::~EditorOptionsPage ()
|
EditorOptionsPage::~EditorOptionsPage ()
|
||||||
|
|
@ -42,6 +43,30 @@ EditorOptionsPage::~EditorOptionsPage ()
|
||||||
set_owner (0);
|
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
|
void
|
||||||
EditorOptionsPage::set_owner (EditorOptionsPages *owner)
|
EditorOptionsPage::set_owner (EditorOptionsPages *owner)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,8 @@
|
||||||
|
|
||||||
#include "laybasicCommon.h"
|
#include "laybasicCommon.h"
|
||||||
|
|
||||||
|
#include "tlObject.h"
|
||||||
|
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
namespace lay
|
namespace lay
|
||||||
|
|
@ -32,19 +34,21 @@ namespace lay
|
||||||
|
|
||||||
class PluginDeclaration;
|
class PluginDeclaration;
|
||||||
class Dispatcher;
|
class Dispatcher;
|
||||||
|
class LayoutView;
|
||||||
class Plugin;
|
class Plugin;
|
||||||
|
class CellView;
|
||||||
class EditorOptionsPages;
|
class EditorOptionsPages;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The base class for a object properties page
|
* @brief The base class for a object properties page
|
||||||
*/
|
*/
|
||||||
class LAYBASIC_PUBLIC EditorOptionsPage
|
class LAYBASIC_PUBLIC EditorOptionsPage
|
||||||
: public QWidget
|
: public QWidget, public tl::Object
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
EditorOptionsPage (lay::Dispatcher *dispatcher);
|
EditorOptionsPage (lay::LayoutView *view, lay::Dispatcher *dispatcher);
|
||||||
virtual ~EditorOptionsPage ();
|
virtual ~EditorOptionsPage ();
|
||||||
|
|
||||||
virtual std::string title () const = 0;
|
virtual std::string title () const = 0;
|
||||||
|
|
@ -72,11 +76,24 @@ protected:
|
||||||
return mp_dispatcher;
|
return mp_dispatcher;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lay::LayoutView *view () const
|
||||||
|
{
|
||||||
|
return mp_view;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void active_cellview_changed () { }
|
||||||
|
virtual void technology_changed (const std::string & /*tech*/) { }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
EditorOptionsPages *mp_owner;
|
EditorOptionsPages *mp_owner;
|
||||||
bool m_active;
|
bool m_active;
|
||||||
const lay::PluginDeclaration *mp_plugin_declaration;
|
const lay::PluginDeclaration *mp_plugin_declaration;
|
||||||
lay::Dispatcher *mp_dispatcher;
|
lay::Dispatcher *mp_dispatcher;
|
||||||
|
lay::LayoutView *mp_view;
|
||||||
|
|
||||||
|
void on_active_cellview_changed ();
|
||||||
|
void on_technology_changed ();
|
||||||
|
void attach_events ();
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,8 @@ LayerMappingWidget::LayerMappingWidget (QWidget *parent)
|
||||||
|
|
||||||
mp_ui->layer_lv->viewport ()->acceptDrops ();
|
mp_ui->layer_lv->viewport ()->acceptDrops ();
|
||||||
|
|
||||||
|
connect (mp_ui->tabs, SIGNAL (currentChanged (int)), this, SLOT (current_tab_changed (int)));
|
||||||
|
|
||||||
mp_layer_table_file_dialog = new lay::FileDialog (this,
|
mp_layer_table_file_dialog = new lay::FileDialog (this,
|
||||||
tl::to_string (QObject::tr ("Load Layer Table")),
|
tl::to_string (QObject::tr ("Load Layer Table")),
|
||||||
tl::to_string (QObject::tr ("Layer properties and text files (*.lyp *.txt);;Layer properties files (*.lyp);;Text files (*.txt);;All files (*)")));
|
tl::to_string (QObject::tr ("Layer properties and text files (*.lyp *.txt);;Layer properties files (*.lyp);;Text files (*.txt);;All files (*)")));
|
||||||
|
|
@ -72,6 +74,8 @@ LayerMappingWidget::set_layer_map (const db::LayerMap &lm)
|
||||||
{
|
{
|
||||||
std::vector<unsigned int> layer_ids = lm.get_layers ();
|
std::vector<unsigned int> layer_ids = lm.get_layers ();
|
||||||
|
|
||||||
|
mp_ui->text_edit->setPlainText (tl::to_qstring (lm.to_string_file_format ()));
|
||||||
|
|
||||||
mp_ui->layer_lv->reset ();
|
mp_ui->layer_lv->reset ();
|
||||||
mp_ui->layer_lv->clear ();
|
mp_ui->layer_lv->clear ();
|
||||||
|
|
||||||
|
|
@ -88,16 +92,31 @@ LayerMappingWidget::set_layer_map (const db::LayerMap &lm)
|
||||||
|
|
||||||
db::LayerMap
|
db::LayerMap
|
||||||
LayerMappingWidget::get_layer_map () const
|
LayerMappingWidget::get_layer_map () const
|
||||||
|
{
|
||||||
|
return get_layer_map_from_tab (mp_ui->tabs->currentIndex ());
|
||||||
|
}
|
||||||
|
|
||||||
|
db::LayerMap
|
||||||
|
LayerMappingWidget::get_layer_map_from_tab (int tab) const
|
||||||
{
|
{
|
||||||
db::LayerMap lm;
|
db::LayerMap lm;
|
||||||
for (int i = 0; i < mp_ui->layer_lv->count (); ++i) {
|
|
||||||
std::string t = tl::to_string (mp_ui->layer_lv->item (i)->data (Qt::DisplayRole).toString ());
|
if (tab == 0) {
|
||||||
try {
|
|
||||||
lm.map_expr (t, (unsigned int) i);
|
for (int i = 0; i < mp_ui->layer_lv->count (); ++i) {
|
||||||
} catch (...) {
|
std::string t = tl::to_string (mp_ui->layer_lv->item (i)->data (Qt::DisplayRole).toString ());
|
||||||
mp_ui->layer_lv->setCurrentItem (mp_ui->layer_lv->item (i));
|
try {
|
||||||
throw;
|
lm.add_expr (t, (unsigned int) i);
|
||||||
|
} catch (...) {
|
||||||
|
mp_ui->layer_lv->setCurrentItem (mp_ui->layer_lv->item (i));
|
||||||
|
throw;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
lm = db::LayerMap::from_string_file_format (tl::to_string (mp_ui->text_edit->toPlainText ()));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return lm;
|
return lm;
|
||||||
|
|
@ -128,17 +147,19 @@ LayerMappingWidget::load_button_pressed ()
|
||||||
mp_ui->layer_lv->reset ();
|
mp_ui->layer_lv->reset ();
|
||||||
mp_ui->layer_lv->clear ();
|
mp_ui->layer_lv->clear ();
|
||||||
|
|
||||||
|
db::LayerMap lm;
|
||||||
|
|
||||||
// use those layers which have cellview index 0
|
// use those layers which have cellview index 0
|
||||||
|
unsigned int n = 0;
|
||||||
for (LayerPropertiesConstIterator lay_iter = props.begin_const_recursive (); ! lay_iter.at_end (); ++lay_iter) {
|
for (LayerPropertiesConstIterator lay_iter = props.begin_const_recursive (); ! lay_iter.at_end (); ++lay_iter) {
|
||||||
if (! lay_iter->has_children () && lay_iter->source (true /*=real*/).cv_index () == 0) {
|
if (! lay_iter->has_children () && lay_iter->source (true /*=real*/).cv_index () == 0) {
|
||||||
db::LayerProperties db_lp = lay_iter->source (true /*=real*/).layer_props ();
|
db::LayerProperties db_lp = lay_iter->source (true /*=real*/).layer_props ();
|
||||||
QListWidgetItem *item = new QListWidgetItem (mp_ui->layer_lv);
|
lm.map (db_lp, (unsigned int) n++);
|
||||||
item->setData (Qt::DisplayRole, tl::to_qstring (db_lp.to_string ()));
|
|
||||||
item->setFlags (item->flags () | Qt::ItemIsEditable);
|
|
||||||
mp_ui->layer_lv->addItem (item);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
set_layer_map (lm);
|
||||||
|
|
||||||
// if successful, stop now.
|
// if successful, stop now.
|
||||||
success = true;
|
success = true;
|
||||||
|
|
||||||
|
|
@ -230,5 +251,11 @@ LayerMappingWidget::edit_button_pressed ()
|
||||||
END_PROTECTED
|
END_PROTECTED
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
LayerMappingWidget::current_tab_changed (int index)
|
||||||
|
{
|
||||||
|
set_layer_map (get_layer_map_from_tab (1 - index));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -84,11 +84,14 @@ private slots:
|
||||||
void add_button_pressed ();
|
void add_button_pressed ();
|
||||||
void delete_button_pressed ();
|
void delete_button_pressed ();
|
||||||
void edit_button_pressed ();
|
void edit_button_pressed ();
|
||||||
|
void current_tab_changed (int tab);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
lay::FileDialog *mp_layer_table_file_dialog;
|
lay::FileDialog *mp_layer_table_file_dialog;
|
||||||
std::string m_layer_table_file;
|
std::string m_layer_table_file;
|
||||||
Ui::LayerMappingWidget *mp_ui;
|
Ui::LayerMappingWidget *mp_ui;
|
||||||
|
|
||||||
|
db::LayerMap get_layer_map_from_tab (int tab) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace lay
|
} // namespace lay
|
||||||
|
|
|
||||||
|
|
@ -2538,7 +2538,7 @@ LayoutView::erase_cellview (unsigned int index)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
cancel ();
|
cancel_esc ();
|
||||||
|
|
||||||
// issue to event that signals a change in the cellviews
|
// issue to event that signals a change in the cellviews
|
||||||
cellviews_about_to_change_event ();
|
cellviews_about_to_change_event ();
|
||||||
|
|
@ -2704,6 +2704,8 @@ LayoutView::signal_apply_technology (lay::LayoutHandle *layout_handle)
|
||||||
|
|
||||||
if (cellview (i).handle () == layout_handle) {
|
if (cellview (i).handle () == layout_handle) {
|
||||||
|
|
||||||
|
cancel_esc ();
|
||||||
|
|
||||||
std::string lyp_file;
|
std::string lyp_file;
|
||||||
const db::Technology *tech = db::Technologies::instance ()->technology_by_name (cellview (i)->tech_name ());
|
const db::Technology *tech = db::Technologies::instance ()->technology_by_name (cellview (i)->tech_name ());
|
||||||
if (tech && ! tech->eff_layer_properties_file ().empty ()) {
|
if (tech && ! tech->eff_layer_properties_file ().empty ()) {
|
||||||
|
|
@ -3056,7 +3058,7 @@ void
|
||||||
LayoutView::reload_layout (unsigned int cv_index)
|
LayoutView::reload_layout (unsigned int cv_index)
|
||||||
{
|
{
|
||||||
stop ();
|
stop ();
|
||||||
cancel ();
|
cancel_esc ();
|
||||||
|
|
||||||
// save the current view state
|
// save the current view state
|
||||||
lay::DisplayState state;
|
lay::DisplayState state;
|
||||||
|
|
@ -3948,6 +3950,13 @@ LayoutView::cancel ()
|
||||||
clear_selection ();
|
clear_selection ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
LayoutView::cancel_esc ()
|
||||||
|
{
|
||||||
|
cancel ();
|
||||||
|
switch_mode (default_mode ());
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
LayoutView::bookmark_current_view ()
|
LayoutView::bookmark_current_view ()
|
||||||
{
|
{
|
||||||
|
|
@ -4751,7 +4760,7 @@ LayoutView::select_cellviews_fit (const std::list <CellView> &cvs)
|
||||||
cellviews_about_to_change_event ();
|
cellviews_about_to_change_event ();
|
||||||
|
|
||||||
set_min_hier_levels (0);
|
set_min_hier_levels (0);
|
||||||
cancel ();
|
cancel_esc ();
|
||||||
m_cellviews = cvs;
|
m_cellviews = cvs;
|
||||||
zoom_fit ();
|
zoom_fit ();
|
||||||
finish_cellviews_changed ();
|
finish_cellviews_changed ();
|
||||||
|
|
@ -4772,6 +4781,12 @@ LayoutView::active_cellview_changed (int index)
|
||||||
{
|
{
|
||||||
if (m_active_cellview_changed_event_enabled) {
|
if (m_active_cellview_changed_event_enabled) {
|
||||||
|
|
||||||
|
// we need to cancel pending drawing or dragging operations to reflect the new cellview (different target, may have different technology etc.)
|
||||||
|
cancel_esc ();
|
||||||
|
|
||||||
|
// we need to setup the editor option pages because the technology may have changed
|
||||||
|
dm_setup_editor_option_pages ();
|
||||||
|
|
||||||
active_cellview_changed_event ();
|
active_cellview_changed_event ();
|
||||||
active_cellview_changed_with_index_event (index);
|
active_cellview_changed_with_index_event (index);
|
||||||
|
|
||||||
|
|
@ -4889,7 +4904,7 @@ LayoutView::select_cellviews (const std::list <CellView> &cvs)
|
||||||
cellviews_about_to_change_event ();
|
cellviews_about_to_change_event ();
|
||||||
|
|
||||||
set_min_hier_levels (0);
|
set_min_hier_levels (0);
|
||||||
cancel ();
|
cancel_esc ();
|
||||||
m_cellviews = cvs;
|
m_cellviews = cvs;
|
||||||
redraw ();
|
redraw ();
|
||||||
|
|
||||||
|
|
@ -4914,7 +4929,7 @@ LayoutView::select_cellview (int index, const CellView &cv)
|
||||||
|
|
||||||
cellview_about_to_change_event (index);
|
cellview_about_to_change_event (index);
|
||||||
|
|
||||||
cancel ();
|
cancel_esc ();
|
||||||
*cellview_iter (index) = cv;
|
*cellview_iter (index) = cv;
|
||||||
redraw ();
|
redraw ();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2576,12 +2576,17 @@ public slots:
|
||||||
void store_state ();
|
void store_state ();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Cancel all edit operations and clear the selection
|
* @brief Cancels all edit operations, clears the selection and resets the mode to "Select"
|
||||||
|
*/
|
||||||
|
void cancel_esc ();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Cancels all edit operations and clears the selection
|
||||||
*/
|
*/
|
||||||
void cancel ();
|
void cancel ();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Cancel all edit operations but leave selection
|
* @brief Cancels all edit operations but maintains selection
|
||||||
*/
|
*/
|
||||||
void cancel_edits ();
|
void cancel_edits ();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -530,16 +530,28 @@ LibrariesView::do_update_content (int lib_index)
|
||||||
|
|
||||||
size_t imin = (lib_index < 0 ? 0 : (size_t) 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);
|
size_t imax = (lib_index < 0 ? std::numeric_limits <size_t>::max () : (size_t) lib_index);
|
||||||
|
std::string tech_name;
|
||||||
|
|
||||||
// rebuild all events
|
// rebuild all events
|
||||||
detach_from_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);
|
db::LibraryManager::instance ().changed_event.add (this, &LibrariesView::update_required);
|
||||||
|
|
||||||
std::vector<db::Library *> libraries;
|
std::vector<db::Library *> libraries;
|
||||||
for (db::LibraryManager::iterator lib = db::LibraryManager::instance ().begin (); lib != db::LibraryManager::instance ().end (); ++lib) {
|
for (db::LibraryManager::iterator lib = db::LibraryManager::instance ().begin (); lib != db::LibraryManager::instance ().end (); ++lib) {
|
||||||
libraries.push_back (db::LibraryManager::instance ().lib (lib->second));
|
db::Library *lib_ptr = db::LibraryManager::instance ().lib (lib->second);
|
||||||
libraries.back ()->layout ().hier_changed_event.add (this, &LibrariesView::update_required);
|
if (! lib_ptr->for_technologies () || lib_ptr->is_for_technology (tech_name)) {
|
||||||
libraries.back ()->retired_state_changed_event.add (this, &LibrariesView::update_required);
|
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) {
|
for (size_t i = imin; i < libraries.size () && i <= imax; ++i) {
|
||||||
|
|
|
||||||
|
|
@ -298,6 +298,7 @@ struct LayerSelectionComboBoxPrivateData
|
||||||
const db::Layout *layout;
|
const db::Layout *layout;
|
||||||
lay::LayoutView *view;
|
lay::LayoutView *view;
|
||||||
int cv_index;
|
int cv_index;
|
||||||
|
db::LayerProperties last_props;
|
||||||
};
|
};
|
||||||
|
|
||||||
LayerSelectionComboBox::LayerSelectionComboBox (QWidget *parent)
|
LayerSelectionComboBox::LayerSelectionComboBox (QWidget *parent)
|
||||||
|
|
@ -419,11 +420,19 @@ LayerSelectionComboBox::set_view (lay::LayoutView *view, int cv_index, bool all_
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mp_private->layout = &view->cellview (cv_index)->layout ();
|
mp_private->layout = 0;
|
||||||
mp_private->view = view;
|
mp_private->view = view;
|
||||||
mp_private->cv_index = cv_index;
|
mp_private->cv_index = cv_index;
|
||||||
mp_private->all_layers = all_layers;
|
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 ();
|
update_layer_list ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -442,7 +451,7 @@ void
|
||||||
LayerSelectionComboBox::update_layer_list ()
|
LayerSelectionComboBox::update_layer_list ()
|
||||||
{
|
{
|
||||||
int i = currentIndex ();
|
int i = currentIndex ();
|
||||||
db::LayerProperties props;
|
db::LayerProperties props = mp_private->last_props;
|
||||||
if (i >= 0 && i < int (mp_private->layers.size ())) {
|
if (i >= 0 && i < int (mp_private->layers.size ())) {
|
||||||
props = mp_private->layers [i].first;
|
props = mp_private->layers [i].first;
|
||||||
}
|
}
|
||||||
|
|
@ -456,45 +465,60 @@ LayerSelectionComboBox::update_layer_list ()
|
||||||
|
|
||||||
if (mp_private->view) {
|
if (mp_private->view) {
|
||||||
|
|
||||||
LPIPairCompareOp cmp_op;
|
const db::Layout *layout = 0;
|
||||||
std::map<std::pair <db::LayerProperties, int>, std::string, LPIPairCompareOp> name_for_layer (cmp_op);
|
|
||||||
LayerPropertiesConstIterator lp = mp_private->view->begin_layers ();
|
const CellView &cv = mp_private->view->cellview (mp_private->cv_index);
|
||||||
while (! lp.at_end ()) {
|
if (cv.is_valid ()) {
|
||||||
if (lp->cellview_index () == mp_private->cv_index && ! lp->has_children () && (mp_private->all_layers || lp->layer_index () >= 0) && lp->source (true).layer_props () != db::LayerProperties ()) {
|
layout = & cv->layout ();
|
||||||
std::pair <db::LayerProperties, int> k (lp->source (true).layer_props (), lp->layer_index ());
|
|
||||||
name_for_layer.insert (std::make_pair (k, lp->display_string (mp_private->view, true, true /*always show source*/)));
|
|
||||||
mp_private->layers.push_back (k);
|
|
||||||
}
|
|
||||||
++lp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t nk = mp_private->layers.size ();
|
if (! layout) {
|
||||||
|
|
||||||
for (unsigned int l = 0; l < mp_private->layout->layers (); ++l) {
|
set_current_layer (-1);
|
||||||
if (mp_private->layout->is_valid_layer (l)) {
|
|
||||||
std::pair <db::LayerProperties, int> k (mp_private->layout->get_properties (l), int (l));
|
} else {
|
||||||
if (name_for_layer.find (k) == name_for_layer.end ()) {
|
|
||||||
|
LPIPairCompareOp cmp_op;
|
||||||
|
std::map<std::pair <db::LayerProperties, int>, std::string, LPIPairCompareOp> name_for_layer (cmp_op);
|
||||||
|
LayerPropertiesConstIterator lp = mp_private->view->begin_layers ();
|
||||||
|
while (! lp.at_end ()) {
|
||||||
|
if (lp->cellview_index () == mp_private->cv_index && ! lp->has_children () && (mp_private->all_layers || lp->layer_index () >= 0) && lp->source (true).layer_props () != db::LayerProperties ()) {
|
||||||
|
std::pair <db::LayerProperties, int> k (lp->source (true).layer_props (), lp->layer_index ());
|
||||||
|
name_for_layer.insert (std::make_pair (k, lp->display_string (mp_private->view, true, true /*always show source*/)));
|
||||||
mp_private->layers.push_back (k);
|
mp_private->layers.push_back (k);
|
||||||
}
|
}
|
||||||
|
++lp;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
std::sort (mp_private->layers.begin () + nk, mp_private->layers.end ());
|
size_t nk = mp_private->layers.size ();
|
||||||
|
|
||||||
for (std::vector <std::pair <db::LayerProperties, int> >::iterator ll = mp_private->layers.begin (); ll != mp_private->layers.end (); ++ll) {
|
for (unsigned int l = 0; l < layout->layers (); ++l) {
|
||||||
std::map<std::pair <db::LayerProperties, int>, std::string, LPIPairCompareOp>::const_iterator ln = name_for_layer.find (*ll);
|
if (layout->is_valid_layer (l)) {
|
||||||
if (ln != name_for_layer.end ()) {
|
std::pair <db::LayerProperties, int> k (layout->get_properties (l), int (l));
|
||||||
addItem (tl::to_qstring (ln->second));
|
if (name_for_layer.find (k) == name_for_layer.end ()) {
|
||||||
} else {
|
mp_private->layers.push_back (k);
|
||||||
addItem (tl::to_qstring (ll->first.to_string ()));
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (mp_private->new_layer_enabled) {
|
std::sort (mp_private->layers.begin () + nk, mp_private->layers.end ());
|
||||||
addItem (QObject::tr ("New Layer .."));
|
|
||||||
}
|
|
||||||
|
|
||||||
set_current_layer (props);
|
for (std::vector <std::pair <db::LayerProperties, int> >::iterator ll = mp_private->layers.begin (); ll != mp_private->layers.end (); ++ll) {
|
||||||
|
std::map<std::pair <db::LayerProperties, int>, std::string, LPIPairCompareOp>::const_iterator ln = name_for_layer.find (*ll);
|
||||||
|
if (ln != name_for_layer.end ()) {
|
||||||
|
addItem (tl::to_qstring (ln->second));
|
||||||
|
} else {
|
||||||
|
addItem (tl::to_qstring (ll->first.to_string ()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mp_private->new_layer_enabled) {
|
||||||
|
addItem (QObject::tr ("New Layer .."));
|
||||||
|
}
|
||||||
|
|
||||||
|
set_current_layer (props);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
} else if (mp_private->layout) {
|
} else if (mp_private->layout) {
|
||||||
|
|
||||||
|
|
@ -522,6 +546,8 @@ LayerSelectionComboBox::update_layer_list ()
|
||||||
void
|
void
|
||||||
LayerSelectionComboBox::set_current_layer (const db::LayerProperties &props)
|
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) {
|
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)) {
|
if (ll->first.log_equal (props)) {
|
||||||
setCurrentIndex (std::distance (mp_private->layers.begin (), ll));
|
setCurrentIndex (std::distance (mp_private->layers.begin (), ll));
|
||||||
|
|
@ -562,7 +588,7 @@ LayerSelectionComboBox::current_layer_props () const
|
||||||
{
|
{
|
||||||
int i = currentIndex ();
|
int i = currentIndex ();
|
||||||
if (i < 0 || i > int (mp_private->layers.size ())) {
|
if (i < 0 || i > int (mp_private->layers.size ())) {
|
||||||
return db::LayerProperties ();
|
return mp_private->last_props;
|
||||||
} else {
|
} else {
|
||||||
return mp_private->layers [i].first;
|
return mp_private->layers [i].first;
|
||||||
}
|
}
|
||||||
|
|
@ -600,7 +626,7 @@ LibrarySelectionComboBox::update_list ()
|
||||||
for (db::LibraryManager::iterator l = db::LibraryManager::instance ().begin (); l != db::LibraryManager::instance ().end (); ++l) {
|
for (db::LibraryManager::iterator l = db::LibraryManager::instance ().begin (); l != db::LibraryManager::instance ().end (); ++l) {
|
||||||
|
|
||||||
db::Library *lib = db::LibraryManager::instance ().lib (l->second);
|
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 ();
|
std::string item_text = lib->get_name ();
|
||||||
if (! lib->get_description ().empty ()) {
|
if (! lib->get_description ().empty ()) {
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,8 @@
|
||||||
|
|
||||||
#include "laybasicCommon.h"
|
#include "laybasicCommon.h"
|
||||||
|
|
||||||
|
#include "tlObject.h"
|
||||||
|
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
#include <QComboBox>
|
#include <QComboBox>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
|
|
@ -170,7 +172,7 @@ private:
|
||||||
* This combo box allows selecting a (physical) layer from a layout
|
* This combo box allows selecting a (physical) layer from a layout
|
||||||
*/
|
*/
|
||||||
class LAYBASIC_PUBLIC LayerSelectionComboBox
|
class LAYBASIC_PUBLIC LayerSelectionComboBox
|
||||||
: public QComboBox
|
: public QComboBox, public tl::Object
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
|
|
@ -249,6 +251,7 @@ protected slots:
|
||||||
private:
|
private:
|
||||||
LayerSelectionComboBoxPrivateData *mp_private;
|
LayerSelectionComboBoxPrivateData *mp_private;
|
||||||
|
|
||||||
|
void on_layer_list_changed (int);
|
||||||
void update_layer_list ();
|
void update_layer_list ();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -59,22 +59,20 @@ CIFReader::~CIFReader ()
|
||||||
const LayerMap &
|
const LayerMap &
|
||||||
CIFReader::read (db::Layout &layout, const db::LoadLayoutOptions &options)
|
CIFReader::read (db::Layout &layout, const db::LoadLayoutOptions &options)
|
||||||
{
|
{
|
||||||
prepare_layers ();
|
|
||||||
|
|
||||||
const db::CIFReaderOptions &specific_options = options.get_options<db::CIFReaderOptions> ();
|
const db::CIFReaderOptions &specific_options = options.get_options<db::CIFReaderOptions> ();
|
||||||
m_wire_mode = specific_options.wire_mode;
|
m_wire_mode = specific_options.wire_mode;
|
||||||
m_dbu = specific_options.dbu;
|
m_dbu = specific_options.dbu;
|
||||||
|
|
||||||
db::LayerMap lm = specific_options.layer_map;
|
set_layer_map (specific_options.layer_map);
|
||||||
lm.prepare (layout);
|
|
||||||
set_layer_map (lm);
|
|
||||||
set_create_layers (specific_options.create_other_layers);
|
set_create_layers (specific_options.create_other_layers);
|
||||||
set_keep_layer_names (specific_options.keep_layer_names);
|
set_keep_layer_names (specific_options.keep_layer_names);
|
||||||
|
|
||||||
|
prepare_layers (layout);
|
||||||
|
|
||||||
do_read (layout);
|
do_read (layout);
|
||||||
|
|
||||||
finish_layers (layout);
|
finish_layers (layout);
|
||||||
return layer_map ();
|
return layer_map_out ();
|
||||||
}
|
}
|
||||||
|
|
||||||
const LayerMap &
|
const LayerMap &
|
||||||
|
|
|
||||||
|
|
@ -39,13 +39,8 @@ static void run_test (tl::TestBase *_this, const std::string &base, const char *
|
||||||
unsigned int ln = 0;
|
unsigned int ln = 0;
|
||||||
tl::Extractor ex (map);
|
tl::Extractor ex (map);
|
||||||
while (! ex.at_end ()) {
|
while (! ex.at_end ()) {
|
||||||
std::string n;
|
lm.add_expr (ex, ln++);
|
||||||
int l;
|
|
||||||
ex.read_word_or_quoted (n);
|
|
||||||
ex.test (":");
|
|
||||||
ex.read (l);
|
|
||||||
ex.test (",");
|
ex.test (",");
|
||||||
lm.map (n, ln++, db::LayerProperties (l, 0));
|
|
||||||
}
|
}
|
||||||
opt->layer_map = lm;
|
opt->layer_map = lm;
|
||||||
opt->create_other_layers = true;
|
opt->create_other_layers = true;
|
||||||
|
|
@ -173,6 +168,11 @@ TEST(3b)
|
||||||
run_test (_this, tl::testsrc_private (), "t3.cif.gz", "t3b_au.gds.gz", "CAA:43,CCA:48,CCP:47,CMF:49,CMS:51,CPG:46,CSN:45,CSP:44,CVA:50,CWN:42,XP:26", 0.00012);
|
run_test (_this, tl::testsrc_private (), "t3.cif.gz", "t3b_au.gds.gz", "CAA:43,CCA:48,CCP:47,CMF:49,CMS:51,CPG:46,CSN:45,CSP:44,CVA:50,CWN:42,XP:26", 0.00012);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(3c)
|
||||||
|
{
|
||||||
|
run_test (_this, tl::testsrc_private (), "t3.cif.gz", "t3c_au.gds.gz", "(CPG:1/0) +(CPG:1000/0) (CCP:1/0) (CMF:2/0) +(CMF:1000/0) (CVA:3/0)", 0.00012);
|
||||||
|
}
|
||||||
|
|
||||||
TEST(4)
|
TEST(4)
|
||||||
{
|
{
|
||||||
run_test (_this, tl::testsrc_private (), "t4.cif.gz", "t4_au.gds.gz");
|
run_test (_this, tl::testsrc_private (), "t4.cif.gz", "t4_au.gds.gz");
|
||||||
|
|
|
||||||
|
|
@ -318,9 +318,7 @@ DXFReader::read (db::Layout &layout, const db::LoadLayoutOptions &options)
|
||||||
m_stream.reset ();
|
m_stream.reset ();
|
||||||
m_initial = true;
|
m_initial = true;
|
||||||
m_line_number = 0;
|
m_line_number = 0;
|
||||||
db::LayerMap lm = specific_options.layer_map;
|
set_layer_map (specific_options.layer_map);
|
||||||
lm.prepare (layout);
|
|
||||||
set_layer_map (lm);
|
|
||||||
set_create_layers (specific_options.create_other_layers);
|
set_create_layers (specific_options.create_other_layers);
|
||||||
set_keep_layer_names (specific_options.keep_layer_names);
|
set_keep_layer_names (specific_options.keep_layer_names);
|
||||||
|
|
||||||
|
|
@ -330,7 +328,7 @@ DXFReader::read (db::Layout &layout, const db::LoadLayoutOptions &options)
|
||||||
do_read (layout, top);
|
do_read (layout, top);
|
||||||
cleanup (layout, top);
|
cleanup (layout, top);
|
||||||
|
|
||||||
return layer_map ();
|
return layer_map_out ();
|
||||||
}
|
}
|
||||||
|
|
||||||
const LayerMap &
|
const LayerMap &
|
||||||
|
|
@ -366,43 +364,31 @@ DXFReader::warn (const std::string &msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair <bool, unsigned int>
|
|
||||||
DXFReader::open_layer (db::Layout &layout, const std::string &n)
|
|
||||||
{
|
|
||||||
if (n == zero_layer_name) {
|
|
||||||
return std::make_pair (true, m_zero_layer);
|
|
||||||
} else {
|
|
||||||
return NamedLayerReader::open_layer (layout, n);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
DXFReader::do_read (db::Layout &layout, db::cell_index_type top)
|
DXFReader::do_read (db::Layout &layout, db::cell_index_type top)
|
||||||
{
|
{
|
||||||
|
prepare_layers (layout);
|
||||||
|
|
||||||
// create the zero layer - this is not mapped to GDS but can be specified in the layer mapping as
|
// create the zero layer - this is not mapped to GDS but can be specified in the layer mapping as
|
||||||
// a layer named "0".
|
// a layer named "0".
|
||||||
std::pair<bool, unsigned int> ll = layer_map ().logical (zero_layer_name, layout);
|
|
||||||
if (ll.first) {
|
|
||||||
|
|
||||||
// create the layer if it is not part of the layout yet.
|
std::pair<bool, unsigned int> li = NamedLayerReader::open_layer (layout, zero_layer_name, true /*keep layer name*/, false /*don't create a new layer*/);
|
||||||
if (! layout.is_valid_layer (ll.second)) {
|
if (li.first) {
|
||||||
layout.insert_layer (ll.second, layer_map ().mapping (ll.second));
|
|
||||||
}
|
|
||||||
|
|
||||||
m_zero_layer = ll.second;
|
// we got one from the layer mapping
|
||||||
|
m_zero_layer = li.second;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// or explicitly create the layer:
|
// or we explicitly create the layer
|
||||||
m_zero_layer = layer_map ().next_index ();
|
db::LayerProperties lp_zero (0, 0, zero_layer_name);
|
||||||
layout.insert_layer (m_zero_layer, db::LayerProperties (0, 0, zero_layer_name));
|
m_zero_layer = layout.insert_layer (lp_zero);
|
||||||
map_layer (zero_layer_name, m_zero_layer);
|
map_layer (zero_layer_name, m_zero_layer);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
prepare_layers ();
|
// Read sections
|
||||||
|
|
||||||
// Read sections
|
|
||||||
int g;
|
int g;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
|
|
|
||||||
|
|
@ -193,7 +193,6 @@ private:
|
||||||
|
|
||||||
void do_read (db::Layout &layout, db::cell_index_type top);
|
void do_read (db::Layout &layout, db::cell_index_type top);
|
||||||
|
|
||||||
std::pair <bool, unsigned int> open_layer (db::Layout &layout, const std::string &n);
|
|
||||||
db::cell_index_type make_layer_variant (db::Layout &layout, const std::string &cellname, db::cell_index_type template_cell, unsigned int layer, double sx, double sy);
|
db::cell_index_type make_layer_variant (db::Layout &layout, const std::string &cellname, db::cell_index_type template_cell, unsigned int layer, double sx, double sy);
|
||||||
void cleanup (db::Layout &layout, db::cell_index_type top);
|
void cleanup (db::Layout &layout, db::cell_index_type top);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ TARGET = dxf_tests
|
||||||
include($$PWD/../../../../lib_ut.pri)
|
include($$PWD/../../../../lib_ut.pri)
|
||||||
|
|
||||||
SOURCES = \
|
SOURCES = \
|
||||||
dbDXFReader.cc \
|
dbDXFReaderTests.cc
|
||||||
|
|
||||||
INCLUDEPATH += $$LAY_INC $$TL_INC $$DB_INC $$GSI_INC $$PWD/../db_plugin $$PWD/../../../common
|
INCLUDEPATH += $$LAY_INC $$TL_INC $$DB_INC $$GSI_INC $$PWD/../db_plugin $$PWD/../../../common
|
||||||
DEPENDPATH += $$LAY_INC $$TL_INC $$DB_INC $$GSI_INC $$PWD/../db_plugin $$PWD/../../../common
|
DEPENDPATH += $$LAY_INC $$TL_INC $$DB_INC $$GSI_INC $$PWD/../db_plugin $$PWD/../../../common
|
||||||
|
|
|
||||||
|
|
@ -51,23 +51,11 @@ GDS2ReaderText::~GDS2ReaderText()
|
||||||
// .. nothing yet ..
|
// .. nothing yet ..
|
||||||
}
|
}
|
||||||
|
|
||||||
const LayerMap &
|
void
|
||||||
GDS2ReaderText::read (db::Layout &layout, const db::LoadLayoutOptions &options)
|
GDS2ReaderText::init (const db::LoadLayoutOptions &options)
|
||||||
{
|
{
|
||||||
|
GDS2ReaderBase::init (options);
|
||||||
storedRecId = 0;
|
storedRecId = 0;
|
||||||
|
|
||||||
// HINT: reuse the standard GDS2 reader options for the text reader.
|
|
||||||
// However, the allow_big_records and allow_multi_xy_records options are ignored.
|
|
||||||
db::GDS2ReaderOptions gds2_options = options.get_options<db::GDS2ReaderOptions> ();
|
|
||||||
db::CommonReaderOptions common_options = options.get_options<db::CommonReaderOptions> ();
|
|
||||||
|
|
||||||
return basic_read (layout, common_options.layer_map, common_options.create_other_layers, common_options.enable_text_objects, common_options.enable_properties, false, gds2_options.box_mode, common_options.cell_conflict_resolution);
|
|
||||||
}
|
|
||||||
|
|
||||||
const LayerMap &
|
|
||||||
GDS2ReaderText::read (db::Layout &layout)
|
|
||||||
{
|
|
||||||
return read (layout, db::LoadLayoutOptions ());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
||||||
|
|
@ -64,43 +64,14 @@ public:
|
||||||
*/
|
*/
|
||||||
~GDS2ReaderText();
|
~GDS2ReaderText();
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The basic read method
|
|
||||||
*
|
|
||||||
* This method will read the stream data and translate this to
|
|
||||||
* insert calls into the layout object. This will not do much
|
|
||||||
* on the layout object beside inserting the objects.
|
|
||||||
* It can be given a couple of options specified with the
|
|
||||||
* LoadLayoutOptions object.
|
|
||||||
* The returned map will contain all layers, the passed
|
|
||||||
* ones and the newly created ones.
|
|
||||||
*
|
|
||||||
* @param layout The layout object to write to
|
|
||||||
* @param options The generic reader options
|
|
||||||
* @return The LayerMap object that tells where which layer was loaded
|
|
||||||
*/
|
|
||||||
virtual const LayerMap &read (db::Layout &layout, const LoadLayoutOptions &options);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The basic read method (without mapping)
|
|
||||||
*
|
|
||||||
* This method will read the stream data and translate this to
|
|
||||||
* insert calls into the layout object. This will not do much
|
|
||||||
* on the layout object beside inserting the objects.
|
|
||||||
* This version will read all input layers and return a map
|
|
||||||
* which tells which GDS2 layer has been read into which logical
|
|
||||||
* layer.
|
|
||||||
*
|
|
||||||
* @param layout The layout object to write to
|
|
||||||
* @return The LayerMap object
|
|
||||||
*/
|
|
||||||
virtual const LayerMap &read (db::Layout &layout);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Format
|
* @brief Format
|
||||||
*/
|
*/
|
||||||
const char *format () const { return "GDS2Text"; }
|
const char *format () const { return "GDS2Text"; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void init (const LoadLayoutOptions &options);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
tl::TextInputStream sStream;
|
tl::TextInputStream sStream;
|
||||||
std::string sExtractedValue;
|
std::string sExtractedValue;
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,7 @@ GDS2Reader::GDS2Reader (tl::InputStream &s)
|
||||||
m_recptr (0),
|
m_recptr (0),
|
||||||
mp_rec_buf (0),
|
mp_rec_buf (0),
|
||||||
m_stored_rec (0),
|
m_stored_rec (0),
|
||||||
|
m_allow_big_records (true),
|
||||||
m_progress (tl::to_string (tr ("Reading GDS2 file")), 10000)
|
m_progress (tl::to_string (tr ("Reading GDS2 file")), 10000)
|
||||||
{
|
{
|
||||||
m_progress.set_format (tl::to_string (tr ("%.0f MB")));
|
m_progress.set_format (tl::to_string (tr ("%.0f MB")));
|
||||||
|
|
@ -54,23 +55,16 @@ GDS2Reader::~GDS2Reader ()
|
||||||
// .. nothing yet ..
|
// .. nothing yet ..
|
||||||
}
|
}
|
||||||
|
|
||||||
const LayerMap &
|
void
|
||||||
GDS2Reader::read (db::Layout &layout, const db::LoadLayoutOptions &options)
|
GDS2Reader::init (const db::LoadLayoutOptions &options)
|
||||||
{
|
{
|
||||||
m_options = options.get_options<db::GDS2ReaderOptions> ();
|
GDS2ReaderBase::init (options);
|
||||||
m_common_options = options.get_options<db::CommonReaderOptions> ();
|
|
||||||
|
m_allow_big_records = options.get_options<db::GDS2ReaderOptions> ().allow_big_records;
|
||||||
|
|
||||||
m_recnum = 0;
|
m_recnum = 0;
|
||||||
--m_recnum;
|
--m_recnum;
|
||||||
m_reclen = 0;
|
m_reclen = 0;
|
||||||
|
|
||||||
return basic_read (layout, m_common_options.layer_map, m_common_options.create_other_layers, m_common_options.enable_text_objects, m_common_options.enable_properties, m_options.allow_multi_xy_records, m_options.box_mode, m_common_options.cell_conflict_resolution);
|
|
||||||
}
|
|
||||||
|
|
||||||
const LayerMap &
|
|
||||||
GDS2Reader::read (db::Layout &layout)
|
|
||||||
{
|
|
||||||
return read (layout, db::LoadLayoutOptions ());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -108,7 +102,7 @@ GDS2Reader::get_record ()
|
||||||
error (tl::to_string (tr ("Invalid record length (less than 4)")));
|
error (tl::to_string (tr ("Invalid record length (less than 4)")));
|
||||||
}
|
}
|
||||||
if (m_reclen >= 0x8000) {
|
if (m_reclen >= 0x8000) {
|
||||||
if (m_options.allow_big_records) {
|
if (m_allow_big_records) {
|
||||||
warn (tl::to_string (tr ("Record length larger than 0x8000 encountered: interpreting as unsigned")));
|
warn (tl::to_string (tr ("Record length larger than 0x8000 encountered: interpreting as unsigned")));
|
||||||
} else {
|
} else {
|
||||||
error (tl::to_string (tr ("Record length larger than 0x8000 encountered (reader is configured not to allow such records)")));
|
error (tl::to_string (tr ("Record length larger than 0x8000 encountered (reader is configured not to allow such records)")));
|
||||||
|
|
|
||||||
|
|
@ -72,43 +72,14 @@ public:
|
||||||
*/
|
*/
|
||||||
~GDS2Reader ();
|
~GDS2Reader ();
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The basic read method
|
|
||||||
*
|
|
||||||
* This method will read the stream data and translate this to
|
|
||||||
* insert calls into the layout object. This will not do much
|
|
||||||
* on the layout object beside inserting the objects.
|
|
||||||
* It can be given a couple of options specified with the
|
|
||||||
* LoadLayoutOptions object.
|
|
||||||
* The returned map will contain all layers, the passed
|
|
||||||
* ones and the newly created ones.
|
|
||||||
*
|
|
||||||
* @param layout The layout object to write to
|
|
||||||
* @param options The generic reader options
|
|
||||||
* @return The LayerMap object that tells where which layer was loaded
|
|
||||||
*/
|
|
||||||
virtual const LayerMap &read (db::Layout &layout, const LoadLayoutOptions &options);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The basic read method (without mapping)
|
|
||||||
*
|
|
||||||
* This method will read the stream data and translate this to
|
|
||||||
* insert calls into the layout object. This will not do much
|
|
||||||
* on the layout object beside inserting the objects.
|
|
||||||
* This version will read all input layers and return a map
|
|
||||||
* which tells which GDS2 layer has been read into which logical
|
|
||||||
* layer.
|
|
||||||
*
|
|
||||||
* @param layout The layout object to write to
|
|
||||||
* @return The LayerMap object
|
|
||||||
*/
|
|
||||||
virtual const LayerMap &read (db::Layout &layout);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Format
|
* @brief Format
|
||||||
*/
|
*/
|
||||||
virtual const char *format () const { return "GDS2"; }
|
virtual const char *format () const { return "GDS2"; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void init (const LoadLayoutOptions &options);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
tl::InputStream &m_stream;
|
tl::InputStream &m_stream;
|
||||||
size_t m_recnum;
|
size_t m_recnum;
|
||||||
|
|
@ -117,8 +88,7 @@ private:
|
||||||
unsigned char *mp_rec_buf;
|
unsigned char *mp_rec_buf;
|
||||||
tl::string m_string_buf;
|
tl::string m_string_buf;
|
||||||
short m_stored_rec;
|
short m_stored_rec;
|
||||||
db::GDS2ReaderOptions m_options;
|
bool m_allow_big_records;
|
||||||
db::CommonReaderOptions m_common_options;
|
|
||||||
tl::AbsoluteProgress m_progress;
|
tl::AbsoluteProgress m_progress;
|
||||||
|
|
||||||
virtual void error (const std::string &txt);
|
virtual void error (const std::string &txt);
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@
|
||||||
|
|
||||||
|
|
||||||
#include "dbGDS2ReaderBase.h"
|
#include "dbGDS2ReaderBase.h"
|
||||||
|
#include "dbGDS2Format.h"
|
||||||
#include "dbGDS2.h"
|
#include "dbGDS2.h"
|
||||||
#include "dbArray.h"
|
#include "dbArray.h"
|
||||||
|
|
||||||
|
|
@ -34,42 +35,12 @@ namespace db
|
||||||
|
|
||||||
// ---------------------------------------------------------------
|
// ---------------------------------------------------------------
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief A utility class that maps the layers for the proxy cell recovery
|
|
||||||
*/
|
|
||||||
class GDS2ReaderLayerMapping
|
|
||||||
: public db::ImportLayerMapping
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
GDS2ReaderLayerMapping (db::GDS2ReaderBase *reader, db::Layout *layout, bool create)
|
|
||||||
: mp_reader (reader), mp_layout (layout), m_create (create)
|
|
||||||
{
|
|
||||||
// .. nothing yet ..
|
|
||||||
}
|
|
||||||
|
|
||||||
std::pair<bool, unsigned int> map_layer (const db::LayerProperties &lprops)
|
|
||||||
{
|
|
||||||
// named layers that are imported from a library are ignored
|
|
||||||
if (lprops.is_named ()) {
|
|
||||||
return std::make_pair (false, 0);
|
|
||||||
} else {
|
|
||||||
return mp_reader->open_dl (*mp_layout, LDPair (lprops.layer, lprops.datatype), m_create);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
db::GDS2ReaderBase *mp_reader;
|
|
||||||
db::Layout *mp_layout;
|
|
||||||
bool m_create;
|
|
||||||
};
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------
|
// ---------------------------------------------------------------
|
||||||
// GDS2ReaderBase
|
// GDS2ReaderBase
|
||||||
|
|
||||||
GDS2ReaderBase::GDS2ReaderBase ()
|
GDS2ReaderBase::GDS2ReaderBase ()
|
||||||
: m_dbu (0.001),
|
: m_dbu (0.001),
|
||||||
m_dbuu (1.0),
|
m_dbuu (1.0),
|
||||||
m_create_layers (true),
|
|
||||||
m_read_texts (true),
|
m_read_texts (true),
|
||||||
m_read_properties (true),
|
m_read_properties (true),
|
||||||
m_allow_multi_xy_records (false),
|
m_allow_multi_xy_records (false),
|
||||||
|
|
@ -83,31 +54,18 @@ GDS2ReaderBase::~GDS2ReaderBase ()
|
||||||
// .. nothing yet ..
|
// .. nothing yet ..
|
||||||
}
|
}
|
||||||
|
|
||||||
const LayerMap &
|
void
|
||||||
GDS2ReaderBase::basic_read (db::Layout &layout, const LayerMap &layer_map, bool create_other_layers, bool enable_text_objects, bool enable_properties, bool allow_multi_xy_records, unsigned int box_mode, db::CommonReader::CellConflictResolution cc_resolution)
|
GDS2ReaderBase::init (const db::LoadLayoutOptions &options)
|
||||||
{
|
{
|
||||||
m_layer_map = layer_map;
|
CommonReader::init (options);
|
||||||
m_layer_map.prepare (layout);
|
|
||||||
m_read_texts = enable_text_objects;
|
|
||||||
m_read_properties = enable_properties;
|
|
||||||
|
|
||||||
m_allow_multi_xy_records = allow_multi_xy_records;
|
db::GDS2ReaderOptions gds2_options = options.get_options<db::GDS2ReaderOptions> ();
|
||||||
m_box_mode = box_mode;
|
|
||||||
m_create_layers = create_other_layers;
|
|
||||||
|
|
||||||
set_cell_conflict_resolution (cc_resolution);
|
m_read_texts = common_options ().enable_text_objects;
|
||||||
|
m_read_properties = common_options ().enable_properties;
|
||||||
|
|
||||||
layout.start_changes ();
|
m_allow_multi_xy_records = gds2_options.allow_multi_xy_records;
|
||||||
try {
|
m_box_mode = gds2_options.box_mode;
|
||||||
do_read (layout);
|
|
||||||
finish (layout);
|
|
||||||
layout.end_changes ();
|
|
||||||
} catch (...) {
|
|
||||||
layout.end_changes ();
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
|
|
||||||
return m_layer_map;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -181,34 +139,6 @@ GDS2ReaderBase::finish_element (db::PropertiesRepository &rep)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::pair <bool, unsigned int>
|
|
||||||
GDS2ReaderBase::open_dl (db::Layout &layout, const LDPair &dl, bool create)
|
|
||||||
{
|
|
||||||
std::pair<bool, unsigned int> ll = m_layer_map.logical (dl, layout);
|
|
||||||
if (ll.first) {
|
|
||||||
|
|
||||||
return ll;
|
|
||||||
|
|
||||||
} else if (! create) {
|
|
||||||
|
|
||||||
// layer not mapped and no layer create is requested
|
|
||||||
return ll;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
// and create the layer
|
|
||||||
db::LayerProperties lp;
|
|
||||||
lp.layer = dl.layer;
|
|
||||||
lp.datatype = dl.datatype;
|
|
||||||
|
|
||||||
unsigned int ll = layout.insert_layer (lp);
|
|
||||||
m_layer_map.map (dl, ll, lp);
|
|
||||||
|
|
||||||
return std::make_pair (true, ll);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline db::Point
|
inline db::Point
|
||||||
pt_conv (const GDS2XY &p)
|
pt_conv (const GDS2XY &p)
|
||||||
{
|
{
|
||||||
|
|
@ -358,17 +288,21 @@ GDS2ReaderBase::do_read (db::Layout &layout)
|
||||||
|
|
||||||
db::cell_index_type cell_index = make_cell (layout, m_cellname);
|
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);
|
std::map <tl::string, std::vector <std::string> >::const_iterator ctx = m_context_info.find (m_cellname);
|
||||||
if (ctx != m_context_info.end ()) {
|
if (ctx != m_context_info.end ()) {
|
||||||
GDS2ReaderLayerMapping layer_mapping (this, &layout, m_create_layers);
|
CommonReaderLayerMapping layer_mapping (this, &layout);
|
||||||
if (layout.recover_proxy_as (cell_index, ctx->second.begin (), ctx->second.end (), &layer_mapping)) {
|
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:
|
// 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;
|
long attr = 0;
|
||||||
db::PropertiesRepository::properties_set cell_properties;
|
db::PropertiesRepository::properties_set cell_properties;
|
||||||
|
|
||||||
|
|
@ -553,7 +487,7 @@ GDS2ReaderBase::read_boundary (db::Layout &layout, db::Cell &cell, bool from_box
|
||||||
unsigned int xy_length = 0;
|
unsigned int xy_length = 0;
|
||||||
GDS2XY *xy_data = get_xy_data (xy_length);
|
GDS2XY *xy_data = get_xy_data (xy_length);
|
||||||
|
|
||||||
std::pair<bool, unsigned int> ll = open_dl (layout, ld, m_create_layers);
|
std::pair<bool, unsigned int> ll = open_dl (layout, ld);
|
||||||
if (ll.first) {
|
if (ll.first) {
|
||||||
|
|
||||||
// create a box object if possible
|
// create a box object if possible
|
||||||
|
|
@ -734,7 +668,7 @@ GDS2ReaderBase::read_path (db::Layout &layout, db::Cell &cell)
|
||||||
unsigned int xy_length = 0;
|
unsigned int xy_length = 0;
|
||||||
GDS2XY *xy_data = get_xy_data (xy_length);
|
GDS2XY *xy_data = get_xy_data (xy_length);
|
||||||
|
|
||||||
std::pair<bool, unsigned int> ll = open_dl (layout, ld, m_create_layers);
|
std::pair<bool, unsigned int> ll = open_dl (layout, ld);
|
||||||
if (ll.first) {
|
if (ll.first) {
|
||||||
|
|
||||||
// this will copy the path:
|
// this will copy the path:
|
||||||
|
|
@ -825,7 +759,7 @@ GDS2ReaderBase::read_text (db::Layout &layout, db::Cell &cell)
|
||||||
std::pair<bool, unsigned int> ll (false, 0);
|
std::pair<bool, unsigned int> ll (false, 0);
|
||||||
|
|
||||||
if (m_read_texts) {
|
if (m_read_texts) {
|
||||||
ll = open_dl (layout, ld, m_create_layers);
|
ll = open_dl (layout, ld);
|
||||||
}
|
}
|
||||||
|
|
||||||
rec_id = get_record ();
|
rec_id = get_record ();
|
||||||
|
|
@ -947,7 +881,7 @@ GDS2ReaderBase::read_box (db::Layout &layout, db::Cell &cell)
|
||||||
}
|
}
|
||||||
ld.datatype = get_ushort ();
|
ld.datatype = get_ushort ();
|
||||||
|
|
||||||
std::pair<bool, unsigned int> ll = open_dl (layout, ld, m_create_layers);
|
std::pair<bool, unsigned int> ll = open_dl (layout, ld);
|
||||||
|
|
||||||
if (get_record () != sXY) {
|
if (get_record () != sXY) {
|
||||||
error (tl::to_string (tr ("XY record expected")));
|
error (tl::to_string (tr ("XY record expected")));
|
||||||
|
|
|
||||||
|
|
@ -69,42 +69,20 @@ public:
|
||||||
const std::string &libname () const { return m_libname; }
|
const std::string &libname () const { return m_libname; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/**
|
|
||||||
* @brief The basic read method
|
|
||||||
*
|
|
||||||
* This method will read the stream data and translate this to
|
|
||||||
* insert calls into the layout object. This will not do much
|
|
||||||
* on the layout object beside inserting the objects.
|
|
||||||
* It can be given a couple of options specified with the
|
|
||||||
* LoadLayoutOptions object.
|
|
||||||
* The returned map will contain all layers, the passed
|
|
||||||
* ones and the newly created ones.
|
|
||||||
*
|
|
||||||
* @param layout The layout object to write to
|
|
||||||
* @param layer_map The layer mapping on input
|
|
||||||
* @param create_other_layer A flag indicating whether to read all other layers
|
|
||||||
* @param enable_text_objects A flag indicating whether to read text objects
|
|
||||||
* @param enable_properties A flag indicating whether to read user properties
|
|
||||||
* @param allow_multi_xy_records If true, tries to check for multiple XY records for BOUNDARY elements
|
|
||||||
* @param box_mode How to treat BOX records (0: ignore, 1: as rectangles, 2: as boundaries, 3: error)
|
|
||||||
* @param cc_resolution The cell name conflict resolution mode
|
|
||||||
* @return The LayerMap object that tells where which layer was loaded
|
|
||||||
*/
|
|
||||||
const LayerMap &basic_read (db::Layout &layout, const LayerMap &layer_map, bool create_other_layers, bool enable_text_objects, bool enable_properties, bool allow_multi_xy_records, unsigned int box_mode, db::CommonReader::CellConflictResolution cc_resolution);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Accessor method to the current cellname
|
* @brief Accessor method to the current cellname
|
||||||
*/
|
*/
|
||||||
const std::string &cellname () const { return m_cellname; }
|
const std::string &cellname () const { return m_cellname; }
|
||||||
|
|
||||||
|
virtual void do_read (db::Layout &layout);
|
||||||
|
virtual void init (const LoadLayoutOptions &options);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class GDS2ReaderLayerMapping;
|
friend class GDS2ReaderLayerMapping;
|
||||||
|
|
||||||
LayerMap m_layer_map;
|
|
||||||
std::string m_cellname;
|
std::string m_cellname;
|
||||||
std::string m_libname;
|
std::string m_libname;
|
||||||
double m_dbu, m_dbuu;
|
double m_dbu, m_dbuu;
|
||||||
bool m_create_layers;
|
|
||||||
bool m_read_texts;
|
bool m_read_texts;
|
||||||
bool m_read_properties;
|
bool m_read_properties;
|
||||||
bool m_allow_multi_xy_records;
|
bool m_allow_multi_xy_records;
|
||||||
|
|
@ -119,9 +97,6 @@ private:
|
||||||
void read_box (db::Layout &layout, db::Cell &cell);
|
void read_box (db::Layout &layout, db::Cell &cell);
|
||||||
void read_ref (db::Layout &layout, db::Cell &cell, bool array, tl::vector<db::CellInstArray> &instances, tl::vector<db::CellInstArrayWithProperties> &insts_wp);
|
void read_ref (db::Layout &layout, db::Cell &cell, bool array, tl::vector<db::CellInstArray> &instances, tl::vector<db::CellInstArrayWithProperties> &insts_wp);
|
||||||
|
|
||||||
void do_read (db::Layout &layout);
|
|
||||||
|
|
||||||
std::pair <bool, unsigned int> open_dl (db::Layout &layout, const LDPair &dl, bool create);
|
|
||||||
std::pair <bool, db::properties_id_type> finish_element (db::PropertiesRepository &rep);
|
std::pair <bool, db::properties_id_type> finish_element (db::PropertiesRepository &rep);
|
||||||
void finish_element ();
|
void finish_element ();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -332,7 +332,7 @@ TEST(2)
|
||||||
db::Layout layout_piece (&m);
|
db::Layout layout_piece (&m);
|
||||||
layout_piece = layout;
|
layout_piece = layout;
|
||||||
|
|
||||||
std::pair<bool, unsigned int> jj = map_full.logical (pairs[i]);
|
std::pair<bool, unsigned int> jj = map_full.first_logical (pairs[i]);
|
||||||
EXPECT_EQ (jj.first, true);
|
EXPECT_EQ (jj.first, true);
|
||||||
|
|
||||||
for (unsigned int j = 0; j < layout_piece.layers(); ++j) {
|
for (unsigned int j = 0; j < layout_piece.layers(); ++j) {
|
||||||
|
|
@ -418,7 +418,7 @@ TEST(3_AdvancedMapping)
|
||||||
|
|
||||||
EXPECT_EQ (lm_read.to_string_file_format (),
|
EXPECT_EQ (lm_read.to_string_file_format (),
|
||||||
"1/10 : 1/0\n"
|
"1/10 : 1/0\n"
|
||||||
"2/0-9,21-*\n"
|
"2/0-1 : 2/0\n"
|
||||||
"1/0 : 1/0\n"
|
"1/0 : 1/0\n"
|
||||||
"1/1 : 1/1\n"
|
"1/1 : 1/1\n"
|
||||||
"1/20 : 1/1020\n"
|
"1/20 : 1/1020\n"
|
||||||
|
|
@ -427,23 +427,103 @@ TEST(3_AdvancedMapping)
|
||||||
"2/11 : 2/11\n"
|
"2/11 : 2/11\n"
|
||||||
"42/42 : 142/42\n"
|
"42/42 : 142/42\n"
|
||||||
"100/0 : 200/0\n"
|
"100/0 : 200/0\n"
|
||||||
"2/12-20 : */*\n"
|
|
||||||
"1/22-30 : 1/*+1000\n"
|
|
||||||
"1/2-9,11-19,31-* : */*\n"
|
|
||||||
"0/*;3-41/*;42/0-41,43-*;43-99/*;100/1-*;101-*/* : *+100/*\n"
|
|
||||||
);
|
);
|
||||||
|
|
||||||
std::string fn_au (tl::testsrc () + "/testdata/gds/alm_au.gds");
|
std::string fn_au (tl::testsrc () + "/testdata/gds/alm_au.gds");
|
||||||
db::compare_layouts (_this, layout, fn_au, db::WriteGDS2, 1);
|
db::compare_layouts (_this, layout, fn_au, db::WriteGDS2, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(3_MultiMapping)
|
||||||
|
{
|
||||||
|
db::Manager m (false);
|
||||||
|
db::Layout layout (&m);
|
||||||
|
|
||||||
|
db::LoadLayoutOptions options;
|
||||||
|
db::LayerMap lm, lm_read;
|
||||||
|
|
||||||
|
unsigned int n = 0;
|
||||||
|
lm.map_expr ("*/*: */*", n++);
|
||||||
|
lm.unmap_expr ("1-2/10");
|
||||||
|
lm.mmap_expr ("1-2/10: *+100/*", n++);
|
||||||
|
lm.mmap_expr ("1/10;2/10: 12/1010", n++);
|
||||||
|
lm.mmap_expr ("1/0-1: */*+1000", n++);
|
||||||
|
options.get_options<db::CommonReaderOptions> ().layer_map = lm;
|
||||||
|
|
||||||
|
{
|
||||||
|
tl::InputStream file (tl::testsrc () + "/testdata/gds/alm.gds");
|
||||||
|
db::Reader reader (file);
|
||||||
|
lm_read = reader.read (layout, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPECT_EQ (lm_read.to_string_file_format (),
|
||||||
|
"+1-2/10 : 12/1010\n"
|
||||||
|
"+1/0 : 1/1000\n"
|
||||||
|
"+1/0 : 1/0\n"
|
||||||
|
"+1/1 : 1/1001\n"
|
||||||
|
"+1/1 : 1/1\n"
|
||||||
|
"+1/10 : 101/10\n"
|
||||||
|
"1/20 : 1/20\n"
|
||||||
|
"1/21 : 1/21\n"
|
||||||
|
"2/0 : 2/0\n"
|
||||||
|
"2/1 : 2/1\n"
|
||||||
|
"+2/10 : 102/10\n"
|
||||||
|
"2/11 : 2/11\n"
|
||||||
|
"42/42 : 42/42\n"
|
||||||
|
"100/0 : 100/0\n"
|
||||||
|
);
|
||||||
|
|
||||||
|
std::string fn_au (tl::testsrc () + "/testdata/gds/alm_au2.gds");
|
||||||
|
db::compare_layouts (_this, layout, fn_au, db::WriteGDS2, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(3_MultiMapping2)
|
||||||
|
{
|
||||||
|
db::Manager m (false);
|
||||||
|
db::Layout layout (&m);
|
||||||
|
|
||||||
|
db::LoadLayoutOptions options;
|
||||||
|
db::LayerMap lm, lm_read;
|
||||||
|
|
||||||
|
unsigned int n = 0;
|
||||||
|
lm.add_expr ("(1/0:1/0)", n++);
|
||||||
|
lm.add_expr ("+(1/0:1000/0)", n++);
|
||||||
|
lm.add_expr ("(4/0:1/0)", n++);
|
||||||
|
lm.add_expr ("(2/0:2/0)", n++);
|
||||||
|
lm.add_expr ("+(2/0:1000/0)", n++);
|
||||||
|
lm.add_expr ("(3/0:3/0)", n++);
|
||||||
|
options.get_options<db::CommonReaderOptions> ().layer_map = lm;
|
||||||
|
|
||||||
|
{
|
||||||
|
tl::InputStream file (tl::testsrc () + "/testdata/gds/t10.gds");
|
||||||
|
db::Reader reader (file);
|
||||||
|
lm_read = reader.read (layout, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPECT_EQ (lm_read.to_string_file_format (),
|
||||||
|
"+1/0;4/0 : 1/0\n"
|
||||||
|
"+1-2/0 : 1000/0\n"
|
||||||
|
"+2/0 : 2/0\n"
|
||||||
|
"3/0 : 3/0\n"
|
||||||
|
"6/0 : 6/0\n"
|
||||||
|
"8/0 : 8/0\n"
|
||||||
|
"5/0 : 5/0\n"
|
||||||
|
"7/0 : 7/0\n"
|
||||||
|
"3/1 : 3/1\n"
|
||||||
|
"6/1 : 6/1\n"
|
||||||
|
"8/1 : 8/1\n"
|
||||||
|
);
|
||||||
|
|
||||||
|
std::string fn_au (tl::testsrc () + "/testdata/gds/alm_au3.gds");
|
||||||
|
db::compare_layouts (_this, layout, fn_au, db::WriteGDS2, 1);
|
||||||
|
}
|
||||||
|
|
||||||
TEST(4_CollectModeRename)
|
TEST(4_CollectModeRename)
|
||||||
{
|
{
|
||||||
db::Manager m (false);
|
db::Manager m (false);
|
||||||
db::Layout layout (&m);
|
db::Layout layout (&m);
|
||||||
|
|
||||||
db::LoadLayoutOptions options;
|
db::LoadLayoutOptions options;
|
||||||
options.get_options<db::CommonReaderOptions> ().cell_conflict_resolution = db::CommonReader::RenameCell;
|
options.get_options<db::CommonReaderOptions> ().cell_conflict_resolution = db::RenameCell;
|
||||||
|
|
||||||
{
|
{
|
||||||
tl::InputStream file (tl::testsrc () + "/testdata/gds/collect_basic.gds");
|
tl::InputStream file (tl::testsrc () + "/testdata/gds/collect_basic.gds");
|
||||||
|
|
@ -467,7 +547,7 @@ TEST(4_CollectModeOverwrite)
|
||||||
db::Layout layout (&m);
|
db::Layout layout (&m);
|
||||||
|
|
||||||
db::LoadLayoutOptions options;
|
db::LoadLayoutOptions options;
|
||||||
options.get_options<db::CommonReaderOptions> ().cell_conflict_resolution = db::CommonReader::OverwriteCell;
|
options.get_options<db::CommonReaderOptions> ().cell_conflict_resolution = db::OverwriteCell;
|
||||||
|
|
||||||
{
|
{
|
||||||
tl::InputStream file (tl::testsrc () + "/testdata/gds/collect_basic.gds");
|
tl::InputStream file (tl::testsrc () + "/testdata/gds/collect_basic.gds");
|
||||||
|
|
@ -491,7 +571,7 @@ TEST(4_CollectModeSkip)
|
||||||
db::Layout layout (&m);
|
db::Layout layout (&m);
|
||||||
|
|
||||||
db::LoadLayoutOptions options;
|
db::LoadLayoutOptions options;
|
||||||
options.get_options<db::CommonReaderOptions> ().cell_conflict_resolution = db::CommonReader::SkipNewCell;
|
options.get_options<db::CommonReaderOptions> ().cell_conflict_resolution = db::SkipNewCell;
|
||||||
|
|
||||||
{
|
{
|
||||||
tl::InputStream file (tl::testsrc () + "/testdata/gds/collect_basic.gds");
|
tl::InputStream file (tl::testsrc () + "/testdata/gds/collect_basic.gds");
|
||||||
|
|
@ -515,7 +595,7 @@ TEST(4_CollectModeAdd)
|
||||||
db::Layout layout (&m);
|
db::Layout layout (&m);
|
||||||
|
|
||||||
db::LoadLayoutOptions options;
|
db::LoadLayoutOptions options;
|
||||||
options.get_options<db::CommonReaderOptions> ().cell_conflict_resolution = db::CommonReader::AddToCell;
|
options.get_options<db::CommonReaderOptions> ().cell_conflict_resolution = db::AddToCell;
|
||||||
|
|
||||||
{
|
{
|
||||||
tl::InputStream file (tl::testsrc () + "/testdata/gds/collect_basic.gds");
|
tl::InputStream file (tl::testsrc () + "/testdata/gds/collect_basic.gds");
|
||||||
|
|
|
||||||
|
|
@ -157,14 +157,14 @@ DEFImporter::read_diearea (db::Layout &layout, db::Cell &design, double scale)
|
||||||
if (points.size () >= 2) {
|
if (points.size () >= 2) {
|
||||||
|
|
||||||
// create outline shape
|
// create outline shape
|
||||||
std::pair <bool, unsigned int> dl = open_layer (layout, std::string (), Outline, 0);
|
std::set<unsigned int> dl = open_layer (layout, std::string (), Outline, 0);
|
||||||
if (dl.first) {
|
for (std::set<unsigned int>::const_iterator l = dl.begin (); l != dl.end (); ++l) {
|
||||||
if (points.size () == 2) {
|
if (points.size () == 2) {
|
||||||
design.shapes (dl.second).insert (db::Box (points [0], points [1]));
|
design.shapes (*l).insert (db::Box (points [0], points [1]));
|
||||||
} else {
|
} else {
|
||||||
db::Polygon p;
|
db::Polygon p;
|
||||||
p.assign_hull (points.begin (), points.end ());
|
p.assign_hull (points.begin (), points.end ());
|
||||||
design.shapes (dl.second).insert (p);
|
design.shapes (*l).insert (p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -305,9 +305,9 @@ DEFImporter::read_blockages (db::Layout &layout, db::Cell &design, double scale)
|
||||||
db::Polygon p;
|
db::Polygon p;
|
||||||
read_polygon (p, scale);
|
read_polygon (p, scale);
|
||||||
|
|
||||||
std::pair <bool, unsigned int> dl = open_layer (layout, layer, layer.empty () ? PlacementBlockage : Blockage, 0);
|
std::set <unsigned int> dl = open_layer (layout, layer, layer.empty () ? PlacementBlockage : Blockage, 0);
|
||||||
if (dl.first) {
|
for (std::set<unsigned int>::const_iterator l = dl.begin (); l != dl.end (); ++l) {
|
||||||
design.shapes (dl.second).insert (p);
|
design.shapes (*l).insert (p);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (test ("RECT")) {
|
} else if (test ("RECT")) {
|
||||||
|
|
@ -315,9 +315,9 @@ DEFImporter::read_blockages (db::Layout &layout, db::Cell &design, double scale)
|
||||||
db::Polygon p;
|
db::Polygon p;
|
||||||
read_rect (p, scale);
|
read_rect (p, scale);
|
||||||
|
|
||||||
std::pair <bool, unsigned int> dl = open_layer (layout, layer, layer.empty () ? PlacementBlockage : Blockage, 0);
|
std::set <unsigned int> dl = open_layer (layout, layer, layer.empty () ? PlacementBlockage : Blockage, 0);
|
||||||
if (dl.first) {
|
for (std::set<unsigned int>::const_iterator l = dl.begin (); l != dl.end (); ++l) {
|
||||||
design.shapes (dl.second).insert (p);
|
design.shapes (*l).insert (p);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -554,17 +554,19 @@ DEFImporter::read_single_net (std::string &nondefaultrule, Layout &layout, db::C
|
||||||
|
|
||||||
test (")");
|
test (")");
|
||||||
|
|
||||||
std::pair <bool, unsigned int> dl = open_layer (layout, ln, specialnets ? SpecialRouting : Routing, mask);
|
std::set <unsigned int> dl = open_layer (layout, ln, specialnets ? SpecialRouting : Routing, mask);
|
||||||
if (dl.first) {
|
if (! dl.empty ()) {
|
||||||
|
|
||||||
db::Point p (x, y);
|
db::Point p (x, y);
|
||||||
db::Box rect (db::Point (db::DPoint ((x + x1) * scale, (y + y1) * scale)),
|
db::Box rect (db::Point (db::DPoint ((x + x1) * scale, (y + y1) * scale)),
|
||||||
db::Point (db::DPoint ((x + x2) * scale, (y + y2) * scale)));
|
db::Point (db::DPoint ((x + x2) * scale, (y + y2) * scale)));
|
||||||
|
|
||||||
if (prop_id != 0) {
|
for (std::set<unsigned int>::const_iterator l = dl.begin (); l != dl.end (); ++l) {
|
||||||
design.shapes (dl.second).insert (db::object_with_properties<db::Box> (rect, prop_id));
|
if (prop_id != 0) {
|
||||||
} else {
|
design.shapes (*l).insert (db::object_with_properties<db::Box> (rect, prop_id));
|
||||||
design.shapes (dl.second).insert (rect);
|
} else {
|
||||||
|
design.shapes (*l).insert (rect);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -615,9 +617,9 @@ DEFImporter::read_single_net (std::string &nondefaultrule, Layout &layout, db::C
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pts.size () > 1) {
|
if (pts.size () > 1) {
|
||||||
std::pair <bool, unsigned int> dl = open_layer (layout, ln, specialnets ? SpecialRouting : Routing, mask);
|
std::set <unsigned int> dl = open_layer (layout, ln, specialnets ? SpecialRouting : Routing, mask);
|
||||||
if (dl.first) {
|
for (std::set<unsigned int>::const_iterator l = dl.begin (); l != dl.end (); ++l) {
|
||||||
produce_routing_geometry (design, style, dl.second, prop_id, pts, ext, w);
|
produce_routing_geometry (design, style, *l, prop_id, pts, ext, w);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -803,12 +805,12 @@ DEFImporter::read_nets (db::Layout &layout, db::Cell &design, double scale, bool
|
||||||
db::Polygon p;
|
db::Polygon p;
|
||||||
read_polygon (p, scale);
|
read_polygon (p, scale);
|
||||||
|
|
||||||
std::pair <bool, unsigned int> dl = open_layer (layout, ln, specialnets ? SpecialRouting : Routing, mask);
|
std::set <unsigned int> dl = open_layer (layout, ln, specialnets ? SpecialRouting : Routing, mask);
|
||||||
if (dl.first) {
|
for (std::set<unsigned int>::const_iterator l = dl.begin (); l != dl.end (); ++l) {
|
||||||
if (prop_id != 0) {
|
if (prop_id != 0) {
|
||||||
design.shapes (dl.second).insert (db::object_with_properties<db::Polygon> (p, prop_id));
|
design.shapes (*l).insert (db::object_with_properties<db::Polygon> (p, prop_id));
|
||||||
} else {
|
} else {
|
||||||
design.shapes (dl.second).insert (p);
|
design.shapes (*l).insert (p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -821,12 +823,12 @@ DEFImporter::read_nets (db::Layout &layout, db::Cell &design, double scale, bool
|
||||||
db::Polygon p;
|
db::Polygon p;
|
||||||
read_rect (p, scale);
|
read_rect (p, scale);
|
||||||
|
|
||||||
std::pair <bool, unsigned int> dl = open_layer (layout, ln, specialnets ? SpecialRouting : Routing, mask);
|
std::set <unsigned int> dl = open_layer (layout, ln, specialnets ? SpecialRouting : Routing, mask);
|
||||||
if (dl.first) {
|
for (std::set<unsigned int>::const_iterator l = dl.begin (); l != dl.end (); ++l) {
|
||||||
if (prop_id != 0) {
|
if (prop_id != 0) {
|
||||||
design.shapes (dl.second).insert (db::object_with_properties<db::Polygon> (p, prop_id));
|
design.shapes (*l).insert (db::object_with_properties<db::Polygon> (p, prop_id));
|
||||||
} else {
|
} else {
|
||||||
design.shapes (dl.second).insert (p);
|
design.shapes (*l).insert (p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1191,8 +1193,8 @@ DEFImporter::read_pins (db::Layout &layout, db::Cell &design, double scale)
|
||||||
// Produce geometry collected so far
|
// Produce geometry collected so far
|
||||||
for (std::map<std::pair<std::string, unsigned int>, std::vector<db::Polygon> >::const_iterator g = geometry.begin (); g != geometry.end (); ++g) {
|
for (std::map<std::pair<std::string, unsigned int>, std::vector<db::Polygon> >::const_iterator g = geometry.begin (); g != geometry.end (); ++g) {
|
||||||
|
|
||||||
std::pair <bool, unsigned int> dl = open_layer (layout, g->first.first, Pins, g->first.second);
|
std::set<unsigned int> dl = open_layer (layout, g->first.first, Pins, g->first.second);
|
||||||
if (dl.first) {
|
if (! dl.empty ()) {
|
||||||
|
|
||||||
db::properties_id_type prop_id = 0;
|
db::properties_id_type prop_id = 0;
|
||||||
if (produce_pin_props ()) {
|
if (produce_pin_props ()) {
|
||||||
|
|
@ -1204,21 +1206,27 @@ DEFImporter::read_pins (db::Layout &layout, db::Cell &design, double scale)
|
||||||
for (std::vector<db::Polygon>::const_iterator p = g->second.begin (); p != g->second.end (); ++p) {
|
for (std::vector<db::Polygon>::const_iterator p = g->second.begin (); p != g->second.end (); ++p) {
|
||||||
db::Polygon pt = p->transformed (trans);
|
db::Polygon pt = p->transformed (trans);
|
||||||
if (prop_id == 0) {
|
if (prop_id == 0) {
|
||||||
design.shapes (dl.second).insert (pt);
|
for (std::set<unsigned int>::const_iterator l = dl.begin (); l != dl.end (); ++l) {
|
||||||
|
design.shapes (*l).insert (pt);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
design.shapes (dl.second).insert (db::PolygonWithProperties (pt, prop_id));
|
for (std::set<unsigned int>::const_iterator l = dl.begin (); l != dl.end (); ++l) {
|
||||||
|
design.shapes (*l).insert (db::PolygonWithProperties (pt, prop_id));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dl = open_layer (layout, g->first.first, Label, 0);
|
dl = open_layer (layout, g->first.first, Label, 0);
|
||||||
if (dl.first) {
|
if (! dl.empty ()) {
|
||||||
db::Box bbox;
|
db::Box bbox;
|
||||||
if (! g->second.empty ()) {
|
if (! g->second.empty ()) {
|
||||||
bbox = g->second.back ().box ().transformed (trans);
|
bbox = g->second.back ().box ().transformed (trans);
|
||||||
}
|
}
|
||||||
design.shapes (dl.second).insert (db::Text (label.c_str (), db::Trans (db::Vector (bbox.center ()))));
|
for (std::set<unsigned int>::const_iterator l = dl.begin (); l != dl.end (); ++l) {
|
||||||
|
design.shapes (*l).insert (db::Text (label.c_str (), db::Trans (db::Vector (bbox.center ()))));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -1554,10 +1562,10 @@ DEFImporter::do_read (db::Layout &layout)
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
std::pair <bool, unsigned int> dl = open_layer (layout, std::string (), Regions, 0);
|
std::set<unsigned int> dl = open_layer (layout, std::string (), Regions, 0);
|
||||||
if (dl.first) {
|
for (std::set<unsigned int>::const_iterator l = dl.begin (); l != dl.end (); ++l) {
|
||||||
for (std::vector<db::Polygon>::const_iterator p = r->second.begin (); p != r->second.end (); ++p) {
|
for (std::vector<db::Polygon>::const_iterator p = r->second.begin (); p != r->second.end (); ++p) {
|
||||||
group_cell->shapes (dl.second).insert (*p);
|
group_cell->shapes (*l).insert (*p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
regions.erase (r);
|
regions.erase (r);
|
||||||
|
|
@ -1597,12 +1605,12 @@ DEFImporter::do_read (db::Layout &layout)
|
||||||
|
|
||||||
if (! regions.empty ()) {
|
if (! regions.empty ()) {
|
||||||
|
|
||||||
std::pair <bool, unsigned int> dl = open_layer (layout, std::string (), Regions, 0);
|
std::set<unsigned int> dl = open_layer (layout, std::string (), Regions, 0);
|
||||||
if (dl.first) {
|
for (std::set<unsigned int>::const_iterator l = dl.begin (); l != dl.end (); ++l) {
|
||||||
|
|
||||||
for (std::map<std::string, std::vector<db::Polygon> >::const_iterator r = regions.begin (); r != regions.end (); ++r) {
|
for (std::map<std::string, std::vector<db::Polygon> >::const_iterator r = regions.begin (); r != regions.end (); ++r) {
|
||||||
for (std::vector<db::Polygon>::const_iterator p = r->second.begin (); p != r->second.end (); ++p) {
|
for (std::vector<db::Polygon>::const_iterator p = r->second.begin (); p != r->second.end (); ++p) {
|
||||||
others_cell->shapes (dl.second).insert (*p);
|
others_cell->shapes (*l).insert (*p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
// if a technology is given and the file can be found in the technology's base path, take it
|
||||||
// from there.
|
// from there.
|
||||||
std::string tn = layout.meta_info_value ("technology");
|
const db::Technology *tech = layout.technology ();
|
||||||
const db::Technology *tech = 0;
|
|
||||||
if (! tn.empty ()) {
|
|
||||||
tech = db::Technologies::instance ()->technology_by_name (tn);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tech && ! tech->base_path ().empty ()) {
|
if (tech && ! tech->base_path ().empty ()) {
|
||||||
std::string new_fn = tl::combine_path (tech->base_path (), fn);
|
std::string new_fn = tl::combine_path (tech->base_path (), fn);
|
||||||
|
|
@ -146,16 +142,16 @@ RuleBasedViaGenerator::create_cell (LEFDEFReaderState &reader, Layout &layout, d
|
||||||
db::Vector vs ((m_cutsize.x () * m_columns + m_cutspacing.x () * (m_columns - 1)) / 2, (m_cutsize.y () * m_rows + m_cutspacing.y () * (m_rows - 1)) / 2);
|
db::Vector vs ((m_cutsize.x () * m_columns + m_cutspacing.x () * (m_columns - 1)) / 2, (m_cutsize.y () * m_rows + m_cutspacing.y () * (m_rows - 1)) / 2);
|
||||||
db::Box via_box (m_offset - vs, m_offset + vs);
|
db::Box via_box (m_offset - vs, m_offset + vs);
|
||||||
|
|
||||||
std::pair <bool, unsigned int> dl (false, 0);
|
std::set <unsigned int> dl;
|
||||||
|
|
||||||
dl = reader.open_layer (layout, m_bottom_layer, ViaGeometry, mask_bottom);
|
dl = reader.open_layer (layout, m_bottom_layer, ViaGeometry, mask_bottom);
|
||||||
if (dl.first) {
|
for (std::set<unsigned int>::const_iterator l = dl.begin (); l != dl.end (); ++l) {
|
||||||
cell.shapes (dl.second).insert (db::Polygon (via_box.enlarged (m_be).moved (m_bo)));
|
cell.shapes (*l).insert (db::Polygon (via_box.enlarged (m_be).moved (m_bo)));
|
||||||
}
|
}
|
||||||
|
|
||||||
dl = reader.open_layer (layout, m_top_layer, ViaGeometry, mask_top);
|
dl = reader.open_layer (layout, m_top_layer, ViaGeometry, mask_top);
|
||||||
if (dl.first) {
|
for (std::set<unsigned int>::const_iterator l = dl.begin (); l != dl.end (); ++l) {
|
||||||
cell.shapes (dl.second).insert (db::Polygon (via_box.enlarged (m_te).moved (m_bo)));
|
cell.shapes (*l).insert (db::Polygon (via_box.enlarged (m_te).moved (m_bo)));
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *p = m_pattern.c_str ();
|
const char *p = m_pattern.c_str ();
|
||||||
|
|
@ -253,8 +249,8 @@ RuleBasedViaGenerator::create_cell (LEFDEFReaderState &reader, Layout &layout, d
|
||||||
}
|
}
|
||||||
|
|
||||||
dl = reader.open_layer (layout, m_cut_layer, ViaGeometry, cm);
|
dl = reader.open_layer (layout, m_cut_layer, ViaGeometry, cm);
|
||||||
if (dl.first) {
|
for (std::set<unsigned int>::const_iterator l = dl.begin (); l != dl.end (); ++l) {
|
||||||
cell.shapes (dl.second).insert (db::Polygon (vb));
|
cell.shapes (*l).insert (db::Polygon (vb));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -322,9 +318,9 @@ GeometryBasedLayoutGenerator::create_cell (LEFDEFReaderState &reader, Layout &la
|
||||||
unsigned int mshift = get_maskshift (g->first.first, ext_msl, masks);
|
unsigned int mshift = get_maskshift (g->first.first, ext_msl, masks);
|
||||||
unsigned int mask = mask_for (g->first.first, g->first.second.second, mshift, nm);
|
unsigned int mask = mask_for (g->first.first, g->first.second.second, mshift, nm);
|
||||||
|
|
||||||
std::pair <bool, unsigned int> dl = reader.open_layer (layout, g->first.first, g->first.second.first, mask);
|
std::set <unsigned int> dl = reader.open_layer (layout, g->first.first, g->first.second.first, mask);
|
||||||
if (dl.first) {
|
for (std::set<unsigned int>::const_iterator l = dl.begin (); l != dl.end (); ++l) {
|
||||||
cell.shapes (dl.second).insert (g->second);
|
cell.shapes (*l).insert (g->second);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -805,12 +801,24 @@ LEFDEFReaderState::register_layer (const std::string &ln)
|
||||||
++m_laynum;
|
++m_laynum;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static bool try_read_layers (tl::Extractor &ex, std::vector<int> &layers)
|
||||||
LEFDEFReaderState::map_layer_explicit (const std::string &n, LayerPurpose purpose, const db::LayerProperties &lp, unsigned int layer, unsigned int mask)
|
|
||||||
{
|
{
|
||||||
tl_assert (m_has_explicit_layer_mapping);
|
int l = 0;
|
||||||
m_layers [std::make_pair (n, std::make_pair (purpose, mask))] = std::make_pair (true, layer);
|
if (! ex.try_read (l)) {
|
||||||
m_layer_map.map (lp, layer);
|
return false;
|
||||||
|
}
|
||||||
|
layers.push_back (l);
|
||||||
|
|
||||||
|
if (ex.test (",")) {
|
||||||
|
do {
|
||||||
|
if (! ex.try_read (l)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
layers.push_back (l);
|
||||||
|
} while (ex.test (","));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -832,13 +840,14 @@ LEFDEFReaderState::read_map_file (const std::string &path, db::Layout &layout)
|
||||||
purpose_translation ["NET"] = Routing;
|
purpose_translation ["NET"] = Routing;
|
||||||
purpose_translation ["VIA"] = ViaGeometry;
|
purpose_translation ["VIA"] = ViaGeometry;
|
||||||
purpose_translation ["BLOCKAGE"] = Blockage;
|
purpose_translation ["BLOCKAGE"] = Blockage;
|
||||||
|
purpose_translation ["ALL"] = All;
|
||||||
|
|
||||||
std::map<LayerPurpose, std::string> purpose_translation_rev;
|
std::map<LayerPurpose, std::string> purpose_translation_rev;
|
||||||
for (std::map<std::string, LayerPurpose>::const_iterator i = purpose_translation.begin (); i != purpose_translation.end (); ++i) {
|
for (std::map<std::string, LayerPurpose>::const_iterator i = purpose_translation.begin (); i != purpose_translation.end (); ++i) {
|
||||||
purpose_translation_rev.insert (std::make_pair (i->second, i->first));
|
purpose_translation_rev.insert (std::make_pair (i->second, i->first));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<std::pair<std::string, std::pair<LayerPurpose, unsigned int> >, db::LayerProperties> layer_map;
|
std::map<std::pair<std::string, std::pair<LayerPurpose, unsigned int> >, std::vector<db::LayerProperties> > layer_map;
|
||||||
|
|
||||||
while (! ts.at_end ()) {
|
while (! ts.at_end ()) {
|
||||||
|
|
||||||
|
|
@ -852,113 +861,173 @@ LEFDEFReaderState::read_map_file (const std::string &path, db::Layout &layout)
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
std::string w1, w2;
|
std::string w1, w2;
|
||||||
int layer = 0, datatype = 0;
|
std::vector<int> layers, datatypes;
|
||||||
size_t max_purpose_str = 10;
|
size_t max_purpose_str = 10;
|
||||||
|
|
||||||
if (ex.try_read_word (w1) && ex.try_read_word (w2, "._$,/:") && ex.try_read (layer) && ex.try_read (datatype)) {
|
if (! ex.try_read_word (w1) || ! ex.try_read_word (w2, "._$,/:") || ! try_read_layers (ex, layers) || ! try_read_layers (ex, datatypes)) {
|
||||||
|
tl::warn << tl::sprintf (tl::to_string (tr ("Reading layer map file %s, line %d not understood - skipped")), path, ts.line_number ());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (w1 == "DIEAREA") {
|
if (w1 == "DIEAREA") {
|
||||||
|
|
||||||
layer_map [std::make_pair (std::string (), std::make_pair (Outline, (unsigned int) 0))] = db::LayerProperties (layer, datatype, "OUTLINE");
|
for (std::vector<int>::const_iterator l = layers.begin (); l != layers.end (); ++l) {
|
||||||
|
for (std::vector<int>::const_iterator d = datatypes.begin (); d != datatypes.end (); ++d) {
|
||||||
|
layer_map [std::make_pair (std::string (), std::make_pair (Outline, (unsigned int) 0))].push_back (db::LayerProperties (*l, *d, "OUTLINE"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} else if (w1 == "REGIONS") {
|
} else if (w1 == "REGIONS") {
|
||||||
|
|
||||||
layer_map [std::make_pair (std::string (), std::make_pair (Regions, (unsigned int) 0))] = db::LayerProperties (layer, datatype, "REGIONS");
|
for (std::vector<int>::const_iterator l = layers.begin (); l != layers.end (); ++l) {
|
||||||
|
for (std::vector<int>::const_iterator d = datatypes.begin (); d != datatypes.end (); ++d) {
|
||||||
|
layer_map [std::make_pair (std::string (), std::make_pair (Regions, (unsigned int) 0))].push_back (db::LayerProperties (*l, *d, "REGIONS"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} else if (w1 == "BLOCKAGE") {
|
} else if (w1 == "BLOCKAGE") {
|
||||||
|
|
||||||
layer_map [std::make_pair (std::string (), std::make_pair (PlacementBlockage, (unsigned int) 0))] = db::LayerProperties (layer, datatype, "PLACEMENT_BLK");
|
for (std::vector<int>::const_iterator l = layers.begin (); l != layers.end (); ++l) {
|
||||||
|
for (std::vector<int>::const_iterator d = datatypes.begin (); d != datatypes.end (); ++d) {
|
||||||
|
layer_map [std::make_pair (std::string (), std::make_pair (PlacementBlockage, (unsigned int) 0))].push_back (db::LayerProperties (*l, *d, "PLACEMENT_BLK"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} else if (w1 == "NAME") {
|
} else if (w1 == "NAME") {
|
||||||
|
|
||||||
// converts a line like
|
// converts a line like
|
||||||
// "NAME M1/PINS,M2/PINS ..."
|
// "NAME M1/PINS,M2/PINS ..."
|
||||||
// into a canonical name mapping like
|
// into a canonical name mapping like
|
||||||
// "(M1/LABELS): M1.LABEL"
|
// "(M1/LABELS): M1.LABEL"
|
||||||
// "(M2/LABELS): M2.LABEL"
|
// "(M2/LABELS): M2.LABEL"
|
||||||
|
|
||||||
|
std::vector<std::string> layer_names;
|
||||||
|
std::vector<std::string> purposes = tl::split (w2, ",");
|
||||||
|
for (std::vector<std::string>::const_iterator p = purposes.begin (); p != purposes.end (); ++p) {
|
||||||
|
if (*p == "DIEAREA" || *p == "ALL" || *p == "COMP") {
|
||||||
|
tl::warn << tl::sprintf (tl::to_string (tr ("Reading layer map file %s, line %d: NAME record ignored for entity: %s")), path, ts.line_number (), *p);
|
||||||
|
} else {
|
||||||
|
layer_names.push_back (tl::split (*p, "/").front ());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string final_name = tl::join (layer_names, "/") + ".LABEL";
|
||||||
|
for (std::vector<std::string>::const_iterator ln = layer_names.begin (); ln != layer_names.end (); ++ln) {
|
||||||
|
for (std::vector<int>::const_iterator l = layers.begin (); l != layers.end (); ++l) {
|
||||||
|
for (std::vector<int>::const_iterator d = datatypes.begin (); d != datatypes.end (); ++d) {
|
||||||
|
layer_map [std::make_pair (*ln, std::make_pair (Label, (unsigned int) 0))].push_back (db::LayerProperties (*l, *d, final_name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (w1 == "COMP") {
|
||||||
|
|
||||||
|
// ignore "COMP (ALL) ..."
|
||||||
|
tl::warn << tl::sprintf (tl::to_string (tr ("Reading layer map file %s, line %d: COMP entry ignored")), path, ts.line_number ());
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// converts a line like
|
||||||
|
// "M1 SPNET,NET,PINS,LEFPINS ..."
|
||||||
|
// into a canonical name mapping like
|
||||||
|
// "(M1,NET): M1.NET/PINS"
|
||||||
|
// "(M1,PINS): M1.NET/PINS"
|
||||||
|
// (separating, translating and recombing the purposes)
|
||||||
|
|
||||||
|
std::set<std::pair<LayerPurpose, unsigned int> > translated_purposes;
|
||||||
|
|
||||||
|
std::vector<std::string> purposes = tl::split (w2, ",");
|
||||||
|
std::reverse (purposes.begin (), purposes.end ());
|
||||||
|
|
||||||
|
unsigned int mask = 0;
|
||||||
|
|
||||||
|
for (std::vector<std::string>::const_iterator p = purposes.begin (); p != purposes.end (); ++p) {
|
||||||
|
|
||||||
|
std::string p_uc = tl::to_upper_case (*p);
|
||||||
|
tl::Extractor ex (p_uc.c_str ());
|
||||||
|
|
||||||
|
std::string ps;
|
||||||
|
ex.read_word_or_quoted (ps);
|
||||||
|
|
||||||
|
std::map<std::string, LayerPurpose>::const_iterator i = purpose_translation.find (ps);
|
||||||
|
if (i != purpose_translation.end ()) {
|
||||||
|
|
||||||
|
if (i->second == Routing) {
|
||||||
|
|
||||||
|
if (ex.test (":VOLTAGE:")) {
|
||||||
|
double f = 0.0;
|
||||||
|
ex.read (f);
|
||||||
|
tl::warn << tl::sprintf (tl::to_string (tr ("Reading layer map file %s, line %d: NET voltage constraint ignored for layer %s")), path, ts.line_number (), w1);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (i->second == ViaGeometry) {
|
||||||
|
|
||||||
|
if (ex.test (":SIZE:")) {
|
||||||
|
std::string sz;
|
||||||
|
ex.read_word (sz);
|
||||||
|
tl::warn << tl::sprintf (tl::to_string (tr ("Reading layer map file %s, line %d: VIA size constraint ignored for layer %s")), path, ts.line_number (), w1);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<std::string> layers;
|
|
||||||
std::vector<std::string> purposes = tl::split (w2, ",");
|
|
||||||
for (std::vector<std::string>::const_iterator p = purposes.begin (); p != purposes.end (); ++p) {
|
|
||||||
layers.push_back (tl::split (*p, "/").front ());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string final_name = tl::join (layers, "/") + ".LABEL";
|
if (ex.test (":MASK:")) {
|
||||||
for (std::vector<std::string>::const_iterator l = layers.begin (); l != layers.end (); ++l) {
|
ex.read (mask);
|
||||||
layer_map [std::make_pair (*l, std::make_pair (Label, (unsigned int) 0))] = db::LayerProperties (layer, datatype, final_name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (w1 == "COMP") {
|
if (i == purpose_translation.end ()) {
|
||||||
|
|
||||||
// ignore "COMP (ALL) ..."
|
tl::warn << tl::sprintf (tl::to_string (tr ("Reading layer map file %s, line %d: purpose %s ignored for layer %s")), path, ts.line_number (), ps, w1);
|
||||||
|
|
||||||
} else {
|
} else if (i->second == All) {
|
||||||
|
|
||||||
// converts a line like
|
for (std::map<std::string, LayerPurpose>::const_iterator p = purpose_translation.begin (); p != purpose_translation.end (); ++p) {
|
||||||
// "M1 SPNET,NET,PINS,LEFPINS ..."
|
if (p->second != All) {
|
||||||
// into a canonical name mapping like
|
translated_purposes.insert (std::make_pair (p->second, mask));
|
||||||
// "(M1,NET): M1.NET/PINS"
|
|
||||||
// "(M1,PINS): M1.NET/PINS"
|
|
||||||
// (separating, translating and recombing the purposes)
|
|
||||||
|
|
||||||
std::set<std::pair<LayerPurpose, unsigned int> > translated_purposes;
|
|
||||||
|
|
||||||
std::vector<std::string> purposes = tl::split (w2, ",");
|
|
||||||
std::reverse (purposes.begin (), purposes.end ());
|
|
||||||
|
|
||||||
unsigned int mask = 0;
|
|
||||||
|
|
||||||
for (std::vector<std::string>::const_iterator p = purposes.begin (); p != purposes.end (); ++p) {
|
|
||||||
|
|
||||||
std::string p_uc = tl::to_upper_case (*p);
|
|
||||||
tl::Extractor ex (p_uc.c_str ());
|
|
||||||
|
|
||||||
std::string ps;
|
|
||||||
ex.read_word_or_quoted (ps);
|
|
||||||
|
|
||||||
if (ex.test (":")) {
|
|
||||||
if (ex.test ("MASK") && ex.test (":")) {
|
|
||||||
ex.read (mask);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<std::string, LayerPurpose>::const_iterator i = purpose_translation.find (ps);
|
} else {
|
||||||
if (i != purpose_translation.end ()) {
|
|
||||||
translated_purposes.insert (std::make_pair (i->second, mask));
|
translated_purposes.insert (std::make_pair (i->second, mask));
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// create a visual description string for the combined purposes
|
}
|
||||||
std::string purpose_str;
|
|
||||||
|
|
||||||
for (std::set<std::pair<LayerPurpose, unsigned int> >::const_iterator p = translated_purposes.begin (); p != translated_purposes.end (); ++p) {
|
// create a visual description string for the combined purposes
|
||||||
|
std::string purpose_str;
|
||||||
|
|
||||||
if (p != translated_purposes.begin ()) {
|
for (std::set<std::pair<LayerPurpose, unsigned int> >::const_iterator p = translated_purposes.begin (); p != translated_purposes.end (); ++p) {
|
||||||
purpose_str += "/";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string ps = purpose_translation_rev [p->first];
|
|
||||||
if (p->second > 0) {
|
|
||||||
ps += ":";
|
|
||||||
ps += tl::to_string (p->second);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((purpose_str + ps).size () > max_purpose_str) {
|
|
||||||
purpose_str += "...";
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
purpose_str += ps;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (p != translated_purposes.begin ()) {
|
||||||
|
purpose_str += "/";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string final_name = w1 + "." + purpose_str;
|
std::string ps = purpose_translation_rev [p->first];
|
||||||
|
if (p->second > 0) {
|
||||||
for (std::set<std::pair<LayerPurpose, unsigned int> >::const_iterator p = translated_purposes.begin (); p != translated_purposes.end (); ++p) {
|
ps += ":";
|
||||||
layer_map [std::make_pair (w1, *p)] = db::LayerProperties (layer, datatype, final_name);
|
ps += tl::to_string (p->second);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((purpose_str + ps).size () > max_purpose_str) {
|
||||||
|
purpose_str += "...";
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
purpose_str += ps;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string final_name = w1 + "." + purpose_str;
|
||||||
|
|
||||||
|
for (std::set<std::pair<LayerPurpose, unsigned int> >::const_iterator p = translated_purposes.begin (); p != translated_purposes.end (); ++p) {
|
||||||
|
for (std::vector<int>::const_iterator l = layers.begin (); l != layers.end (); ++l) {
|
||||||
|
for (std::vector<int>::const_iterator d = datatypes.begin (); d != datatypes.end (); ++d) {
|
||||||
|
layer_map [std::make_pair (w1, *p)].push_back (db::LayerProperties (*l, *d, final_name));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -967,19 +1036,29 @@ LEFDEFReaderState::read_map_file (const std::string &path, db::Layout &layout)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// build an explicit layer mapping now.
|
||||||
|
|
||||||
|
tl_assert (m_has_explicit_layer_mapping);
|
||||||
|
m_layers.clear ();
|
||||||
|
m_layer_map.clear ();
|
||||||
|
|
||||||
db::DirectLayerMapping lm (&layout);
|
db::DirectLayerMapping lm (&layout);
|
||||||
for (std::map<std::pair<std::string, std::pair<LayerPurpose, unsigned int> >, db::LayerProperties>::const_iterator i = layer_map.begin (); i != layer_map.end (); ++i) {
|
for (std::map<std::pair<std::string, std::pair<LayerPurpose, unsigned int> >, std::vector<db::LayerProperties> >::const_iterator i = layer_map.begin (); i != layer_map.end (); ++i) {
|
||||||
map_layer_explicit (i->first.first, i->first.second.first, i->second, lm.map_layer (i->second).second, i->first.second.second);
|
for (std::vector<db::LayerProperties>::const_iterator j = i->second.begin (); j != i->second.end (); ++j) {
|
||||||
|
unsigned int layer = lm.map_layer (*j).second;
|
||||||
|
m_layers [i->first].insert (layer);
|
||||||
|
m_layer_map.mmap (*j, layer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair <bool, unsigned int>
|
std::set <unsigned int>
|
||||||
LEFDEFReaderState::open_layer (db::Layout &layout, const std::string &n, LayerPurpose purpose, unsigned int mask)
|
LEFDEFReaderState::open_layer (db::Layout &layout, const std::string &n, LayerPurpose purpose, unsigned int mask)
|
||||||
{
|
{
|
||||||
std::map <std::pair<std::string, std::pair<LayerPurpose, unsigned int> >, std::pair<bool, unsigned int> >::const_iterator nl = m_layers.find (std::make_pair (n, std::make_pair (purpose, mask)));
|
std::map <std::pair<std::string, std::pair<LayerPurpose, unsigned int> >, std::set<unsigned int> >::const_iterator nl = m_layers.find (std::make_pair (n, std::make_pair (purpose, mask)));
|
||||||
if (nl == m_layers.end ()) {
|
if (nl == m_layers.end ()) {
|
||||||
|
|
||||||
std::pair <bool, unsigned int> ll (false, 0);
|
std::set <unsigned int> ll;
|
||||||
|
|
||||||
if (n.empty () || ! m_has_explicit_layer_mapping) {
|
if (n.empty () || ! m_has_explicit_layer_mapping) {
|
||||||
ll = open_layer_uncached (layout, n, purpose, mask);
|
ll = open_layer_uncached (layout, n, purpose, mask);
|
||||||
|
|
@ -993,14 +1072,84 @@ LEFDEFReaderState::open_layer (db::Layout &layout, const std::string &n, LayerPu
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair <bool, unsigned int>
|
static std::string purpose_to_name (LayerPurpose purpose)
|
||||||
LEFDEFReaderState::open_layer_uncached (db::Layout &layout, const std::string &n, LayerPurpose purpose, unsigned int mask)
|
{
|
||||||
|
switch (purpose) {
|
||||||
|
case Outline:
|
||||||
|
return "OUTLINE";
|
||||||
|
case Regions:
|
||||||
|
return "REGION";
|
||||||
|
case PlacementBlockage:
|
||||||
|
return "BLOCKAGE";
|
||||||
|
case Routing:
|
||||||
|
return "NET";
|
||||||
|
case SpecialRouting:
|
||||||
|
return "SPNET";
|
||||||
|
case ViaGeometry:
|
||||||
|
return "VIA";
|
||||||
|
case Label:
|
||||||
|
return "LABEL";
|
||||||
|
case Pins:
|
||||||
|
return "PIN";
|
||||||
|
case LEFPins:
|
||||||
|
return "LEFPIN";
|
||||||
|
case Obstructions:
|
||||||
|
return "LEFOBS";
|
||||||
|
case Blockage:
|
||||||
|
return "BLK";
|
||||||
|
case All:
|
||||||
|
return "ALL";
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::string ();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Implements implicit layer mapping
|
||||||
|
*
|
||||||
|
* This is how Implicit layer mapping works:
|
||||||
|
*
|
||||||
|
* 1. For named layers (e.g. routing, pin, etc.
|
||||||
|
*
|
||||||
|
* A decorated name is formed from the basic name and the purpose string (e.g. "M1" -> "M1.PIN").
|
||||||
|
* With the example of "M1" and purpose Pin (decorated name "M1.PIN") and with a tech component datatype specification
|
||||||
|
* of "5" for "Pin", the layer map entries have the following effect:
|
||||||
|
*
|
||||||
|
* Layer map Result
|
||||||
|
*
|
||||||
|
* (nothing) M1.PIN (default/5) (only if "create_all_layers" is ON, "default" is a default number assigned by the reader)
|
||||||
|
* M1.PIN : 1/0 M1.PIN (1/0)
|
||||||
|
* M1.PIN : 1/17 M1.PIN (1/17)
|
||||||
|
* M1 : 1/0 M1.PIN (1/5)
|
||||||
|
* M1 : 1/2 M1.PIN (1/7) (datatypes will add)
|
||||||
|
* M1 M1.PIN (default/5)
|
||||||
|
* M1 : METAL1 METAL1.PIN (default/5) (name is taken from layer map and decorated)
|
||||||
|
* M1 : METAL1 (1/2) METAL1.PIN (1/7)
|
||||||
|
* M1.PIN : METAL1_PIN METAL1_PIN (default/5) (specific name is used without decoration)
|
||||||
|
* M1.PIN : METAL1_PIN (1/17) METAL1_PIN (1/17) (full and specific mapping)
|
||||||
|
*
|
||||||
|
* 2. For general layers (e.g. outline)
|
||||||
|
*
|
||||||
|
* By default, the name, layer and datatype are taken from the tech component's specification. The specification may
|
||||||
|
* lack the layer and datatype and even the name. If the name is missing, it is generated from the purpose.
|
||||||
|
*
|
||||||
|
* Here are some examples for the mapping of "OUTLINE":
|
||||||
|
*
|
||||||
|
* Tech component Layer map Result
|
||||||
|
*
|
||||||
|
* (nothing) (nothing) OUTLINE (only if "create_all_layers" is ON)
|
||||||
|
* OUTL (nothing) OUTL (default/0) ("default" is a default number assigned by the reader)
|
||||||
|
* OUTL (4/17) (nothing) OUTL (4/17)
|
||||||
|
* OUTL OUTL : 5/1 OUTL (5/1)
|
||||||
|
* OUTL (4/17) OUTL : 4/11 OUTL 4/11
|
||||||
|
* OUTL (4/17) 4/17 : 4/11 OUTL 4/11
|
||||||
|
* 4/17 4/17 : 4/11 OUTLINE 4/11
|
||||||
|
*/
|
||||||
|
|
||||||
|
std::set<unsigned int> LEFDEFReaderState::open_layer_uncached(db::Layout &layout, const std::string &n, LayerPurpose purpose, unsigned int mask)
|
||||||
{
|
{
|
||||||
if (n.empty ()) {
|
if (n.empty ()) {
|
||||||
|
|
||||||
// NOTE: the canonical name is independent from the tech component's settings
|
|
||||||
// as is "(name)". It's used for implementing the automatic map file import
|
|
||||||
// feature.
|
|
||||||
std::string ld;
|
std::string ld;
|
||||||
bool produce = false;
|
bool produce = false;
|
||||||
|
|
||||||
|
|
@ -1016,7 +1165,7 @@ LEFDEFReaderState::open_layer_uncached (db::Layout &layout, const std::string &n
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! produce) {
|
if (! produce) {
|
||||||
return std::make_pair (false, 0);
|
return std::set<unsigned int> ();
|
||||||
}
|
}
|
||||||
|
|
||||||
db::LayerProperties lp;
|
db::LayerProperties lp;
|
||||||
|
|
@ -1028,13 +1177,69 @@ LEFDEFReaderState::open_layer_uncached (db::Layout &layout, const std::string &n
|
||||||
lp.datatype = 0;
|
lp.datatype = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (db::Layout::layer_iterator l = layout.begin_layers (); l != layout.end_layers (); ++l) {
|
// if no name is given, derive one from the purpose
|
||||||
if ((*l).second->log_equal (lp)) {
|
if (lp.name.empty ()) {
|
||||||
return std::make_pair (true, (*l).first);
|
lp.name = purpose_to_name (purpose);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lp.layer < 0) {
|
||||||
|
std::map<std::string, int>::const_iterator ldef = m_default_number.find (lp.name);
|
||||||
|
if (ldef != m_default_number.end ()) {
|
||||||
|
lp.layer = ldef->second;
|
||||||
|
lp.datatype = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::make_pair (true, layout.insert_layer (lp));
|
// employ the layer map to find the target layer
|
||||||
|
std::set<unsigned int> ll = m_layer_map.logical (lp, layout);
|
||||||
|
if (ll.empty () && ! m_create_layers) {
|
||||||
|
return std::set<unsigned int> ();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::set<unsigned int> res;
|
||||||
|
|
||||||
|
// map the layers to targets from the layout
|
||||||
|
// (NOTE: the other readers will do this in advance, but LEF/DEF is too dynamic)
|
||||||
|
|
||||||
|
bool at_least_once = true;
|
||||||
|
for (std::set<unsigned int>::const_iterator l = ll.begin (); l != ll.end () || at_least_once; ++l) {
|
||||||
|
|
||||||
|
at_least_once = false;
|
||||||
|
|
||||||
|
// If the layer map provides a target, use that one for the layer
|
||||||
|
db::LayerProperties lp_new = lp;
|
||||||
|
const db::LayerProperties *lpp = (l == ll.end () ? 0 : m_layer_map.target (*l));
|
||||||
|
if (lpp) {
|
||||||
|
if (! lpp->name.empty ()) {
|
||||||
|
lp_new.name = lpp->name;
|
||||||
|
}
|
||||||
|
if (lpp->datatype >= 0) {
|
||||||
|
lp_new.datatype = lpp->datatype;
|
||||||
|
}
|
||||||
|
if (lpp->layer >= 0) {
|
||||||
|
lp_new.layer = lpp->layer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool found = false;
|
||||||
|
for (db::Layout::layer_iterator i = layout.begin_layers (); i != layout.end_layers () && ! found; ++i) {
|
||||||
|
if ((*i).second->log_equal (lp_new)) {
|
||||||
|
found = true;
|
||||||
|
res.insert ((*i).first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! found) {
|
||||||
|
res.insert (layout.insert_layer (lp_new));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (l == ll.end ()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
|
@ -1068,12 +1273,10 @@ LEFDEFReaderState::open_layer_uncached (db::Layout &layout, const std::string &n
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (! produce) {
|
if (! produce) {
|
||||||
return std::make_pair (false, 0);
|
return std::set<unsigned int> ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: "name" is the decorated name as provided by the tech component's
|
|
||||||
// x_suffix specifications.
|
|
||||||
std::string name_suffix;
|
std::string name_suffix;
|
||||||
int dt = 0;
|
int dt = 0;
|
||||||
|
|
||||||
|
|
@ -1115,8 +1318,10 @@ LEFDEFReaderState::open_layer_uncached (db::Layout &layout, const std::string &n
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// "name" is the decorated name as provided by the tech component's x_suffix specifications.
|
||||||
std::string name = n + name_suffix;
|
std::string name = n + name_suffix;
|
||||||
|
|
||||||
|
// Assign a layer number (a default one for now) and the datatype from the tech component's x_datatype specification.
|
||||||
db::LayerProperties lp (name);
|
db::LayerProperties lp (name);
|
||||||
lp.datatype = dt;
|
lp.datatype = dt;
|
||||||
std::map<std::string, int>::const_iterator ldef = m_default_number.find (n);
|
std::map<std::string, int>::const_iterator ldef = m_default_number.find (n);
|
||||||
|
|
@ -1124,37 +1329,71 @@ LEFDEFReaderState::open_layer_uncached (db::Layout &layout, const std::string &n
|
||||||
lp.layer = ldef->second;
|
lp.layer = ldef->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<bool, unsigned int> ll = m_layer_map.logical (name, layout);
|
// Route the layer through the layer map, first the decorated name and if there is no mapping, the
|
||||||
if (! ll.first) {
|
// undecorated one.
|
||||||
|
std::set<unsigned int> ll = m_layer_map.logical (name, layout);
|
||||||
|
bool generic_match = false;
|
||||||
|
if (ll.empty ()) {
|
||||||
ll = m_layer_map.logical (n, layout);
|
ll = m_layer_map.logical (n, layout);
|
||||||
|
generic_match = true;
|
||||||
|
} else if (n == name) {
|
||||||
|
// no suffix defined in tech component -> treat as generic match and combine datatypes
|
||||||
|
generic_match = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ll.first) {
|
if (ll.empty () && ! m_create_layers) {
|
||||||
|
return std::set<unsigned int> ();
|
||||||
|
}
|
||||||
|
|
||||||
const db::LayerProperties *lpp = m_layer_map.target (ll.second);
|
std::set<unsigned int> res;
|
||||||
|
|
||||||
|
bool at_least_once = true;
|
||||||
|
for (std::set<unsigned int>::const_iterator l = ll.begin (); l != ll.end () || at_least_once; ++l) {
|
||||||
|
|
||||||
|
at_least_once = false;
|
||||||
|
|
||||||
|
// If the layer map provides a target, use that one for the layer
|
||||||
|
db::LayerProperties lp_new = lp;
|
||||||
|
const db::LayerProperties *lpp = (l == ll.end () ? 0 : m_layer_map.target (*l));
|
||||||
if (lpp) {
|
if (lpp) {
|
||||||
lp = *lpp;
|
lp_new = *lpp;
|
||||||
if (lp.datatype >= 0) {
|
if (lp_new.datatype < 0) {
|
||||||
lp.datatype += dt;
|
lp_new.datatype = dt;
|
||||||
|
} else if (generic_match) {
|
||||||
|
lp_new.datatype += dt;
|
||||||
}
|
}
|
||||||
if (lp.name.empty ()) {
|
if (lp_new.name.empty ()) {
|
||||||
lp.name = name;
|
lp_new.name = name;
|
||||||
|
} else if (generic_match) {
|
||||||
|
lp_new.name += name_suffix;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (! m_create_layers) {
|
int lfound = -1;
|
||||||
return std::make_pair (false, 0);
|
if (lp_new.layer >= 0 && lp_new.datatype >= 0) {
|
||||||
}
|
for (db::Layout::layer_iterator i = layout.begin_layers (); i != layout.end_layers () && lfound < 0; ++i) {
|
||||||
|
if ((*i).second->log_equal (lp_new)) {
|
||||||
if (lp.layer >= 0 && lp.datatype >= 0) {
|
lfound = int ((*i).first);
|
||||||
for (db::Layout::layer_iterator l = layout.begin_layers (); l != layout.end_layers (); ++l) {
|
}
|
||||||
if ((*l).second->log_equal (lp)) {
|
|
||||||
return std::make_pair (true, (*l).first);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (lfound < 0) {
|
||||||
|
res.insert (layout.insert_layer (lp_new));
|
||||||
|
} else {
|
||||||
|
res.insert ((unsigned int) lfound);
|
||||||
|
db::LayerProperties lp_org = layout.get_properties ((unsigned int) lfound);
|
||||||
|
join_layer_names (lp_org.name, name);
|
||||||
|
layout.set_properties ((unsigned int) lfound, lp_org);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (l == ll.end ()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::make_pair (true, layout.insert_layer (lp));
|
return res;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1181,78 +1420,13 @@ LEFDEFReaderState::finish (db::Layout &layout)
|
||||||
|
|
||||||
db::LayerMap lm;
|
db::LayerMap lm;
|
||||||
|
|
||||||
for (std::map <std::pair<std::string, std::pair<LayerPurpose, unsigned int> >, std::pair<bool, unsigned int> >::const_iterator l = m_layers.begin (); l != m_layers.end (); ++l) {
|
for (std::map <std::pair<std::string, std::pair<LayerPurpose, unsigned int> >, std::set<unsigned int> >::const_iterator l = m_layers.begin (); l != m_layers.end (); ++l) {
|
||||||
|
|
||||||
if (! l->second.first) {
|
if (l->second.empty ()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ps;
|
std::string ps = purpose_to_name (l->first.second.first);
|
||||||
|
|
||||||
switch (l->first.second.first) {
|
|
||||||
case Outline:
|
|
||||||
ps = "OUTLINE";
|
|
||||||
break;
|
|
||||||
case Regions:
|
|
||||||
ps = "REGION";
|
|
||||||
break;
|
|
||||||
case PlacementBlockage:
|
|
||||||
ps = "PLACEMENT_BLK";
|
|
||||||
break;
|
|
||||||
case Routing:
|
|
||||||
default:
|
|
||||||
ps = "NET";
|
|
||||||
break;
|
|
||||||
case SpecialRouting:
|
|
||||||
ps = "SPNET";
|
|
||||||
break;
|
|
||||||
case ViaGeometry:
|
|
||||||
ps = "VIA";
|
|
||||||
break;
|
|
||||||
case Label:
|
|
||||||
ps = "LABEL";
|
|
||||||
break;
|
|
||||||
case Pins:
|
|
||||||
ps = "PIN";
|
|
||||||
break;
|
|
||||||
case LEFPins:
|
|
||||||
ps = "LEFPIN";
|
|
||||||
break;
|
|
||||||
case Obstructions:
|
|
||||||
ps = "OBS";
|
|
||||||
break;
|
|
||||||
case Blockage:
|
|
||||||
ps = "BLK";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int layer_index = l->second.second;
|
|
||||||
db::LayerProperties lp = layout.get_properties (layer_index);
|
|
||||||
|
|
||||||
if (lp.layer < 0) {
|
|
||||||
|
|
||||||
std::map<std::string, int>::const_iterator n4n = number_for_name.end ();
|
|
||||||
if (! l->first.first.empty ()) {
|
|
||||||
n4n = number_for_name.find (l->first.first);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (n4n == number_for_name.end ()) {
|
|
||||||
do {
|
|
||||||
++lnum;
|
|
||||||
} while (used_numbers.find (lnum) != used_numbers.end ());
|
|
||||||
number_for_name.insert (std::make_pair (l->first.first, lnum));
|
|
||||||
lp.layer = lnum;
|
|
||||||
} else {
|
|
||||||
lp.layer = n4n->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lp.datatype < 0) {
|
|
||||||
lp.datatype = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
layout.set_properties (layer_index, lp);
|
|
||||||
|
|
||||||
std::string n = l->first.first;
|
std::string n = l->first.first;
|
||||||
if (! n.empty ()) {
|
if (! n.empty ()) {
|
||||||
|
|
@ -1265,11 +1439,43 @@ LEFDEFReaderState::finish (db::Layout &layout)
|
||||||
n += tl::to_string (l->first.second.second);
|
n += tl::to_string (l->first.second.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
lm.map (db::LayerProperties (n), l->second.second, lp);
|
for (std::set<unsigned int>::const_iterator li = l->second.begin (); li != l->second.end (); ++li) {
|
||||||
|
|
||||||
|
unsigned int layer_index = *li;
|
||||||
|
db::LayerProperties lp = layout.get_properties (layer_index);
|
||||||
|
|
||||||
|
if (lp.layer < 0) {
|
||||||
|
|
||||||
|
std::map<std::string, int>::const_iterator n4n = number_for_name.end ();
|
||||||
|
if (! l->first.first.empty ()) {
|
||||||
|
n4n = number_for_name.find (l->first.first);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n4n == number_for_name.end ()) {
|
||||||
|
do {
|
||||||
|
++lnum;
|
||||||
|
} while (used_numbers.find (lnum) != used_numbers.end ());
|
||||||
|
number_for_name.insert (std::make_pair (l->first.first, lnum));
|
||||||
|
lp.layer = lnum;
|
||||||
|
} else {
|
||||||
|
lp.layer = n4n->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lp.datatype < 0) {
|
||||||
|
lp.datatype = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
layout.set_properties (layer_index, lp);
|
||||||
|
|
||||||
|
lm.mmap (db::LayerProperties (n), layer_index, lp);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// On return we deliver the "canonical" map
|
// On return we deliver the "canonical" map which lists the decorated name vs. the real ones.
|
||||||
m_layer_map = lm;
|
m_layer_map = lm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -775,7 +775,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Specify the LEF macro resolution strategy
|
* @brief Specify the LEF macro resolution strategy when reading DEF files
|
||||||
* Values are:
|
* Values are:
|
||||||
* 0: propduce LEF geometry unless a FOREIGN cell is specified (default)
|
* 0: propduce LEF geometry unless a FOREIGN cell is specified (default)
|
||||||
* 1: produce LEF geometry always and ignore FOREIGN
|
* 1: produce LEF geometry always and ignore FOREIGN
|
||||||
|
|
@ -884,6 +884,7 @@ enum LayerPurpose
|
||||||
Blockage, // from DEF only
|
Blockage, // from DEF only
|
||||||
PlacementBlockage, // from DEF only
|
PlacementBlockage, // from DEF only
|
||||||
Regions, // from DEF only
|
Regions, // from DEF only
|
||||||
|
All // from DEF only
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -1053,7 +1054,7 @@ public:
|
||||||
/**
|
/**
|
||||||
* @brief Create a new layer or return the index of the given layer
|
* @brief Create a new layer or return the index of the given layer
|
||||||
*/
|
*/
|
||||||
std::pair <bool, unsigned int> open_layer (db::Layout &layout, const std::string &name, LayerPurpose purpose, unsigned int mask);
|
std::set<unsigned int> open_layer (db::Layout &layout, const std::string &name, LayerPurpose purpose, unsigned int mask);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Registers a layer (assign a new default layer number)
|
* @brief Registers a layer (assign a new default layer number)
|
||||||
|
|
@ -1187,7 +1188,7 @@ private:
|
||||||
LEFDEFReaderState (const LEFDEFReaderState &);
|
LEFDEFReaderState (const LEFDEFReaderState &);
|
||||||
LEFDEFReaderState &operator= (const LEFDEFReaderState &);
|
LEFDEFReaderState &operator= (const LEFDEFReaderState &);
|
||||||
|
|
||||||
std::map <std::pair<std::string, std::pair<LayerPurpose, unsigned int> >, std::pair<bool, unsigned int> > m_layers;
|
std::map <std::pair<std::string, std::pair<LayerPurpose, unsigned int> >, std::set<unsigned int> > m_layers;
|
||||||
db::LayerMap m_layer_map;
|
db::LayerMap m_layer_map;
|
||||||
bool m_create_layers;
|
bool m_create_layers;
|
||||||
bool m_has_explicit_layer_mapping;
|
bool m_has_explicit_layer_mapping;
|
||||||
|
|
@ -1200,8 +1201,7 @@ private:
|
||||||
std::map<std::string, LEFDEFLayoutGenerator *> m_macro_generators;
|
std::map<std::string, LEFDEFLayoutGenerator *> m_macro_generators;
|
||||||
std::map<std::string, db::cell_index_type> m_foreign_cells;
|
std::map<std::string, db::cell_index_type> m_foreign_cells;
|
||||||
|
|
||||||
std::pair <bool, unsigned int> open_layer_uncached (db::Layout &layout, const std::string &name, LayerPurpose purpose, unsigned int mask);
|
std::set<unsigned int> open_layer_uncached (db::Layout &layout, const std::string &name, LayerPurpose purpose, unsigned int mask);
|
||||||
void map_layer_explicit (const std::string &n, LayerPurpose purpose, const LayerProperties &lp, unsigned int layer, unsigned int mask);
|
|
||||||
db::cell_index_type foreign_cell(Layout &layout, const std::string &name);
|
db::cell_index_type foreign_cell(Layout &layout, const std::string &name);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -1363,7 +1363,7 @@ protected:
|
||||||
/**
|
/**
|
||||||
* @brief Create a new layer or return the index of the given layer
|
* @brief Create a new layer or return the index of the given layer
|
||||||
*/
|
*/
|
||||||
std::pair <bool, unsigned int> open_layer (db::Layout &layout, const std::string &name, LayerPurpose purpose, unsigned int mask)
|
std::set<unsigned int> open_layer (db::Layout &layout, const std::string &name, LayerPurpose purpose, unsigned int mask)
|
||||||
{
|
{
|
||||||
return mp_reader_state->open_layer (layout, name, purpose, mask);
|
return mp_reader_state->open_layer (layout, name, purpose, mask);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -113,22 +113,25 @@ private:
|
||||||
const db::LayerMap &read_lefdef (db::Layout &layout, const db::LoadLayoutOptions &options, bool import_lef)
|
const db::LayerMap &read_lefdef (db::Layout &layout, const db::LoadLayoutOptions &options, bool import_lef)
|
||||||
{
|
{
|
||||||
const db::LEFDEFReaderOptions *lefdef_options = dynamic_cast<const db::LEFDEFReaderOptions *> (options.get_options (format ()));
|
const db::LEFDEFReaderOptions *lefdef_options = dynamic_cast<const db::LEFDEFReaderOptions *> (options.get_options (format ()));
|
||||||
static db::LEFDEFReaderOptions default_options;
|
db::LEFDEFReaderOptions effective_options;
|
||||||
if (! lefdef_options) {
|
if (lefdef_options) {
|
||||||
lefdef_options = &default_options;
|
effective_options = *lefdef_options;
|
||||||
}
|
}
|
||||||
|
|
||||||
db::LEFDEFReaderState state (lefdef_options, layout, tl::dirname (m_stream.absolute_path ()));
|
db::LEFDEFReaderState state (&effective_options, layout, tl::dirname (m_stream.absolute_path ()));
|
||||||
|
|
||||||
layout.dbu (lefdef_options->dbu ());
|
layout.dbu (effective_options.dbu ());
|
||||||
|
|
||||||
if (import_lef) {
|
if (import_lef) {
|
||||||
|
|
||||||
|
// Always produce LEF geometry when reading LEF
|
||||||
|
effective_options.set_macro_resolution_mode (1);
|
||||||
|
|
||||||
tl::SelfTimer timer (tl::verbosity () >= 21, tl::to_string (tr ("Reading LEF file")));
|
tl::SelfTimer timer (tl::verbosity () >= 21, tl::to_string (tr ("Reading LEF file")));
|
||||||
|
|
||||||
db::LEFImporter importer;
|
db::LEFImporter importer;
|
||||||
|
|
||||||
for (std::vector<std::string>::const_iterator l = lefdef_options->begin_lef_files (); l != lefdef_options->end_lef_files (); ++l) {
|
for (std::vector<std::string>::const_iterator l = effective_options.begin_lef_files (); l != effective_options.end_lef_files (); ++l) {
|
||||||
|
|
||||||
std::string lp = correct_path (*l, layout, tl::dirname (m_stream.absolute_path ()));
|
std::string lp = correct_path (*l, layout, tl::dirname (m_stream.absolute_path ()));
|
||||||
|
|
||||||
|
|
@ -149,7 +152,7 @@ private:
|
||||||
|
|
||||||
DEFImporter importer;
|
DEFImporter importer;
|
||||||
|
|
||||||
for (std::vector<std::string>::const_iterator l = lefdef_options->begin_lef_files (); l != lefdef_options->end_lef_files (); ++l) {
|
for (std::vector<std::string>::const_iterator l = effective_options.begin_lef_files (); l != effective_options.end_lef_files (); ++l) {
|
||||||
|
|
||||||
std::string lp = correct_path (*l, layout, tl::dirname (m_stream.absolute_path ()));
|
std::string lp = correct_path (*l, layout, tl::dirname (m_stream.absolute_path ()));
|
||||||
|
|
||||||
|
|
@ -163,7 +166,7 @@ private:
|
||||||
|
|
||||||
// Additionally read all LEF files next to the DEF file
|
// Additionally read all LEF files next to the DEF file
|
||||||
|
|
||||||
if (lefdef_options->read_lef_with_def ()) {
|
if (effective_options.read_lef_with_def ()) {
|
||||||
|
|
||||||
std::string input_dir = tl::absolute_path (m_stream.absolute_path ());
|
std::string input_dir = tl::absolute_path (m_stream.absolute_path ());
|
||||||
|
|
||||||
|
|
@ -198,7 +201,7 @@ private:
|
||||||
std::map<std::string, db::cell_index_type> foreign_cells = state.foreign_cells ();
|
std::map<std::string, db::cell_index_type> foreign_cells = state.foreign_cells ();
|
||||||
db::cell_index_type seen = std::numeric_limits<db::cell_index_type>::max ();
|
db::cell_index_type seen = std::numeric_limits<db::cell_index_type>::max ();
|
||||||
|
|
||||||
std::vector<db::Layout *> macro_layouts = lefdef_options->macro_layouts ();
|
std::vector<db::Layout *> macro_layouts = effective_options.macro_layouts ();
|
||||||
for (std::vector<db::Layout *>::const_iterator m = macro_layouts.begin (); m != macro_layouts.end (); ++m) {
|
for (std::vector<db::Layout *>::const_iterator m = macro_layouts.begin (); m != macro_layouts.end (); ++m) {
|
||||||
|
|
||||||
std::vector<db::cell_index_type> target_cells, source_cells;
|
std::vector<db::cell_index_type> target_cells, source_cells;
|
||||||
|
|
|
||||||
|
|
@ -937,6 +937,24 @@ LEFImporter::read_macro (Layout &layout)
|
||||||
|
|
||||||
expect ("END");
|
expect ("END");
|
||||||
|
|
||||||
|
} else if (test ("DENSITY")) {
|
||||||
|
|
||||||
|
// read over DENSITY statements
|
||||||
|
while (! test ("END")) {
|
||||||
|
if (test ("LAYER")) {
|
||||||
|
get ();
|
||||||
|
expect (";");
|
||||||
|
} else {
|
||||||
|
expect ("RECT");
|
||||||
|
for (int i = 0; i < 5; ++i) {
|
||||||
|
get_double ();
|
||||||
|
}
|
||||||
|
expect (";");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expect ("END");
|
||||||
|
|
||||||
} else if (test ("FIXEDMASK")) {
|
} else if (test ("FIXEDMASK")) {
|
||||||
|
|
||||||
mg->set_fixedmask (true);
|
mg->set_fixedmask (true);
|
||||||
|
|
|
||||||
|
|
@ -770,8 +770,8 @@ gsi::Class<db::LEFDEFReaderOptions> decl_lefdef_config ("db", "LEFDEFReaderConfi
|
||||||
"This property has been added in version 0.27.\n"
|
"This property has been added in version 0.27.\n"
|
||||||
) +
|
) +
|
||||||
gsi::method ("macro_resolution_mode", &db::LEFDEFReaderOptions::macro_resolution_mode,
|
gsi::method ("macro_resolution_mode", &db::LEFDEFReaderOptions::macro_resolution_mode,
|
||||||
"@brief Gets the macro resolution mode.\n"
|
"@brief Gets the macro resolution mode (LEF macros into DEF).\n"
|
||||||
"This property describes the way LEF macros are turned into GDS cells. There "
|
"This property describes the way LEF macros are turned into layout cells when reading DEF. There "
|
||||||
"are three modes available:\n"
|
"are three modes available:\n"
|
||||||
"\n"
|
"\n"
|
||||||
"@ul\n"
|
"@ul\n"
|
||||||
|
|
@ -786,7 +786,7 @@ gsi::Class<db::LEFDEFReaderOptions> decl_lefdef_config ("db", "LEFDEFReaderConfi
|
||||||
"This property has been added in version 0.27.\n"
|
"This property has been added in version 0.27.\n"
|
||||||
) +
|
) +
|
||||||
gsi::method ("macro_resolution_mode=", &db::LEFDEFReaderOptions::set_macro_resolution_mode, gsi::arg ("mode"),
|
gsi::method ("macro_resolution_mode=", &db::LEFDEFReaderOptions::set_macro_resolution_mode, gsi::arg ("mode"),
|
||||||
"@brief Sets the macro resolution mode.\n"
|
"@brief Sets the macro resolution mode (LEF macros into DEF).\n"
|
||||||
"See \\macro_resolution_mode for details about this property.\n"
|
"See \\macro_resolution_mode for details about this property.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"This property has been added in version 0.27.\n"
|
"This property has been added in version 0.27.\n"
|
||||||
|
|
|
||||||
|
|
@ -294,7 +294,7 @@
|
||||||
<item row="1" column="4">
|
<item row="1" column="4">
|
||||||
<widget class="QLabel" name="label">
|
<widget class="QLabel" name="label">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>LEF import</string>
|
<string>LEF import into DEF</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
|
@ -708,6 +708,8 @@
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>If a layer map file is given, pattern based rules are ignored.
|
<string>If a layer map file is given, pattern based rules are ignored.
|
||||||
If used inside a technology, the file will be looked up relative to the technology's base path.
|
If used inside a technology, the file will be looked up relative to the technology's base path.
|
||||||
|
Otherwise it's looked up relative to the LEF or DEF file.
|
||||||
|
|
||||||
(2*) Die area, Blockage and Region layers in map file will have priority over global production rules above.</string>
|
(2*) Die area, Blockage and Region layers in map file will have priority over global production rules above.</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="wordWrap">
|
<property name="wordWrap">
|
||||||
|
|
|
||||||
|
|
@ -50,16 +50,13 @@ static db::LEFDEFReaderOptions default_options ()
|
||||||
return tc;
|
return tc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static db::LayerMap run_test (tl::TestBase *_this, const char *lef_dir, const char *filename, const char *au, const db::LEFDEFReaderOptions &options, bool priv = true)
|
static db::LayerMap read (db::Layout &layout, const char *lef_dir, const char *filename, const db::LEFDEFReaderOptions &options, bool priv = true)
|
||||||
{
|
{
|
||||||
std::string fn_path (priv ? tl::testsrc_private () : tl::testsrc ());
|
std::string fn_path (priv ? tl::testsrc_private () : tl::testsrc ());
|
||||||
fn_path += "/testdata/lefdef/";
|
fn_path += "/testdata/lefdef/";
|
||||||
fn_path += lef_dir;
|
fn_path += lef_dir;
|
||||||
fn_path += "/";
|
fn_path += "/";
|
||||||
|
|
||||||
db::Manager m (false);
|
|
||||||
db::Layout layout (&m), layout2 (&m), layout_au (&m);
|
|
||||||
|
|
||||||
tl::Extractor ex (filename);
|
tl::Extractor ex (filename);
|
||||||
|
|
||||||
db::LEFDEFReaderState ld (&options, layout, fn_path);
|
db::LEFDEFReaderState ld (&options, layout, fn_path);
|
||||||
|
|
@ -142,6 +139,16 @@ static db::LayerMap run_test (tl::TestBase *_this, const char *lef_dir, const ch
|
||||||
|
|
||||||
ld.finish (layout);
|
ld.finish (layout);
|
||||||
|
|
||||||
|
return ld.layer_map ();
|
||||||
|
}
|
||||||
|
|
||||||
|
static db::LayerMap run_test (tl::TestBase *_this, const char *lef_dir, const char *filename, const char *au, const db::LEFDEFReaderOptions &options, bool priv = true)
|
||||||
|
{
|
||||||
|
db::Manager m (false);
|
||||||
|
db::Layout layout (&m), layout2 (&m), layout_au (&m);
|
||||||
|
|
||||||
|
db::LayerMap lm = read (layout, lef_dir, filename, options, priv);
|
||||||
|
|
||||||
// normalize the layout by writing to OASIS and reading from ..
|
// normalize the layout by writing to OASIS and reading from ..
|
||||||
|
|
||||||
// generate a "unique" name ...
|
// generate a "unique" name ...
|
||||||
|
|
@ -200,7 +207,7 @@ static db::LayerMap run_test (tl::TestBase *_this, const char *lef_dir, const ch
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ld.layer_map ();
|
return lm;
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(1)
|
TEST(1)
|
||||||
|
|
@ -549,6 +556,202 @@ TEST(115_componentmaskshift)
|
||||||
run_test (_this, "masks-2", "lef:in_tech.lef+lef:in.lef+def:in.def", "au.oas.gz", options, false);
|
run_test (_this, "masks-2", "lef:in_tech.lef+lef:in.lef+def:in.def", "au.oas.gz", options, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(116_layer_mapping)
|
||||||
|
{
|
||||||
|
db::LEFDEFReaderOptions options = default_options ();
|
||||||
|
db::LayerMap lm = db::LayerMap::from_string_file_format ("metal1: 1\nvia1: 2\nmetal2: 3\nOUTLINE: 42/17");
|
||||||
|
options.set_layer_map (lm);
|
||||||
|
|
||||||
|
{
|
||||||
|
db::Layout layout;
|
||||||
|
db::LayerMap lm_read = read (layout, "via_properties", "lef:in.lef+def:in.def", options, false);
|
||||||
|
EXPECT_EQ (lm_read.to_string (),
|
||||||
|
"layer_map('OUTLINE : OUTLINE (42/17)';'metal1.VIA : metal1 (1/0)';'metal2.VIA : metal2 (3/0)';'via1.VIA : via1 (2/0)')"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
options.set_layer_map (db::LayerMap ());
|
||||||
|
|
||||||
|
{
|
||||||
|
db::Layout layout;
|
||||||
|
db::LayerMap lm_read = read (layout, "via_properties", "lef:in.lef+def:in.def", options, false);
|
||||||
|
EXPECT_EQ (lm_read.to_string (),
|
||||||
|
"layer_map('OUTLINE : OUTLINE (4/0)';'metal1.VIA : metal1 (1/0)';'metal2.VIA : metal2 (3/0)';'via1.VIA : via1 (2/0)')"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
lm = db::LayerMap::from_string_file_format ("metal1: M1\nmetal1.V: M1_V\nvia1: V1\nmetal2: M2\nOUTLINE: OUTL");
|
||||||
|
options.set_layer_map (lm);
|
||||||
|
options.set_via_geometry_suffix ("V");
|
||||||
|
options.set_via_geometry_datatype (42);
|
||||||
|
|
||||||
|
{
|
||||||
|
db::Layout layout;
|
||||||
|
db::LayerMap lm_read = read (layout, "via_properties", "lef:in.lef+def:in.def", options, false);
|
||||||
|
EXPECT_EQ (lm_read.to_string (),
|
||||||
|
"layer_map('OUTLINE : OUTL (4/0)';'metal1.VIA : M1V (1/42)';'metal2.VIA : M2V (3/42)';'via1.VIA : V1V (2/42)')"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
lm = db::LayerMap::from_string_file_format ("metal1: M1\nmetal1.V: M1_V\nvia1: V1\nmetal2: M2");
|
||||||
|
options.set_layer_map (lm);
|
||||||
|
options.set_via_geometry_suffix ("V");
|
||||||
|
options.set_via_geometry_datatype (42);
|
||||||
|
options.set_read_all_layers (false);
|
||||||
|
|
||||||
|
{
|
||||||
|
db::Layout layout;
|
||||||
|
db::LayerMap lm_read = read (layout, "via_properties", "lef:in.lef+def:in.def", options, false);
|
||||||
|
EXPECT_EQ (lm_read.to_string (),
|
||||||
|
"layer_map('metal1.VIA : M1V (1/42)';'metal2.VIA : M2V (3/42)';'via1.VIA : V1V (2/42)')"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
lm = db::LayerMap::from_string_file_format ("metal2: M2 (17/1)");
|
||||||
|
options.set_layer_map (lm);
|
||||||
|
|
||||||
|
{
|
||||||
|
db::Layout layout;
|
||||||
|
db::LayerMap lm_read = read (layout, "via_properties", "lef:in.lef+def:in.def", options, false);
|
||||||
|
EXPECT_EQ (lm_read.to_string (),
|
||||||
|
"layer_map('metal2.VIA : M2V (17/43)')"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
options.set_produce_via_geometry (false);
|
||||||
|
|
||||||
|
{
|
||||||
|
db::Layout layout;
|
||||||
|
db::LayerMap lm_read = read (layout, "via_properties", "lef:in.lef+def:in.def", options, false);
|
||||||
|
EXPECT_EQ (lm_read.to_string (),
|
||||||
|
"layer_map()"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
options.set_produce_via_geometry (true);
|
||||||
|
options.set_via_geometry_suffix (".V");
|
||||||
|
lm = db::LayerMap::from_string_file_format ("metal2.V: 17/1");
|
||||||
|
options.set_layer_map (lm);
|
||||||
|
|
||||||
|
{
|
||||||
|
db::Layout layout;
|
||||||
|
db::LayerMap lm_read = read (layout, "via_properties", "lef:in.lef+def:in.def", options, false);
|
||||||
|
EXPECT_EQ (lm_read.to_string (),
|
||||||
|
"layer_map('metal2.VIA : metal2.V (17/1)')"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
lm = db::LayerMap::from_string_file_format ("metal2.V: m2v (17/5)");
|
||||||
|
options.set_layer_map (lm);
|
||||||
|
|
||||||
|
{
|
||||||
|
db::Layout layout;
|
||||||
|
db::LayerMap lm_read = read (layout, "via_properties", "lef:in.lef+def:in.def", options, false);
|
||||||
|
EXPECT_EQ (lm_read.to_string (),
|
||||||
|
"layer_map('metal2.VIA : m2v (17/5)')"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
lm = db::LayerMap::from_string_file_format ("OUTLINE: OUTL");
|
||||||
|
options.set_layer_map (lm);
|
||||||
|
options.set_cell_outline_layer ("OUTLINE (42/17)");
|
||||||
|
|
||||||
|
{
|
||||||
|
db::Layout layout;
|
||||||
|
db::LayerMap lm_read = read (layout, "via_properties", "lef:in.lef+def:in.def", options, false);
|
||||||
|
EXPECT_EQ (lm_read.to_string (),
|
||||||
|
"layer_map('OUTLINE : OUTL (42/17)')"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
lm = db::LayerMap::from_string_file_format ("OUTLINE: OUTL (18/1)");
|
||||||
|
options.set_layer_map (lm);
|
||||||
|
options.set_cell_outline_layer ("OUTLINE (42/17)");
|
||||||
|
|
||||||
|
{
|
||||||
|
db::Layout layout;
|
||||||
|
db::LayerMap lm_read = read (layout, "via_properties", "lef:in.lef+def:in.def", options, false);
|
||||||
|
EXPECT_EQ (lm_read.to_string (),
|
||||||
|
"layer_map('OUTLINE : OUTL (18/1)')"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
options.set_cell_outline_layer ("OUTLINE (42/17)");
|
||||||
|
lm = db::LayerMap::from_string_file_format ("42/17: OUTL (18/1)");
|
||||||
|
options.set_layer_map (lm);
|
||||||
|
|
||||||
|
{
|
||||||
|
db::Layout layout;
|
||||||
|
db::LayerMap lm_read = read (layout, "via_properties", "lef:in.lef+def:in.def", options, false);
|
||||||
|
EXPECT_EQ (lm_read.to_string (),
|
||||||
|
"layer_map('OUTLINE : OUTL (18/1)')"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
options.set_cell_outline_layer ("42/17");
|
||||||
|
lm = db::LayerMap::from_string_file_format ("42/17: 18/1");
|
||||||
|
options.set_layer_map (lm);
|
||||||
|
|
||||||
|
{
|
||||||
|
db::Layout layout;
|
||||||
|
db::LayerMap lm_read = read (layout, "via_properties", "lef:in.lef+def:in.def", options, false);
|
||||||
|
EXPECT_EQ (lm_read.to_string (),
|
||||||
|
"layer_map('OUTLINE : OUTLINE (18/1)')"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(117_mapfile_all)
|
||||||
|
{
|
||||||
|
db::LEFDEFReaderOptions options = default_options ();
|
||||||
|
|
||||||
|
db::Layout layout;
|
||||||
|
db::LayerMap lm_read = read (layout, "mapfile", "lef:in.lef+def:in.def+map:all.map", options, false);
|
||||||
|
EXPECT_EQ (lm_read.to_string (),
|
||||||
|
"layer_map("
|
||||||
|
"'OUTLINE : OUTLINE (1/0)';"
|
||||||
|
"'+M1.LEFOBS;M1.LEFPIN;M1.NET;M1.PIN;M1.SPNET;M1.VIA : \\'M1.NET/PIN/...\\' (1/5)';"
|
||||||
|
"'+M1.NET;M1.SPNET : \\'M1.NET/SPNET\\' (16/0)';"
|
||||||
|
"'+M1.NET : M1.NET (18/0)';"
|
||||||
|
"'+M1.BLK;M1.LEFOBS;M1.LEFPIN;M1.NET;M1.PIN;M1.SPNET;M1.VIA : \\'M1.NET/PIN/...\\' (22/2)';"
|
||||||
|
"'+\\'M1.NET:1\\';\\'M1.PIN:1\\';\\'M1.SPNET:1\\';\\'M1.VIA:1\\' : \\'M1.NET:1/...\\' (6/0)';"
|
||||||
|
"'+\\'M1.NET:1\\' : \\'M1.NET:1\\' (7/0)';"
|
||||||
|
"'+M1.PIN : M1.PIN (3/0)';"
|
||||||
|
"'+M1.PIN : M1.PIN (4/0)';"
|
||||||
|
"'+M1.VIA : M1.VIA (20/0)';"
|
||||||
|
"'+M1.VIA : M1.VIA (21/0)';"
|
||||||
|
"'+M1.LABEL : M1.LABEL (26/0)';"
|
||||||
|
"'+M1.LABEL : M1.LABEL (27/0)';"
|
||||||
|
"'+M1.LABEL : M1.LABEL (28/1)';"
|
||||||
|
"'+M1.BLK : M1.BLOCKAGE (13/0)';"
|
||||||
|
"'M1_TEXT.LABEL : M1_TEXT.LABEL (29/0)'"
|
||||||
|
")"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(118_density)
|
||||||
|
{
|
||||||
|
run_test (_this, "density", "read:in.lef", "au.oas.gz", default_options (), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(119_multimapping)
|
||||||
|
{
|
||||||
|
db::LEFDEFReaderOptions options = default_options ();
|
||||||
|
db::LayerMap lm = db::LayerMap::from_string_file_format ("(M1:1/0)\n(M2:3/0)\n+(M1:100/0)\n+(M2:100/0)\n(VIA1:2/0)");
|
||||||
|
options.set_layer_map (lm);
|
||||||
|
|
||||||
|
db::LayerMap lm_read = run_test (_this, "multimap", "def:test.def", "au.oas.gz", options, false);
|
||||||
|
EXPECT_EQ (lm_read.to_string (),
|
||||||
|
"layer_map("
|
||||||
|
"'OUTLINE : OUTLINE (4/0)';"
|
||||||
|
"'+M1.VIA : M1 (1/0)';"
|
||||||
|
"'+M1.VIA;M2.VIA : \\'M1;M2\\' (100/0)';"
|
||||||
|
"'+M2.VIA : M2 (3/0)';"
|
||||||
|
"'VIA1.VIA : VIA1 (2/0)'"
|
||||||
|
")"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
TEST(200_lefdef_plugin)
|
TEST(200_lefdef_plugin)
|
||||||
{
|
{
|
||||||
db::Layout ly;
|
db::Layout ly;
|
||||||
|
|
@ -594,3 +797,4 @@ TEST(201_lefdef_plugin_explicit_lef)
|
||||||
|
|
||||||
db::compare_layouts (_this, ly, fn_path + "au_plugin_alt_lef.oas.gz", db::WriteOAS);
|
db::compare_layouts (_this, ly, fn_path + "au_plugin_alt_lef.oas.gz", db::WriteOAS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -72,13 +72,9 @@ MAGReader::read (db::Layout &layout)
|
||||||
const LayerMap &
|
const LayerMap &
|
||||||
MAGReader::read (db::Layout &layout, const db::LoadLayoutOptions &options)
|
MAGReader::read (db::Layout &layout, const db::LoadLayoutOptions &options)
|
||||||
{
|
{
|
||||||
prepare_layers ();
|
prepare_layers (layout);
|
||||||
|
|
||||||
mp_klayout_tech = 0;
|
mp_klayout_tech = layout.technology ();
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
const db::MAGReaderOptions &specific_options = options.get_options<db::MAGReaderOptions> ();
|
const db::MAGReaderOptions &specific_options = options.get_options<db::MAGReaderOptions> ();
|
||||||
m_lambda = specific_options.lambda;
|
m_lambda = specific_options.lambda;
|
||||||
|
|
@ -87,9 +83,7 @@ MAGReader::read (db::Layout &layout, const db::LoadLayoutOptions &options)
|
||||||
m_merge = specific_options.merge;
|
m_merge = specific_options.merge;
|
||||||
mp_current_stream = 0;
|
mp_current_stream = 0;
|
||||||
|
|
||||||
db::LayerMap lm = specific_options.layer_map;
|
set_layer_map (specific_options.layer_map);
|
||||||
lm.prepare (layout);
|
|
||||||
set_layer_map (lm);
|
|
||||||
set_create_layers (specific_options.create_other_layers);
|
set_create_layers (specific_options.create_other_layers);
|
||||||
set_keep_layer_names (specific_options.keep_layer_names);
|
set_keep_layer_names (specific_options.keep_layer_names);
|
||||||
|
|
||||||
|
|
@ -110,6 +104,8 @@ MAGReader::read (db::Layout &layout, const db::LoadLayoutOptions &options)
|
||||||
m_dbu_trans_inv = db::CplxTrans (m_dbu).inverted ();
|
m_dbu_trans_inv = db::CplxTrans (m_dbu).inverted ();
|
||||||
m_tech.clear ();
|
m_tech.clear ();
|
||||||
|
|
||||||
|
prepare_layers (layout);
|
||||||
|
|
||||||
{
|
{
|
||||||
tl::SelfTimer timer (tl::verbosity () >= 11, "Reading MAGIC file tree");
|
tl::SelfTimer timer (tl::verbosity () >= 11, "Reading MAGIC file tree");
|
||||||
|
|
||||||
|
|
@ -129,7 +125,7 @@ MAGReader::read (db::Layout &layout, const db::LoadLayoutOptions &options)
|
||||||
}
|
}
|
||||||
|
|
||||||
finish_layers (layout);
|
finish_layers (layout);
|
||||||
return layer_map ();
|
return layer_map_out ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
||||||
|
|
@ -145,7 +145,7 @@ private:
|
||||||
std::map<std::string, std::string> m_use_lib_paths;
|
std::map<std::string, std::string> m_use_lib_paths;
|
||||||
db::VCplxTrans m_dbu_trans_inv;
|
db::VCplxTrans m_dbu_trans_inv;
|
||||||
std::string m_tech;
|
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 (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);
|
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;
|
std::string tech = m_options.tech;
|
||||||
if (tech.empty ()) {
|
if (tech.empty ()) {
|
||||||
tech = layout.meta_info_value ("technology");
|
tech = layout.technology_name ();
|
||||||
}
|
}
|
||||||
if (! tech.empty ()) {
|
if (! tech.empty ()) {
|
||||||
os << "tech " << make_string (tl::to_lower_case (tech)) << "\n";
|
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;
|
std::string tech = m_options.tech;
|
||||||
if (tech.empty ()) {
|
if (tech.empty ()) {
|
||||||
tech = layout.meta_info_value ("technology");
|
tech = layout.technology_name ();
|
||||||
}
|
}
|
||||||
if (! tech.empty ()) {
|
if (! tech.empty ()) {
|
||||||
os << "tech " << make_string (tl::to_lower_case (tech)) << "\n";
|
os << "tech " << make_string (tl::to_lower_case (tech)) << "\n";
|
||||||
|
|
|
||||||
|
|
@ -38,35 +38,6 @@ namespace db
|
||||||
|
|
||||||
// ---------------------------------------------------------------
|
// ---------------------------------------------------------------
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief A utility class that maps the layers for the proxy cell recovery
|
|
||||||
*/
|
|
||||||
class OASISReaderLayerMapping
|
|
||||||
: public db::ImportLayerMapping
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
OASISReaderLayerMapping (db::OASISReader *reader, db::Layout *layout, bool create)
|
|
||||||
: mp_reader (reader), mp_layout (layout), m_create (create)
|
|
||||||
{
|
|
||||||
// .. nothing yet ..
|
|
||||||
}
|
|
||||||
|
|
||||||
std::pair<bool, unsigned int> map_layer (const db::LayerProperties &lprops)
|
|
||||||
{
|
|
||||||
// named layers that are imported from a library are ignored
|
|
||||||
if (lprops.is_named ()) {
|
|
||||||
return std::make_pair (false, 0);
|
|
||||||
} else {
|
|
||||||
return mp_reader->open_dl (*mp_layout, LDPair (lprops.layer, lprops.datatype), m_create);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
db::OASISReader *mp_reader;
|
|
||||||
db::Layout *mp_layout;
|
|
||||||
bool m_create;
|
|
||||||
};
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------
|
// ---------------------------------------------------------------
|
||||||
// OASISReader
|
// OASISReader
|
||||||
|
|
||||||
|
|
@ -101,7 +72,6 @@ OASISReader::OASISReader (tl::InputStream &s)
|
||||||
mm_last_property_name (this, "last-property-name"),
|
mm_last_property_name (this, "last-property-name"),
|
||||||
mm_last_property_is_sprop (this, "last-property-is-stdprop"),
|
mm_last_property_is_sprop (this, "last-property-is-stdprop"),
|
||||||
mm_last_value_list(this, "last-value-list"),
|
mm_last_value_list(this, "last-value-list"),
|
||||||
m_create_layers (false),
|
|
||||||
m_read_texts (true),
|
m_read_texts (true),
|
||||||
m_read_properties (true),
|
m_read_properties (true),
|
||||||
m_read_all_properties (false),
|
m_read_all_properties (false),
|
||||||
|
|
@ -129,40 +99,17 @@ OASISReader::~OASISReader ()
|
||||||
// .. nothing yet ..
|
// .. nothing yet ..
|
||||||
}
|
}
|
||||||
|
|
||||||
const LayerMap &
|
void
|
||||||
OASISReader::read (db::Layout &layout, const db::LoadLayoutOptions &options)
|
OASISReader::init (const db::LoadLayoutOptions &options)
|
||||||
{
|
{
|
||||||
db::OASISReaderOptions oasis_options = options.get_options<db::OASISReaderOptions> ();
|
CommonReader::init (options);
|
||||||
db::CommonReaderOptions common_options = options.get_options<db::CommonReaderOptions> ();
|
|
||||||
|
|
||||||
m_layer_map = common_options.layer_map;
|
m_read_texts = common_options ().enable_text_objects;
|
||||||
m_layer_map.prepare (layout);
|
m_read_properties = common_options ().enable_properties;
|
||||||
m_layers_created.clear ();
|
|
||||||
m_read_texts = common_options.enable_text_objects;
|
db::OASISReaderOptions oasis_options = options.get_options<db::OASISReaderOptions> ();
|
||||||
m_read_properties = common_options.enable_properties;
|
|
||||||
m_create_layers = common_options.create_other_layers;
|
|
||||||
m_read_all_properties = oasis_options.read_all_properties;
|
m_read_all_properties = oasis_options.read_all_properties;
|
||||||
m_expect_strict_mode = oasis_options.expect_strict_mode;
|
m_expect_strict_mode = oasis_options.expect_strict_mode;
|
||||||
|
|
||||||
set_cell_conflict_resolution (common_options.cell_conflict_resolution);
|
|
||||||
|
|
||||||
layout.start_changes ();
|
|
||||||
try {
|
|
||||||
do_read (layout);
|
|
||||||
finish (layout);
|
|
||||||
layout.end_changes ();
|
|
||||||
} catch (...) {
|
|
||||||
layout.end_changes ();
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
|
|
||||||
return m_layer_map;
|
|
||||||
}
|
|
||||||
|
|
||||||
const LayerMap &
|
|
||||||
OASISReader::read (db::Layout &layout)
|
|
||||||
{
|
|
||||||
return read (layout, db::LoadLayoutOptions ());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline long long
|
inline long long
|
||||||
|
|
@ -554,44 +501,6 @@ OASISReader::warn (const std::string &msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair <bool, unsigned int>
|
|
||||||
OASISReader::open_dl (db::Layout &layout, const LDPair &dl, bool create)
|
|
||||||
{
|
|
||||||
std::pair<bool, unsigned int> ll = m_layer_map.logical (dl, layout);
|
|
||||||
if (ll.first) {
|
|
||||||
|
|
||||||
return ll;
|
|
||||||
|
|
||||||
} else if (! create) {
|
|
||||||
|
|
||||||
return ll;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
// and create the layer
|
|
||||||
db::LayerProperties lp;
|
|
||||||
lp.layer = dl.layer;
|
|
||||||
lp.datatype = dl.datatype;
|
|
||||||
|
|
||||||
// resolve OASIS name if possible
|
|
||||||
const tl::interval_map <db::ld_type, std::string> *names_dmap = m_layernames.mapped (dl.layer);
|
|
||||||
if (names_dmap != 0) {
|
|
||||||
const std::string *name = names_dmap->mapped (dl.datatype);
|
|
||||||
if (name != 0) {
|
|
||||||
lp.name = *name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int ll = layout.insert_layer (lp);
|
|
||||||
m_layer_map.map (dl, ll, lp);
|
|
||||||
|
|
||||||
m_layers_created.insert (ll);
|
|
||||||
|
|
||||||
return std::make_pair (true, ll);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief A helper class to join two datatype layer name map members
|
* @brief A helper class to join two datatype layer name map members
|
||||||
*/
|
*/
|
||||||
|
|
@ -599,12 +508,7 @@ struct LNameJoinOp1
|
||||||
{
|
{
|
||||||
void operator() (std::string &a, const std::string &b)
|
void operator() (std::string &a, const std::string &b)
|
||||||
{
|
{
|
||||||
if (a != b) {
|
join_layer_names (a, b);
|
||||||
if (! a.empty ()) {
|
|
||||||
a += ";";
|
|
||||||
}
|
|
||||||
a += b;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -765,7 +669,6 @@ OASISReader::do_read (db::Layout &layout)
|
||||||
m_textstrings.clear ();
|
m_textstrings.clear ();
|
||||||
m_propstrings.clear ();
|
m_propstrings.clear ();
|
||||||
m_propnames.clear ();
|
m_propnames.clear ();
|
||||||
m_layernames.clear ();
|
|
||||||
|
|
||||||
m_instances.clear ();
|
m_instances.clear ();
|
||||||
m_instances_with_props.clear ();
|
m_instances_with_props.clear ();
|
||||||
|
|
@ -1077,21 +980,8 @@ OASISReader::do_read (db::Layout &layout)
|
||||||
LNameJoinOp1 op1;
|
LNameJoinOp1 op1;
|
||||||
dt_map.add (dt1, dt2 + 1, name, op1);
|
dt_map.add (dt1, dt2 + 1, name, op1);
|
||||||
LNameJoinOp2 op2;
|
LNameJoinOp2 op2;
|
||||||
m_layernames.add (l1, l2 + 1, dt_map, op2);
|
layer_names ().add (l1, l2 + 1, dt_map, op2);
|
||||||
|
|
||||||
// rename layers created before if required
|
|
||||||
for (std::set<unsigned int>::const_iterator i = m_layers_created.begin (); i != m_layers_created.end (); ++i) {
|
|
||||||
const db::LayerProperties &lp = layout.get_properties (*i);
|
|
||||||
if (lp.layer >= l1 && lp.layer <= l2 && lp.datatype >= dt1 && lp.datatype <= dt2 && lp.name != name) {
|
|
||||||
// need to rename: add a new madding to m_layer_map and adjust the layout's layer properties
|
|
||||||
db::LayerProperties lpp = lp;
|
|
||||||
LNameJoinOp1 nj;
|
|
||||||
nj (lpp.name, name);
|
|
||||||
layout.set_properties (*i, lpp);
|
|
||||||
m_layer_map.map (LDPair (lp.layer, lp.datatype), *i, lpp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
reset_modal_variables ();
|
reset_modal_variables ();
|
||||||
|
|
||||||
// ignore properties attached to this name item
|
// ignore properties attached to this name item
|
||||||
|
|
@ -2038,7 +1928,7 @@ OASISReader::do_read_text (bool xy_absolute,
|
||||||
|
|
||||||
std::pair<bool, unsigned int> ll (false, 0);
|
std::pair<bool, unsigned int> ll (false, 0);
|
||||||
if (m_read_texts) {
|
if (m_read_texts) {
|
||||||
ll = open_dl (layout, LDPair (mm_textlayer.get (), mm_texttype.get ()), m_create_layers);
|
ll = open_dl (layout, LDPair (mm_textlayer.get (), mm_texttype.get ()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((m & 0x4) && read_repetition ()) {
|
if ((m & 0x4) && read_repetition ()) {
|
||||||
|
|
@ -2180,7 +2070,7 @@ OASISReader::do_read_rectangle (bool xy_absolute,
|
||||||
db::Box box (db::Point (mm_geometry_x.get (), mm_geometry_y.get ()),
|
db::Box box (db::Point (mm_geometry_x.get (), mm_geometry_y.get ()),
|
||||||
db::Point (mm_geometry_x.get () + mm_geometry_w.get (), mm_geometry_y.get () + mm_geometry_h.get ()));
|
db::Point (mm_geometry_x.get () + mm_geometry_w.get (), mm_geometry_y.get () + mm_geometry_h.get ()));
|
||||||
|
|
||||||
std::pair<bool, unsigned int> ll = open_dl (layout, LDPair (mm_layer.get (), mm_datatype.get ()), m_create_layers);
|
std::pair<bool, unsigned int> ll = open_dl (layout, LDPair (mm_layer.get (), mm_datatype.get ()));
|
||||||
|
|
||||||
if ((m & 0x4) && read_repetition ()) {
|
if ((m & 0x4) && read_repetition ()) {
|
||||||
|
|
||||||
|
|
@ -2294,7 +2184,7 @@ OASISReader::do_read_polygon (bool xy_absolute, db::cell_index_type cell_index,
|
||||||
|
|
||||||
db::Vector pos (mm_geometry_x.get (), mm_geometry_y.get ());
|
db::Vector pos (mm_geometry_x.get (), mm_geometry_y.get ());
|
||||||
|
|
||||||
std::pair<bool, unsigned int> ll = open_dl (layout, LDPair (mm_layer.get (), mm_datatype.get ()), m_create_layers);
|
std::pair<bool, unsigned int> ll = open_dl (layout, LDPair (mm_layer.get (), mm_datatype.get ()));
|
||||||
|
|
||||||
if ((m & 0x4) && read_repetition ()) {
|
if ((m & 0x4) && read_repetition ()) {
|
||||||
|
|
||||||
|
|
@ -2461,7 +2351,7 @@ OASISReader::do_read_path (bool xy_absolute, db::cell_index_type cell_index, db:
|
||||||
|
|
||||||
db::Vector pos (mm_geometry_x.get (), mm_geometry_y.get ());
|
db::Vector pos (mm_geometry_x.get (), mm_geometry_y.get ());
|
||||||
|
|
||||||
std::pair<bool, unsigned int> ll = open_dl (layout, LDPair (mm_layer.get (), mm_datatype.get ()), m_create_layers);
|
std::pair<bool, unsigned int> ll = open_dl (layout, LDPair (mm_layer.get (), mm_datatype.get ()));
|
||||||
|
|
||||||
if ((m & 0x4) && read_repetition ()) {
|
if ((m & 0x4) && read_repetition ()) {
|
||||||
|
|
||||||
|
|
@ -2620,7 +2510,7 @@ OASISReader::do_read_trapezoid (unsigned char r, bool xy_absolute,db::cell_index
|
||||||
|
|
||||||
db::Vector pos (mm_geometry_x.get (), mm_geometry_y.get ());
|
db::Vector pos (mm_geometry_x.get (), mm_geometry_y.get ());
|
||||||
|
|
||||||
std::pair<bool, unsigned int> ll = open_dl (layout, LDPair (mm_layer.get (), mm_datatype.get ()), m_create_layers);
|
std::pair<bool, unsigned int> ll = open_dl (layout, LDPair (mm_layer.get (), mm_datatype.get ()));
|
||||||
|
|
||||||
db::Point pts [4];
|
db::Point pts [4];
|
||||||
|
|
||||||
|
|
@ -2775,7 +2665,7 @@ OASISReader::do_read_ctrapezoid (bool xy_absolute,db::cell_index_type cell_index
|
||||||
|
|
||||||
db::Vector pos (mm_geometry_x.get (), mm_geometry_y.get ());
|
db::Vector pos (mm_geometry_x.get (), mm_geometry_y.get ());
|
||||||
|
|
||||||
std::pair<bool, unsigned int> ll = open_dl (layout, LDPair (mm_layer.get (), mm_datatype.get ()), m_create_layers);
|
std::pair<bool, unsigned int> ll = open_dl (layout, LDPair (mm_layer.get (), mm_datatype.get ()));
|
||||||
|
|
||||||
db::Point pts [4];
|
db::Point pts [4];
|
||||||
|
|
||||||
|
|
@ -3126,7 +3016,7 @@ OASISReader::do_read_circle (bool xy_absolute, db::cell_index_type cell_index, d
|
||||||
|
|
||||||
db::Vector pos (mm_geometry_x.get (), mm_geometry_y.get ());
|
db::Vector pos (mm_geometry_x.get (), mm_geometry_y.get ());
|
||||||
|
|
||||||
std::pair<bool, unsigned int> ll = open_dl (layout, LDPair (mm_layer.get (), mm_datatype.get ()), m_create_layers);
|
std::pair<bool, unsigned int> ll = open_dl (layout, LDPair (mm_layer.get (), mm_datatype.get ()));
|
||||||
|
|
||||||
// ignore this circle if the radius is zero
|
// ignore this circle if the radius is zero
|
||||||
if (mm_circle_radius.get () <= 0) {
|
if (mm_circle_radius.get () <= 0) {
|
||||||
|
|
@ -3444,7 +3334,7 @@ OASISReader::do_read_cell (db::cell_index_type cell_index, db::Layout &layout)
|
||||||
|
|
||||||
// Restore proxy cell (link to PCell or Library)
|
// Restore proxy cell (link to PCell or Library)
|
||||||
if (has_context) {
|
if (has_context) {
|
||||||
OASISReaderLayerMapping layer_mapping (this, &layout, m_create_layers);
|
CommonReaderLayerMapping layer_mapping (this, &layout);
|
||||||
layout.recover_proxy_as (cell_index, context_strings.begin (), context_strings.end (), &layer_mapping);
|
layout.recover_proxy_as (cell_index, context_strings.begin (), context_strings.end (), &layer_mapping);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -81,39 +81,6 @@ public:
|
||||||
*/
|
*/
|
||||||
~OASISReader ();
|
~OASISReader ();
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The basic read method
|
|
||||||
*
|
|
||||||
* This method will read the stream data and translate this to
|
|
||||||
* insert calls into the layout object. This will not do much
|
|
||||||
* on the layout object beside inserting the objects.
|
|
||||||
* A set of options can be specified with the LoadLayoutOptions
|
|
||||||
* object.
|
|
||||||
* The returned map will contain all layers, the passed
|
|
||||||
* ones and the newly created ones.
|
|
||||||
*
|
|
||||||
* @param layout The layout object to write to
|
|
||||||
* @param map The LayerMap object
|
|
||||||
* @param create true, if new layers should be created
|
|
||||||
* @return The LayerMap object that tells where which layer was loaded
|
|
||||||
*/
|
|
||||||
virtual const LayerMap &read (db::Layout &layout, const LoadLayoutOptions &options);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The basic read method (without mapping)
|
|
||||||
*
|
|
||||||
* This method will read the stream data and translate this to
|
|
||||||
* insert calls into the layout object. This will not do much
|
|
||||||
* on the layout object beside inserting the objects.
|
|
||||||
* This version will read all input layers and return a map
|
|
||||||
* which tells which OASIS layer has been read into which logical
|
|
||||||
* layer.
|
|
||||||
*
|
|
||||||
* @param layout The layout object to write to
|
|
||||||
* @return The LayerMap object
|
|
||||||
*/
|
|
||||||
virtual const LayerMap &read (db::Layout &layout);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Format
|
* @brief Format
|
||||||
*/
|
*/
|
||||||
|
|
@ -136,6 +103,8 @@ protected:
|
||||||
|
|
||||||
virtual void common_reader_error (const std::string &msg) { error (msg); }
|
virtual void common_reader_error (const std::string &msg) { error (msg); }
|
||||||
virtual void common_reader_warn (const std::string &msg) { warn (msg); }
|
virtual void common_reader_warn (const std::string &msg) { warn (msg); }
|
||||||
|
virtual void init (const LoadLayoutOptions &options);
|
||||||
|
virtual void do_read (db::Layout &layout);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class OASISReaderLayerMapping;
|
friend class OASISReaderLayerMapping;
|
||||||
|
|
@ -153,8 +122,6 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
tl::InputStream &m_stream;
|
tl::InputStream &m_stream;
|
||||||
LayerMap m_layer_map;
|
|
||||||
std::set<unsigned int> m_layers_created;
|
|
||||||
tl::AbsoluteProgress m_progress;
|
tl::AbsoluteProgress m_progress;
|
||||||
std::string m_cellname;
|
std::string m_cellname;
|
||||||
double m_dbu;
|
double m_dbu;
|
||||||
|
|
@ -204,12 +171,10 @@ private:
|
||||||
std::map <unsigned long, const db::StringRef *> m_text_forward_references;
|
std::map <unsigned long, const db::StringRef *> m_text_forward_references;
|
||||||
std::map <unsigned long, std::string> m_propstrings;
|
std::map <unsigned long, std::string> m_propstrings;
|
||||||
std::map <unsigned long, std::string> m_propnames;
|
std::map <unsigned long, std::string> m_propnames;
|
||||||
tl::interval_map <db::ld_type, tl::interval_map <db::ld_type, std::string> > m_layernames;
|
|
||||||
|
|
||||||
tl::vector<db::CellInstArray> m_instances;
|
tl::vector<db::CellInstArray> m_instances;
|
||||||
tl::vector<db::CellInstArrayWithProperties> m_instances_with_props;
|
tl::vector<db::CellInstArrayWithProperties> m_instances_with_props;
|
||||||
|
|
||||||
bool m_create_layers;
|
|
||||||
bool m_read_texts;
|
bool m_read_texts;
|
||||||
bool m_read_properties;
|
bool m_read_properties;
|
||||||
bool m_read_all_properties;
|
bool m_read_all_properties;
|
||||||
|
|
@ -219,7 +184,6 @@ private:
|
||||||
db::property_names_id_type m_s_gds_property_name_id;
|
db::property_names_id_type m_s_gds_property_name_id;
|
||||||
db::property_names_id_type m_klayout_context_property_name_id;
|
db::property_names_id_type m_klayout_context_property_name_id;
|
||||||
|
|
||||||
void do_read (db::Layout &layout);
|
|
||||||
void do_read_cell (db::cell_index_type cell_index, db::Layout &layout);
|
void do_read_cell (db::cell_index_type cell_index, db::Layout &layout);
|
||||||
|
|
||||||
void do_read_placement (unsigned char r,
|
void do_read_placement (unsigned char r,
|
||||||
|
|
@ -310,8 +274,6 @@ private:
|
||||||
db::Coord get_coord (long grid = 1);
|
db::Coord get_coord (long grid = 1);
|
||||||
db::Coord get_ucoord (unsigned long grid = 1);
|
db::Coord get_ucoord (unsigned long grid = 1);
|
||||||
distance_type get_ucoord_as_distance (unsigned long grid = 1);
|
distance_type get_ucoord_as_distance (unsigned long grid = 1);
|
||||||
|
|
||||||
std::pair <bool, unsigned int> open_dl (db::Layout &layout, const LDPair &dl, bool create);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,28 @@
|
||||||
|
LAYER M1
|
||||||
|
TYPE ROUTING ;
|
||||||
|
END M1
|
||||||
|
LAYER VIA1
|
||||||
|
TYPE CUT ;
|
||||||
|
END VIA1
|
||||||
|
|
||||||
|
MACRO dense
|
||||||
|
CLASS CORE ;
|
||||||
|
ORIGIN 0.0 0.0 ;
|
||||||
|
FOREIGN dense ;
|
||||||
|
SIZE 0.7 BY 0.9 ;
|
||||||
|
OBS
|
||||||
|
LAYER M1 DESIGNRULEWIDTH 0.05 ;
|
||||||
|
RECT 0.04 0.095 0.66 0.685 ;
|
||||||
|
LAYER VIA1 ;
|
||||||
|
RECT 0.285 0.31 0.415 0.36 ;
|
||||||
|
RECT 0.285 0.18 0.415 0.23 ;
|
||||||
|
END
|
||||||
|
DENSITY
|
||||||
|
LAYER M1 ;
|
||||||
|
RECT 0.04 0.09 0.66 0.685 100.0 ;
|
||||||
|
LAYER VIA1 ;
|
||||||
|
RECT 0 0 100 100 45.5 ; #rect from (0,0) to (100,100), density of 45.5%
|
||||||
|
RECT 100 0 200 100 42.2 ; #rect from (100,0) to (200, 100), density of 42.2%
|
||||||
|
END
|
||||||
|
END dense
|
||||||
|
END LIBRARY
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
# some variations of map file entries
|
||||||
|
DIEAREA ALL 1 0
|
||||||
|
COMP ALL 2 0
|
||||||
|
M1 PIN 3,4 0
|
||||||
|
M1 LEFPIN,LEFOBS,PIN,NET,SPNET,VIA 1 5
|
||||||
|
DOES NOT MEAN ANYTHING
|
||||||
|
M1 NET,SPNET,PIN,VIA:MASK:1 6 0
|
||||||
|
M1 NET:MASK:1 7 0
|
||||||
|
M1 TEXT 8 0
|
||||||
|
M1 FILLOPC 9 0
|
||||||
|
M1 FILLOPC:MASK:1 10 0
|
||||||
|
M1 FILLOPC:MASK:2 11 0
|
||||||
|
M1 BLOCKAGEFILL 12 0
|
||||||
|
M1 BLOCKAGE 13 0
|
||||||
|
M1 FILL 14 0
|
||||||
|
M1 VIAFILL,FILL 15 0
|
||||||
|
M1 NET,SPNET,CUSTOM 16 0
|
||||||
|
M1 VIAFILL:FLOATING,FILL:FLOATING 17 0
|
||||||
|
M1 NET:VOLTAGE:0.8 18 0
|
||||||
|
M1 VIAFILL 19 0
|
||||||
|
M1 VIA:SIZE:0.05x0.05 20 0
|
||||||
|
M1 VIA:SIZE:3x3 21 0
|
||||||
|
M1 ALL 22 2
|
||||||
|
NAME DIEAREA 23 0
|
||||||
|
NAME ALL 24 0
|
||||||
|
NAME COMP 25 0
|
||||||
|
NAME M1/PIN 26 0
|
||||||
|
NAME M1/NET 27 0
|
||||||
|
NAME M1/SPNET 28 1
|
||||||
|
NAME M1_TEXT 29 0
|
||||||
Binary file not shown.
|
|
@ -0,0 +1,28 @@
|
||||||
|
|
||||||
|
VERSION 5.8 ;
|
||||||
|
DIVIDERCHAR "/" ;
|
||||||
|
BUSBITCHARS "[]" ;
|
||||||
|
DESIGN chip_top ;
|
||||||
|
UNITS DISTANCE MICRONS 1000 ;
|
||||||
|
DIEAREA ( 30000 3000 ) ( 10000000 4000 ) ;
|
||||||
|
VIAS 1 ;
|
||||||
|
- VIA1_dummy
|
||||||
|
+ RECT M1 ( -200 -140 ) ( 200 140 )
|
||||||
|
+ RECT VIA1 ( -100 -100 ) ( 100 100 )
|
||||||
|
+ RECT M2 ( -300 -120 ) ( 300 120 ) ;
|
||||||
|
END VIAS
|
||||||
|
SPECIALNETS 1 ;
|
||||||
|
- dummy
|
||||||
|
+ ROUTED M1 150 + SHAPE IOWIRE ( 40000 3600 ) VIA1_dummy DO 16000 BY 1 STEP 700 0
|
||||||
|
;
|
||||||
|
END SPECIALNETS
|
||||||
|
SCANCHAINS 77 ;
|
||||||
|
- chain1_clock1
|
||||||
|
+ PARTITION clock1
|
||||||
|
+ START block1/bsr_reg_0 Q
|
||||||
|
+ FLOATING
|
||||||
|
block1/pgm_cgm_en_reg_reg ( IN SD ) ( OUT QZ )
|
||||||
|
block1/start_reset_dd_reg ( IN SD ) ( OUT QZ )
|
||||||
|
+ STOP block1/start_reset_d_reg SD ;
|
||||||
|
END SCANCHAINS
|
||||||
|
END DESIGN
|
||||||
|
|
@ -30,7 +30,11 @@ class DBLayout_TestClass < TestBase
|
||||||
lmap = RBA::LayerMap::new
|
lmap = RBA::LayerMap::new
|
||||||
|
|
||||||
lmap.map( "1/0", 0 )
|
lmap.map( "1/0", 0 )
|
||||||
|
assert_equal(lmap.is_mapped(RBA::LayerInfo::new(1, 0)), true)
|
||||||
|
assert_equal(lmap.is_mapped(RBA::LayerInfo::new(1, 1)), false)
|
||||||
|
assert_equal(lmap.is_mapped(RBA::LayerInfo::new(2, 2)), false)
|
||||||
lmap.map( "2/2", 0 )
|
lmap.map( "2/2", 0 )
|
||||||
|
assert_equal(lmap.is_mapped(RBA::LayerInfo::new(2, 2)), true)
|
||||||
lmap.map( "10/2", 0 )
|
lmap.map( "10/2", 0 )
|
||||||
assert_equal( lmap.mapping_str(0), "1/0;2/2;10/2" )
|
assert_equal( lmap.mapping_str(0), "1/0;2/2;10/2" )
|
||||||
|
|
||||||
|
|
@ -39,7 +43,7 @@ class DBLayout_TestClass < TestBase
|
||||||
lmap.map( "4/2", 1 )
|
lmap.map( "4/2", 1 )
|
||||||
lmap.map( "1/2", 1 )
|
lmap.map( "1/2", 1 )
|
||||||
lmap.map( "0/0", 1 )
|
lmap.map( "0/0", 1 )
|
||||||
assert_equal( lmap.mapping_str(1), "0/0;1/2;2-4/2" ) # could be "0/0;1-4/2" as well ...
|
assert_equal( lmap.mapping_str(1), "0/0;1-4/2" ) # could be "0/0;1-4/2" as well ...
|
||||||
|
|
||||||
lmap.map( RBA::LayerInfo::new(2, 2), RBA::LayerInfo::new(4, 4), 2 )
|
lmap.map( RBA::LayerInfo::new(2, 2), RBA::LayerInfo::new(4, 4), 2 )
|
||||||
lmap.map( RBA::LayerInfo::new(0, 1), 2 )
|
lmap.map( RBA::LayerInfo::new(0, 1), 2 )
|
||||||
|
|
@ -85,6 +89,55 @@ class DBLayout_TestClass < TestBase
|
||||||
assert_equal( lmap.mapping_str(0), "2/2 : 4/4" )
|
assert_equal( lmap.mapping_str(0), "2/2 : 4/4" )
|
||||||
assert_equal( lmap.mapping(0).to_s, "4/4" )
|
assert_equal( lmap.mapping(0).to_s, "4/4" )
|
||||||
assert_equal( lmap.mapping(2).to_s, "5/5" )
|
assert_equal( lmap.mapping(2).to_s, "5/5" )
|
||||||
|
|
||||||
|
lmap = RBA::LayerMap::new
|
||||||
|
|
||||||
|
lmap.map("*/*", 0)
|
||||||
|
lmap.unmap(RBA::LayerInfo::new(5, 10))
|
||||||
|
assert_equal(lmap.mapping_str(0), "0-4/*;5/0-9,11-*;6-*/*")
|
||||||
|
|
||||||
|
lmap.clear
|
||||||
|
lmap.map("*/*", 0)
|
||||||
|
lmap.unmap(RBA::LayerInfo::new(5, 10), RBA::LayerInfo::new(16, 21))
|
||||||
|
assert_equal(lmap.mapping_str(0), "0-4/*;5-16/0-9,22-*;17-*/*")
|
||||||
|
|
||||||
|
lmap.clear
|
||||||
|
lmap.map("*/*", 0)
|
||||||
|
lmap.unmap("5-16/10-21")
|
||||||
|
assert_equal(lmap.mapping_str(0), "0-4/*;5-16/0-9,22-*;17-*/*")
|
||||||
|
|
||||||
|
lmap.clear
|
||||||
|
lmap.map("*/*", 0)
|
||||||
|
lmap.mmap(RBA::LayerInfo::new(5, 10), 1)
|
||||||
|
assert_equal(lmap.mapping_str(0), "+*/*")
|
||||||
|
assert_equal(lmap.mapping_str(1), "+5/10")
|
||||||
|
|
||||||
|
lmap.clear
|
||||||
|
lmap.map("*/*", 0)
|
||||||
|
lmap.mmap(RBA::LayerInfo::new(5, 10), 1, RBA::LayerInfo::new(100, 0))
|
||||||
|
assert_equal(lmap.mapping_str(0), "+*/*")
|
||||||
|
assert_equal(lmap.mapping_str(1), "+5/10 : 100/0")
|
||||||
|
|
||||||
|
lmap.clear
|
||||||
|
lmap.map("*/*", 0)
|
||||||
|
lmap.mmap(RBA::LayerInfo::new(5, 10), RBA::LayerInfo::new(16, 21), 1)
|
||||||
|
assert_equal(lmap.mapping_str(0), "+*/*")
|
||||||
|
assert_equal(lmap.mapping_str(1), "+5-16/10-21")
|
||||||
|
|
||||||
|
lmap.clear
|
||||||
|
lmap.map("*/*", 0)
|
||||||
|
lmap.mmap(RBA::LayerInfo::new(5, 10), RBA::LayerInfo::new(16, 21), 1, RBA::LayerInfo::new(100, 0))
|
||||||
|
assert_equal(lmap.mapping_str(0), "+*/*")
|
||||||
|
assert_equal(lmap.mapping_str(1), "+5-16/10-21 : 100/0")
|
||||||
|
|
||||||
|
lmap.clear
|
||||||
|
lmap.map("*/*", 0)
|
||||||
|
lmap.mmap("5-16/10-21", 1)
|
||||||
|
assert_equal(lmap.mapping_str(0), "+*/*")
|
||||||
|
assert_equal(lmap.mapping_str(1), "+5-16/10-21")
|
||||||
|
|
||||||
|
assert_equal(lmap.logicals(RBA::LayerInfo::new(5, 10)), [ 0, 1 ])
|
||||||
|
assert_equal(lmap.logicals(RBA::LayerInfo::new(0, 10)), [ 0 ])
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue