Merge branch 'master' into complex_drc_ops

This commit is contained in:
Matthias Koefferlein 2020-12-20 23:50:54 +01:00
commit 45a8f7aa20
92 changed files with 4391 additions and 1538 deletions

View File

@ -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;

View File

@ -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);

View File

@ -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 \

128
src/db/db/dbColdProxy.cc Normal file
View File

@ -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 ();
}
}
}

111
src/db/db/dbColdProxy.h Normal file
View File

@ -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

View File

@ -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);
}
} }
// --------------------------------------------------------------- // ---------------------------------------------------------------

View File

@ -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;
}
}; };
} }

View File

@ -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);

View File

@ -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
{ {
@ -1801,7 +2064,36 @@ static const std::vector<tl::Variant> &gauge_parameters (const std::vector<tl::V
} }
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::replace_cell (cell_index_type target_cell_index, db::Cell *new_cell, bool retain_layout)
{
invalidate_hier ();
db::Cell *old_cell = m_cell_ptrs [target_cell_index];
if (old_cell) {
old_cell->unregister ();
if (retain_layout) {
new_cell->Cell::operator= (*old_cell);
}
}
if (manager () && manager ()->transacting ()) {
// note the "take" method - this takes out the cell but does not delete it (we need it inside undo)
m_cells.take (iterator (old_cell));
manager ()->queue (this, new NewRemoveCellOp (target_cell_index, cell_name (target_cell_index), true /*remove*/, old_cell));
} else {
m_cells.erase (iterator (old_cell));
}
m_cells.push_back_ptr (new_cell);
m_cell_ptrs [target_cell_index] = new_cell;
if (manager () && manager ()->transacting ()) {
manager ()->queue (this, new NewRemoveCellOp (target_cell_index, m_cell_names [target_cell_index], false /*new*/, 0));
}
}
void
Layout::get_pcell_variant_as (pcell_id_type pcell_id, const std::vector<tl::Variant> &p, cell_index_type target_cell_index, ImportLayerMapping *layer_mapping, 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
@ -2169,9 +2457,28 @@ 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,54 +2597,53 @@ 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)
{ {

View File

@ -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> &parameters, cell_index_type cell_index, ImportLayerMapping *layer_mapping = 0); void get_pcell_variant_as (pcell_id_type pcell_id, const std::vector<tl::Variant> &parameters, 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)
* *
* @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. * 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);
}; };
/** /**

View File

@ -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);
} }

View File

@ -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);
} }
} }

View File

@ -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 {

View File

@ -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;

View File

@ -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
* *

View File

@ -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 ());

View File

@ -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 ();
} }
} }

View File

@ -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) {

View File

@ -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);
}; };
} }

View File

@ -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:
/** /**

View File

@ -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

View File

@ -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
*/ */

View File

@ -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,6 +57,26 @@ struct LmapJoinOp2
} }
}; };
/// 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 /// Utility typedefs for the expression parser
typedef std::pair<ld_type, ld_type> ld_interval; typedef std::pair<ld_type, ld_type> ld_interval;
@ -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,6 +685,14 @@ 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 (...) {
@ -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 (";");
} }

View File

@ -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;
}; };
} }

View File

@ -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. "

View File

@ -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> &params) static db::Cell *create_cell4 (db::Layout *layout, const std::string &name, const std::string &libname, const std::map<std::string, tl::Variant> &params)
{ {
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"

View File

@ -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", &register_lib, gsi::arg ("name"), gsi::method_ext ("register", &register_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"

View File

@ -36,14 +36,20 @@ 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 std::set<unsigned int>
lm_logicals (const db::LayerMap *layer_map, const db::LayerProperties &lp)
{
return layer_map->logical (lp);
} }
static db::LayerProperties static db::LayerProperties
@ -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.

View File

@ -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");
}
}

View File

@ -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;
}
}

View File

@ -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 ());
}

View File

@ -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
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 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> &parameters) EditorOptionsInstPCellParam::update_pcell_parameters (const std::vector <tl::Variant> &parameters)
{ {
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);

View File

@ -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> &parameters); void update_pcell_parameters (const std::vector <tl::Variant> &parameters);
virtual void technology_changed (const std::string &);
}; };
} }

View File

@ -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);
} }

View File

@ -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 &parameters) PCellParametersPage::setup (lay::LayoutView *view, int cv_index, const db::PCellDeclaration *pcell_decl, const db::pcell_parameters_type &parameters)
{ {
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> &parameters) PCellParametersPage::set_parameters (const std::vector<tl::Variant> &parameters)
{ {
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]);
} }
} }
} }

View File

@ -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 &parameters); void setup (lay::LayoutView *view, int cv_index, const db::PCellDeclaration *pcell_decl, const db::pcell_parameters_type &parameters);
/** /**
* @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;

View File

@ -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);
} }

View File

@ -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) {

View File

@ -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 &);
}; };
} }

View File

@ -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

View File

@ -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>

View File

@ -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));
} }

View File

@ -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 ();
}; };

View File

@ -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;

View File

@ -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);

View File

@ -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);
} }

View File

@ -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>

View File

@ -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,10 +214,17 @@ 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
@ -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);
} }

View File

@ -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;
}; };

View File

@ -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)
{ {

View File

@ -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 ();
}; };
} }

View File

@ -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));
}
} }

View File

@ -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

View File

@ -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 ();

View File

@ -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 ();

View File

@ -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) {

View File

@ -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 ()) {

View File

@ -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 ();
}; };

View File

@ -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 &

View File

@ -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");

View File

@ -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) {

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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)")));

View File

@ -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);

View File

@ -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")));

View File

@ -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 ();

View File

@ -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");

View File

@ -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);
} }
} }

View File

@ -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;
} }

View File

@ -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);
} }

View File

@ -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;

View File

@ -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);

View File

@ -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"

View File

@ -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">

View File

@ -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);
} }

View File

@ -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

View File

@ -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);

View File

@ -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";

View File

@ -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,20 +980,7 @@ 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 ();
@ -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);
} }

View File

@ -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);
}; };
} }

BIN
testdata/gds/alm_au2.gds vendored Normal file

Binary file not shown.

BIN
testdata/gds/alm_au3.gds vendored Normal file

Binary file not shown.

BIN
testdata/lefdef/density/au.oas.gz vendored Normal file

Binary file not shown.

28
testdata/lefdef/density/in.lef vendored Normal file
View File

@ -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

30
testdata/lefdef/mapfile/all.map vendored Normal file
View File

@ -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

BIN
testdata/lefdef/multimap/au.oas.gz vendored Normal file

Binary file not shown.

28
testdata/lefdef/multimap/test.def vendored Normal file
View File

@ -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

View File

@ -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 )
@ -86,6 +90,55 @@ class DBLayout_TestClass < TestBase
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
def test_2 def test_2