WIP: First implementation. Needs testing.

This commit is contained in:
Matthias Koefferlein 2020-11-02 01:23:27 +01:00
parent 96123c3429
commit eb3600d620
12 changed files with 483 additions and 274 deletions

View File

@ -29,6 +29,279 @@
namespace db
{
// ---------------------------------------------------------------
// Common reader implementation
static const size_t null_id = std::numeric_limits<size_t>::max ();
CommonReader::CommonReader ()
: m_cc_resolution (AddToCell)
{
// .. nothing yet ..
}
db::cell_index_type
CommonReader::make_cell (db::Layout &layout, const std::string &cn)
{
tl_assert (! cn.empty ());
std::map<std::string, std::pair<size_t, db::cell_index_type> >::iterator iname = m_name_map.find (cn);
if (iname != m_name_map.end ()) {
db::Cell &cell = layout.cell (iname->second.second);
if (! cell.is_ghost_cell ()) {
common_reader_error (tl::sprintf (tl::to_string (tr ("A cell with name %s already exists")), cn));
}
cell.set_ghost_cell (false);
return cell.cell_index ();
} else {
db::cell_index_type ci = layout.add_cell ();
m_name_map [cn] = std::make_pair (null_id, ci);
return ci;
}
}
bool
CommonReader::has_cell (const std::string &cn) const
{
return m_name_map.find (cn) != m_name_map.end ();
}
std::pair<bool, db::cell_index_type>
CommonReader::cell_by_name (const std::string &cn) const
{
std::map<std::string, std::pair<size_t, db::cell_index_type> >::const_iterator iname = m_name_map.find (cn);
if (iname != m_name_map.end ()) {
return std::make_pair (true, iname->second.second);
} else {
return std::make_pair (false, size_t (0));
}
}
db::cell_index_type
CommonReader::make_cell (db::Layout &layout, size_t id)
{
tl_assert (id != null_id);
std::map<size_t, std::pair<std::string, db::cell_index_type> >::iterator iid = m_id_map.find (id);
if (iid != m_id_map.end ()) {
db::Cell &cell = layout.cell (iid->second.second);
if (! cell.is_ghost_cell ()) {
common_reader_error (tl::sprintf (tl::to_string (tr ("A cell with ID %ld already exists")), id));
}
cell.set_ghost_cell (false);
return cell.cell_index ();
} else {
db::cell_index_type ci = layout.add_cell ();
m_id_map [id] = std::make_pair (std::string (), ci);
return ci;
}
}
bool
CommonReader::has_cell (size_t id) const
{
return m_id_map.find (id) != m_id_map.end ();
}
std::pair<bool, db::cell_index_type>
CommonReader::cell_by_id (size_t id) const
{
std::map<size_t, std::pair<std::string, db::cell_index_type> >::const_iterator iid = m_id_map.find (id);
if (iid != m_id_map.end ()) {
return std::make_pair (true, iid->second.second);
} else {
return std::make_pair (false, size_t (0));
}
}
void
CommonReader::rename_cell (db::Layout &layout, size_t id, const std::string &cn)
{
std::map<size_t, std::pair<std::string, db::cell_index_type> >::iterator iid = m_id_map.find (id);
std::map<std::string, std::pair<size_t, db::cell_index_type> >::iterator iname = m_name_map.find (cn);
if (iid != m_id_map.end () && iname != m_name_map.end ()) {
if (iid->second.first != cn) {
common_reader_error (tl::sprintf (tl::to_string (tr ("Cell named %s with ID %ld was already given name %s")), cn, id, iid->second.first));
}
if (iname->second.second != iid->second.second) {
// Both cells already exist and are not identical: merge ID-declared cell into the name-declared one
layout.force_update ();
merge_cell (layout, iname->second.second, iid->second.second);
iid->second.second = iname->second.second;
}
} else if (iid != m_id_map.end ()) {
m_name_map [cn] = std::make_pair (id, iid->second.second);
} else if (iname != m_name_map.end ()) {
m_id_map [id] = std::make_pair (cn, iname->second.second);
} else {
db::cell_index_type ci = layout.add_cell ();
m_id_map [id] = std::make_pair (std::string (), ci);
m_name_map [cn] = std::make_pair (null_id, ci);
}
}
db::cell_index_type
CommonReader::cell_for_instance (db::Layout &layout, size_t id)
{
tl_assert (id != null_id);
std::map<size_t, std::pair<std::string, db::cell_index_type> >::iterator iid = m_id_map.find (id);
if (iid != m_id_map.end ()) {
return iid->second.second;
} else {
db::cell_index_type ci = layout.add_cell ();
layout.cell (ci).set_ghost_cell (true);
m_id_map [id] = std::make_pair (std::string (), ci);
return ci;
}
}
db::cell_index_type
CommonReader::cell_for_instance (db::Layout &layout, const std::string &cn)
{
tl_assert (! cn.empty ());
std::map<std::string, std::pair<size_t, db::cell_index_type> >::iterator iname = m_name_map.find (cn);
if (iname != m_name_map.end ()) {
return iname->second.second;
} else {
db::cell_index_type ci = layout.add_cell ();
layout.cell (ci).set_ghost_cell (true);
m_name_map [cn] = std::make_pair (null_id, ci);
return ci;
}
}
void
CommonReader::merge_cell (db::Layout &layout, db::cell_index_type target_cell_index, db::cell_index_type src_cell_index) const
{
const db::Cell &src_cell = layout.cell (src_cell_index);
db::Cell &target_cell = layout.cell (target_cell_index);
// copy over the instances
for (db::Cell::const_iterator i = src_cell.begin (); ! i.at_end (); ++i) {
target_cell.insert (*i);
}
// copy over the shapes
for (unsigned int l = 0; l < layout.layers (); ++l) {
if (layout.is_valid_layer (l) && ! src_cell.shapes (l).empty ()) {
target_cell.shapes (l).insert (src_cell.shapes (l));
}
}
// replace all instances of the new cell with the original one
std::vector<std::pair<db::cell_index_type, db::Instance> > parents;
for (db::Cell::parent_inst_iterator pi = src_cell.begin_parent_insts (); ! pi.at_end (); ++pi) {
parents.push_back (std::make_pair (pi->parent_cell_index (), pi->child_inst ()));
}
for (std::vector<std::pair<db::cell_index_type, db::Instance> >::const_iterator p = parents.begin (); p != parents.end (); ++p) {
db::CellInstArray ia = p->second.cell_inst ();
ia.object ().cell_index (target_cell.cell_index ());
layout.cell (p->first).replace (p->second, ia);
}
// finally delete the new cell
layout.delete_cell (src_cell.cell_index ());
}
void
CommonReader::finish (db::Layout &layout)
{
bool any_missing = false;
for (std::map<size_t, std::pair<std::string, db::cell_index_type> >::const_iterator i = m_id_map.begin (); i != m_id_map.end (); ++i) {
if (i->second.first.empty ()) {
common_reader_warn (tl::sprintf (tl::to_string (tr ("Cell name missing for ID %ld")), i->first));
any_missing = true;
}
}
if (any_missing) {
common_reader_error (tl::to_string (tr ("Some cell IDs don't have a name (see previous warnings)")));
}
for (std::map<std::string, std::pair<size_t, db::cell_index_type> >::const_iterator i = m_name_map.begin (); i != m_name_map.end (); ++i) {
if (layout.has_cell (i->first.c_str ())) {
db::cell_index_type ci_org = layout.cell_by_name (i->first.c_str ()).second;
db::cell_index_type ci_new = i->second.second;
if (m_cc_resolution == RenameCell || layout.cell (ci_org).is_proxy ()) {
// NOTE: we never reopen proxies (they are always local to their layout). Instead we
// always rename for proxies
layout.rename_cell (i->second.second, i->first.c_str ());
} else {
// we have a cell conflict
layout.force_update ();
if (m_cc_resolution == OverwriteCell && ! layout.cell (ci_new).is_ghost_cell ()) {
layout.prune_subcells (ci_org);
layout.cell (ci_org).clear_shapes ();
} else if (m_cc_resolution == SkipNewCell && ! layout.cell (ci_org).is_ghost_cell ()) {
layout.prune_subcells (ci_new);
layout.cell (ci_new).clear_shapes ();
}
merge_cell (layout, ci_org, ci_new);
}
} else {
layout.rename_cell (i->second.second, i->first.c_str ());
}
}
}
// ---------------------------------------------------------------
// Common format declaration

View File

@ -31,6 +31,117 @@
namespace db
{
/**
* @brief A common reader base for GDS2 and OASIS providing common services for both readers
*/
class DB_PUBLIC CommonReader
: public ReaderBase
{
public:
/**
* @brief The CellConflictResolution enum
*/
enum CellConflictResolution
{
AddToCell = 0,
OverwriteCell = 1,
SkipNewCell = 2,
RenameCell = 3
};
/**
* @brief Constructor
*/
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
*/
db::cell_index_type make_cell (db::Layout &layout, const std::string &cn);
/**
* @brief Returns true, if there is a cell with the given name already
*/
bool has_cell (const std::string &cn) const;
/**
* @brief Returns a pair with a bool (indicating whether the cell name is known) and the cell index for this name
*/
std::pair<bool, db::cell_index_type> cell_by_name (const std::string &name) const;
/**
* @brief Make a cell from an ID (OASIS)
*/
db::cell_index_type make_cell (db::Layout &layout, size_t id);
/**
* @brief Returns true, if there is a cell with the given ID alreay
*/
bool has_cell (size_t id) const;
/**
* @brief Returns a pair with a bool (indicating whether the cell ID is known) and the cell index for this ID
*/
std::pair<bool, db::cell_index_type> cell_by_id (size_t id) const;
/**
* @brief Registers a cell name for an ID
*/
void rename_cell (db::Layout &layout, size_t id, const std::string &cn);
/**
* @brief Returns a cell reference by ID
* If the cell does not exist, it's created. It is marked as ghost cell until
* "make_cell" is called.
*/
db::cell_index_type cell_for_instance (db::Layout &layout, size_t id);
/**
* @brief Returns a cell reference by name
* Same as the previous method, but acting on cell names.
*/
db::cell_index_type cell_for_instance (db::Layout &layout, const std::string &cn);
/**
* @brief Finishes the reading process
*
* This method will first check if all cells IDs got a name.
* After this, the cells are renamed and cell conflict resolution will happen in the
* specified way (cell_conflict_resolution attribute).
*/
void finish (db::Layout &layout);
protected:
virtual void common_reader_error (const std::string &msg) = 0;
virtual void common_reader_warn (const std::string &msg) = 0;
/**
* @brief Merge (and delete) the src_cell into target_cell
*/
void merge_cell (db::Layout &layout, db::cell_index_type target_cell_index, db::cell_index_type src_cell_index) const;
private:
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;
CellConflictResolution m_cc_resolution;
};
/**
* @brief Structure that holds the GDS2 and OASIS specific options for the reader
*/
@ -44,7 +155,8 @@ public:
CommonReaderOptions ()
: create_other_layers (true),
enable_text_objects (true),
enable_properties (true)
enable_properties (true),
cell_conflict_resolution (CommonReader::AddToCell)
{
// .. nothing yet ..
}
@ -83,6 +195,22 @@ public:
*/
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
*/

View File

@ -1065,8 +1065,7 @@ public:
* @brief Delete the subcells of the given cells which are not used otherwise
*
* All subcells referenced directy or indirectly but not used otherwise
* are deleted as well. This basically prunes the cell tree by this cell.
* All instances of this cell are deleted as well.
* are deleted as well.
* This method is more efficent than calling prune_subcells for single cells multiple times.
*
* @param from A begin iterator delivering the cell id's to delete
@ -1085,8 +1084,7 @@ public:
* @brief Delete the subcells of the given cells which are not used otherwise
*
* All subcells referenced directy or indirectly but not used otherwise
* are deleted as well. This basically prunes the cell tree by this cell.
* All instances of this cell are deleted as well.
* are deleted as well.
* This method is more efficent than calling prune_subcells for single cells multiple times.
*
* @param cells A set of cell id's to prune

View File

@ -25,6 +25,7 @@
#include "dbCommonReader.h"
#include "dbLoadLayoutOptions.h"
#include "gsiDecl.h"
#include "gsiEnums.h"
namespace dn
{
@ -160,6 +161,36 @@ gsi::ClassExt<db::LoadLayoutOptions> common_reader_options (
""
);
gsi::EnumIn<db::LoadLayoutOptions, db::CommonReader::CellConflictResolution> decl_dbCommonReader_CellConflictResolution ("db", "CellConflictResolution",
gsi::enum_const ("AddToCell", db::CommonReader::AddToCell,
"@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."
) +
gsi::enum_const ("OverwriteCell", db::CommonReader::OverwriteCell,
"@brief The old cell is overwritten entirely (including child cells which are not used otherwise)\n"
) +
gsi::enum_const ("SkipNewCell", db::CommonReader::SkipNewCell,
"@brief The new cell is skipped entirely (including child cells which are not used otherwise)\n"
) +
gsi::enum_const ("RenameCell", db::CommonReader::RenameCell,
"@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. "
"Until version 0.26.8 and before, the mode was always 'AddToCell'. On reading, a cell was 'reopened' when encountering a cell name "
"which already existed. This mode is still the default. The other modes are made available to support other ways of merging layouts.\n"
"\n"
"Proxy cells are never modified in the existing layout. Proxy cells are always local to their layout file. So if the existing cell is "
"a proxy cell, the new cell will be renamed.\n"
"\n"
"If the new or existing cell is a ghost cell, both cells are merged always.\n"
"\n"
"This enum was introduced in version 0.27.\n"
);
// Inject the NetlistCrossReference::Status declarations into NetlistCrossReference:
gsi::ClassExt<db::LoadLayoutOptions> inject_CellConflictResolution_in_parent (decl_dbCommonReader_CellConflictResolution.defs ());
}

View File

@ -61,7 +61,7 @@ GDS2ReaderText::read (db::Layout &layout, const db::LoadLayoutOptions &options)
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);
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 &
@ -259,7 +259,7 @@ GDS2ReaderText::get_double ()
}
void
GDS2ReaderText::get_string (tl::string &s) const
GDS2ReaderText::get_string (std::string &s) const
{
// TODO: get rid of this const_cast hack
s = (const_cast<GDS2ReaderText *> (this))->reader.skip ();

View File

@ -112,7 +112,7 @@ private:
virtual std::string path () const;
const char *get_string ();
void get_string (tl::string &s) const;
void get_string (std::string &s) const;
int get_int ();
short get_short ();
unsigned short get_ushort ();

View File

@ -64,7 +64,7 @@ GDS2Reader::read (db::Layout &layout, const db::LoadLayoutOptions &options)
--m_recnum;
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);
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 &
@ -210,7 +210,7 @@ GDS2Reader::get_string ()
}
void
GDS2Reader::get_string (tl::string &s) const
GDS2Reader::get_string (std::string &s) const
{
s.assign ((const char *) mp_rec_buf, 0, m_reclen);
}

View File

@ -126,7 +126,7 @@ private:
virtual std::string path () const;
virtual const char *get_string ();
virtual void get_string (tl::string &s) const;
virtual void get_string (std::string &s) const;
virtual int get_int ();
virtual short get_short ();
virtual unsigned short get_ushort ();

View File

@ -84,7 +84,7 @@ GDS2ReaderBase::~GDS2ReaderBase ()
}
const LayerMap &
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)
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)
{
m_layer_map = layer_map;
m_layer_map.prepare (layout);
@ -95,9 +95,17 @@ GDS2ReaderBase::basic_read (db::Layout &layout, const LayerMap &layer_map, bool
m_box_mode = box_mode;
m_create_layers = create_other_layers;
set_cell_conflict_resolution (cc_resolution);
layout.start_changes ();
do_read (layout);
layout.end_changes ();
try {
do_read (layout);
finish (layout);
layout.end_changes ();
} catch (...) {
layout.end_changes ();
throw;
}
return m_layer_map;
}
@ -235,7 +243,6 @@ GDS2ReaderBase::do_read (db::Layout &layout)
{
m_cellname = "";
m_libname = "";
m_mapped_cellnames.clear ();
// read header
if (get_record () != sHEADER) {
@ -349,7 +356,7 @@ GDS2ReaderBase::do_read (db::Layout &layout)
} else {
db::cell_index_type cell_index = make_cell (layout, m_cellname.c_str (), false);
db::cell_index_type cell_index = make_cell (layout, m_cellname);
db::Cell *cell = &layout.cell (cell_index);
@ -359,8 +366,6 @@ GDS2ReaderBase::do_read (db::Layout &layout)
if (layout.recover_proxy_as (cell_index, ctx->second.begin (), ctx->second.end (), &layer_mapping)) {
// ignore everything in that cell since it is created by the import:
cell = 0;
// marks the cell for begin addressed by REF's despite being a proxy:
m_mapped_cellnames.insert (std::make_pair (m_cellname, m_cellname));
}
}
@ -973,54 +978,6 @@ GDS2ReaderBase::read_box (db::Layout &layout, db::Cell &cell)
}
}
db::cell_index_type
GDS2ReaderBase::make_cell (db::Layout &layout, const char *cn, bool for_instance)
{
db::cell_index_type ci = 0;
// map to the real name which maybe a different one due to localization
// of proxy cells (they are not to be reopened)
bool is_mapped = false;
if (! m_mapped_cellnames.empty ()) {
std::map<tl::string, tl::string>::const_iterator n = m_mapped_cellnames.find (cn);
if (n != m_mapped_cellnames.end ()) {
cn = n->second.c_str ();
is_mapped = true;
}
}
std::pair<bool, db::cell_index_type> c = layout.cell_by_name (cn);
if (c.first && (is_mapped || ! layout.cell (c.second).is_proxy ())) {
// cell already there: just add instance (cell might have been created through forward reference)
// NOTE: we don't address "reopened" proxies as proxies are always local to a layout
ci = c.second;
// mark the cell as read
if (! for_instance) {
layout.cell (ci).set_ghost_cell (false);
}
} else {
ci = layout.add_cell (cn);
if (for_instance) {
// mark this cell a "ghost cell" until it's actually read
layout.cell (ci).set_ghost_cell (true);
}
if (c.first) {
// this cell has been given a new name: remember this name for localization
m_mapped_cellnames.insert (std::make_pair (cn, layout.cell_name (ci)));
}
}
return ci;
}
void
GDS2ReaderBase::read_ref (db::Layout &layout, db::Cell & /*cell*/, bool array, tl::vector<db::CellInstArray> &instances, tl::vector<db::CellInstArrayWithProperties> &instances_with_props)
{
@ -1033,7 +990,7 @@ GDS2ReaderBase::read_ref (db::Layout &layout, db::Cell & /*cell*/, bool array, t
error (tl::to_string (tr ("SNAME record expected")));
}
db::cell_index_type ci = make_cell (layout, get_string (), true);
db::cell_index_type ci = cell_for_instance (layout, get_string ());
bool mirror = false;
int angle = 0;

View File

@ -29,6 +29,7 @@
#include "dbLayout.h"
#include "dbReader.h"
#include "dbStreamLayers.h"
#include "dbCommonReader.h"
#include "tlException.h"
#include "tlInternational.h"
@ -49,7 +50,7 @@ struct GDS2XY
* @brief The GDS2 format basic stream reader
*/
class DB_PLUGIN_PUBLIC GDS2ReaderBase
: public ReaderBase
: public CommonReader
{
public:
/**
@ -86,20 +87,21 @@ protected:
* @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);
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
*/
const tl::string &cellname () const { return m_cellname; }
const std::string &cellname () const { return m_cellname; }
private:
friend class GDS2ReaderLayerMapping;
LayerMap m_layer_map;
tl::string m_cellname;
std::string m_cellname;
std::string m_libname;
double m_dbu, m_dbuu;
bool m_create_layers;
@ -109,7 +111,6 @@ private:
unsigned int m_box_mode;
std::map <tl::string, std::vector<std::string> > m_context_info;
std::vector <db::Point> m_all_points;
std::map <tl::string, tl::string> m_mapped_cellnames;
void read_context_info_cell ();
void read_boundary (db::Layout &layout, db::Cell &cell, bool from_box_record);
@ -117,7 +118,6 @@ private:
void read_text (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);
db::cell_index_type make_cell (db::Layout &layout, const char *cn, bool for_instance);
void do_read (db::Layout &layout);
@ -125,12 +125,15 @@ private:
std::pair <bool, db::properties_id_type> finish_element (db::PropertiesRepository &rep);
void finish_element ();
virtual void common_reader_error (const std::string &msg) { error (msg); }
virtual void common_reader_warn (const std::string &msg) { warn (msg); }
virtual void error (const std::string &txt) = 0;
virtual void warn (const std::string &txt) = 0;
virtual std::string path () const = 0;
virtual const char *get_string () = 0;
virtual void get_string (tl::string &s) const = 0;
virtual void get_string (std::string &s) const = 0;
virtual int get_int () = 0;
virtual short get_short () = 0;
virtual unsigned short get_ushort () = 0;

View File

@ -144,9 +144,12 @@ OASISReader::read (db::Layout &layout, const db::LoadLayoutOptions &options)
m_read_all_properties = oasis_options.read_all_properties;
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 ();
@ -758,17 +761,11 @@ OASISReader::do_read (db::Layout &layout)
id_mode propstring_id_mode = any;
id_mode propname_id_mode = any;
m_cellnames.clear ();
m_cellname_properties.clear ();
m_textstrings.clear ();
m_propstrings.clear ();
m_propnames.clear ();
m_layernames.clear ();
m_cells_by_id.clear ();
m_cells_by_name.clear ();
m_defined_cells_by_id.clear ();
m_defined_cells_by_name.clear ();
m_mapped_cellnames.clear ();
m_instances.clear ();
m_instances_with_props.clear ();
@ -826,9 +823,7 @@ OASISReader::do_read (db::Layout &layout)
get (id);
}
if (! m_cellnames.insert (std::make_pair (id, name)).second) {
error (tl::sprintf (tl::to_string (tr ("A CELLNAME with id %ld is present already")), id));
}
rename_cell (layout, id, name);
reset_modal_variables ();
@ -1150,37 +1145,11 @@ OASISReader::do_read (db::Layout &layout)
unsigned long id = 0;
get (id);
if (! m_defined_cells_by_id.insert (id).second) {
if (has_cell (id)) {
error (tl::sprintf (tl::to_string (tr ("A cell with id %ld is defined already")), id));
}
std::map <unsigned long, db::cell_index_type>::const_iterator c = m_cells_by_id.find (id);
if (c != m_cells_by_id.end ()) {
cell_index = c->second;
layout.cell (cell_index).set_ghost_cell (false);
} else {
std::map <unsigned long, std::string>::const_iterator name = m_cellnames.find (id);
if (name == m_cellnames.end ()) {
cell_index = layout.add_cell ();
// force a cell rename to empty to avoid name clashes of the generated
// $x names with the same inside the OASIS file.
layout.rename_cell (cell_index, "");
m_forward_references.insert (std::make_pair (id, cell_index));
} else {
cell_index = make_cell (layout, name->second.c_str (), false);
m_cells_by_name.insert (std::make_pair (name->second, cell_index));
}
m_cells_by_id.insert (std::make_pair (id, cell_index));
}
cell_index = make_cell (layout, id);
} else {
@ -1189,22 +1158,11 @@ OASISReader::do_read (db::Layout &layout)
}
std::string name = get_str ();
if (! m_defined_cells_by_name.insert (name).second) {
if (has_cell (name)) {
error (tl::sprintf (tl::to_string (tr ("A cell with name %s is defined already")), name.c_str ()));
}
std::map <std::string, db::cell_index_type>::const_iterator c = m_cells_by_name.find (name);
if (c != m_cells_by_name.end ()) {
cell_index = c->second;
layout.cell (cell_index).set_ghost_cell (false);
} else {
cell_index = make_cell (layout, name.c_str (), false);
m_cells_by_name.insert (std::make_pair (name, cell_index));
}
cell_index = make_cell (layout, name);
}
@ -1326,72 +1284,16 @@ OASISReader::do_read (db::Layout &layout)
}
for (std::map <unsigned long, db::cell_index_type>::const_iterator fw = m_forward_references.begin (); fw != m_forward_references.end (); ++fw) {
std::map <unsigned long, std::string>::const_iterator cn = m_cellnames.find (fw->first);
if (cn == m_cellnames.end ()) {
error (tl::sprintf (tl::to_string (tr ("No cellname defined for cell name id %ld")), fw->first));
} else {
std::pair<bool, db::cell_index_type> c = layout.cell_by_name (cn->second.c_str ());
if (c.first) {
// needed, since we have disabled updates
layout.force_update ();
// add-on reading of forward-referenced cell: need to copy the new cell to the original one plus
// change instances of the new cell and delete the new cell then.
const db::Cell &new_cell = layout.cell (fw->second);
db::Cell &org_cell = layout.cell (c.second);
// copy over the instances
for (db::Cell::const_iterator i = new_cell.begin (); ! i.at_end (); ++i) {
org_cell.insert (*i);
}
// copy over the shapes
for (unsigned int l = 0; l < layout.layers (); ++l) {
if (layout.is_valid_layer (l) && ! new_cell.shapes (l).empty ()) {
org_cell.shapes (l).insert (new_cell.shapes (l));
}
}
// replace all instances of the new cell with the original one
std::vector<std::pair<db::cell_index_type, db::Instance> > parents;
for (db::Cell::parent_inst_iterator pi = new_cell.begin_parent_insts (); ! pi.at_end (); ++pi) {
parents.push_back (std::make_pair (pi->parent_cell_index (), pi->child_inst ()));
}
for (std::vector<std::pair<db::cell_index_type, db::Instance> >::const_iterator p = parents.begin (); p != parents.end (); ++p) {
db::CellInstArray ia = p->second.cell_inst ();
ia.object ().cell_index (org_cell.cell_index ());
layout.cell (p->first).replace (p->second, ia);
}
// finally delete the new cell
layout.delete_cell (new_cell.cell_index ());
} else {
layout.rename_cell (fw->second, cn->second.c_str ());
}
}
}
// attach the properties found in CELLNAME to the cells (which may have other properties)
for (std::map<unsigned long, db::properties_id_type>::const_iterator p = m_cellname_properties.begin (); p != m_cellname_properties.end (); ++p) {
std::map <unsigned long, db::cell_index_type>::const_iterator c = m_cells_by_id.find (p->first);
if (c != m_cells_by_id.end ()) {
std::pair<bool, db::cell_index_type> c = cell_by_id (p->first);
if (c.first) {
db::PropertiesRepository::properties_set cnp = layout.properties_repository ().properties (p->second);
// Merge existing properties with the ones from CELLNAME
db::Cell &cell = layout.cell (c->second);
db::Cell &cell = layout.cell (c.second);
if (cell.prop_id () != 0) {
db::PropertiesRepository::properties_set cp = layout.properties_repository ().properties (cell.prop_id ());
cnp.insert (cp.begin (), cp.end ());
@ -1844,54 +1746,6 @@ OASISReader::read_repetition ()
return mm_repetition.get ().size () > 1;
}
db::cell_index_type
OASISReader::make_cell (db::Layout &layout, const char *cn, bool for_instance)
{
db::cell_index_type ci = 0;
// map to the real name which maybe a different one due to localization
// of proxy cells (they are not to be reopened)
bool is_mapped = false;
if (! m_mapped_cellnames.empty ()) {
std::map<tl::string, tl::string>::const_iterator n = m_mapped_cellnames.find (cn);
if (n != m_mapped_cellnames.end ()) {
cn = n->second.c_str ();
is_mapped = true;
}
}
std::pair<bool, db::cell_index_type> c = layout.cell_by_name (cn);
if (c.first && (is_mapped || ! layout.cell (c.second).is_proxy ())) {
// cell already there: just add instance (cell might have been created through forward reference)
// NOTE: we don't address "reopened" proxies as proxies are always local to a layout
ci = c.second;
// mark the cell as read
if (! for_instance) {
layout.cell (ci).set_ghost_cell (false);
}
} else {
ci = layout.add_cell (cn);
if (for_instance) {
// mark this cell a "ghost cell" until it's actually read
layout.cell (ci).set_ghost_cell (true);
}
if (c.first) {
// this cell has been given a new name: remember this name for localization
m_mapped_cellnames.insert (std::make_pair (cn, layout.cell_name (ci)));
}
}
return ci;
}
void
OASISReader::do_read_placement (unsigned char r,
bool xy_absolute,
@ -1909,31 +1763,8 @@ OASISReader::do_read_placement (unsigned char r,
// cell by id
unsigned long id;
get (id);
std::map <unsigned long, db::cell_index_type>::const_iterator cid = m_cells_by_id.find (id);
if (cid == m_cells_by_id.end ()) {
// create the cell
std::map <unsigned long, std::string>::const_iterator name = m_cellnames.find (id);
if (name == m_cellnames.end ()) {
mm_placement_cell = layout.add_cell ();
m_forward_references.insert (std::make_pair (id, mm_placement_cell.get ()));
// temporarily mark as "ghost cell"
layout.cell (mm_placement_cell.get ()).set_ghost_cell (true);
} else {
mm_placement_cell = make_cell (layout, name->second.c_str (), true);
m_cells_by_name.insert (std::make_pair (name->second, mm_placement_cell.get ()));
}
m_cells_by_id.insert (std::make_pair (id, mm_placement_cell.get ()));
} else {
mm_placement_cell = cid->second;
}
mm_placement_cell = cell_for_instance (layout, id);
} else {
@ -1941,15 +1772,7 @@ OASISReader::do_read_placement (unsigned char r,
std::string name;
get_str (name);
std::map <std::string, db::cell_index_type>::const_iterator cid = m_cells_by_name.find (name);
if (cid == m_cells_by_name.end ()) {
mm_placement_cell = make_cell (layout, name.c_str (), true);
m_cells_by_name.insert (std::make_pair (name, mm_placement_cell.get ()));
} else {
mm_placement_cell = cid->second;
}
mm_placement_cell = cell_for_instance (layout, name);
}

View File

@ -33,6 +33,7 @@
#include "dbOASISFormat.h"
#include "dbStreamLayers.h"
#include "dbPropertiesRepository.h"
#include "dbCommonReader.h"
#include "tlException.h"
#include "tlInternational.h"
@ -62,7 +63,7 @@ public:
* @brief The OASIS format stream reader
*/
class DB_PLUGIN_PUBLIC OASISReader
: public ReaderBase,
: public CommonReader,
public OASISDiagnostics
{
public:
@ -118,6 +119,7 @@ public:
*/
virtual const char *format () const { return "OASIS"; }
protected:
/**
* @brief Issue an error with positional information
*
@ -132,6 +134,9 @@ public:
*/
virtual void warn (const std::string &txt);
virtual void common_reader_error (const std::string &msg) { error (msg); }
virtual void common_reader_warn (const std::string &msg) { warn (msg); }
private:
friend class OASISReaderLayerMapping;
@ -194,7 +199,6 @@ private:
modal_variable<bool> mm_last_property_is_sprop;
modal_variable<property_value_list> mm_last_value_list;
std::map <unsigned long, std::string> m_cellnames;
std::map <unsigned long, db::properties_id_type> m_cellname_properties;
std::map <unsigned long, std::string> m_textstrings;
std::map <unsigned long, const db::StringRef *> m_text_forward_references;
@ -205,18 +209,11 @@ private:
tl::vector<db::CellInstArray> m_instances;
tl::vector<db::CellInstArrayWithProperties> m_instances_with_props;
std::map <unsigned long, db::cell_index_type> m_cells_by_id;
std::map <unsigned long, db::cell_index_type> m_forward_references;
std::map <std::string, db::cell_index_type> m_cells_by_name;
bool m_create_layers;
bool m_read_texts;
bool m_read_properties;
bool m_read_all_properties;
std::set <unsigned long> m_defined_cells_by_id;
std::set <std::string> m_defined_cells_by_name;
std::map <tl::string, tl::string> m_mapped_cellnames;
std::map <unsigned long, db::property_names_id_type> m_propname_forward_references;
std::map <unsigned long, std::string> m_propvalue_forward_references;
db::property_names_id_type m_s_gds_property_name_id;
@ -238,7 +235,6 @@ private:
void do_read_trapezoid (unsigned char r, bool xy_absolute,db::cell_index_type cell_index, db::Layout &layout);
void do_read_ctrapezoid (bool xy_absolute,db::cell_index_type cell_index, db::Layout &layout);
void do_read_circle (bool xy_absolute,db::cell_index_type cell_index, db::Layout &layout);
db::cell_index_type make_cell (db::Layout &layout, const char *cn, bool for_instance);
void reset_modal_variables ();