mirror of https://github.com/KLayout/klayout.git
Fixed bug #121 (reopening of PCell's in GDS and - partially - in OASIS)
This commit is contained in:
parent
887bcb3e04
commit
f74f2d3416
|
|
@ -237,6 +237,7 @@ GDS2ReaderBase::do_read (db::Layout &layout)
|
|||
|
||||
m_cellname = "";
|
||||
m_libname = "";
|
||||
m_mapped_cellnames.clear ();
|
||||
|
||||
// read header
|
||||
if (get_record () != sHEADER) {
|
||||
|
|
@ -350,17 +351,7 @@ GDS2ReaderBase::do_read (db::Layout &layout)
|
|||
|
||||
} else {
|
||||
|
||||
db::cell_index_type cell_index;
|
||||
|
||||
std::pair<bool, db::cell_index_type> c = layout.cell_by_name (m_cellname.c_str ());
|
||||
if (c.first) {
|
||||
// cell already there: just add shapes (cell might have been created through forward reference)
|
||||
cell_index = c.second;
|
||||
// remove "ghost cell" state
|
||||
layout.cell (cell_index).set_ghost_cell (false);
|
||||
} else {
|
||||
cell_index = layout.add_cell (m_cellname.c_str ());
|
||||
}
|
||||
db::cell_index_type cell_index = make_cell (layout, m_cellname.c_str (), false);
|
||||
|
||||
db::Cell *cell = &layout.cell (cell_index);
|
||||
|
||||
|
|
@ -370,6 +361,8 @@ 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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -982,6 +975,54 @@ 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)
|
||||
{
|
||||
|
|
@ -994,22 +1035,7 @@ GDS2ReaderBase::read_ref (db::Layout &layout, db::Cell & /*cell*/, bool array, t
|
|||
error (tl::to_string (QObject::tr ("SNAME record expected")));
|
||||
}
|
||||
|
||||
db::cell_index_type ci;
|
||||
|
||||
{
|
||||
// obtain cell or create new: "cn" is not valid beyond the
|
||||
// scope of the get_string() call
|
||||
const char *cn = get_string ();
|
||||
std::pair<bool, db::cell_index_type> c = layout.cell_by_name (cn);
|
||||
if (c.first) {
|
||||
// cell already there: just add shapes (cell might have been created through forward reference)
|
||||
ci = c.second;
|
||||
} else {
|
||||
ci = layout.add_cell (cn);
|
||||
// mark this cell a "ghost cell" until it's actually read
|
||||
layout.cell (ci).set_ghost_cell (true);
|
||||
}
|
||||
}
|
||||
db::cell_index_type ci = make_cell (layout, get_string (), true);
|
||||
|
||||
bool mirror = false;
|
||||
int angle = 0;
|
||||
|
|
|
|||
|
|
@ -109,6 +109,7 @@ 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);
|
||||
|
|
@ -116,6 +117,7 @@ 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);
|
||||
|
||||
|
|
|
|||
|
|
@ -770,6 +770,7 @@ OASISReader::do_read (db::Layout &layout)
|
|||
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 ();
|
||||
|
|
@ -1174,14 +1175,7 @@ OASISReader::do_read (db::Layout &layout)
|
|||
|
||||
} else {
|
||||
|
||||
std::pair<bool, db::cell_index_type> c = layout.cell_by_name (name->second.c_str ());
|
||||
if (c.first) {
|
||||
cell_index = c.second;
|
||||
layout.cell (cell_index).set_ghost_cell (false);
|
||||
} else {
|
||||
cell_index = layout.add_cell (name->second.c_str ());
|
||||
}
|
||||
|
||||
cell_index = make_cell (layout, name->second.c_str (), false);
|
||||
m_cells_by_name.insert (std::make_pair (name->second, cell_index));
|
||||
|
||||
}
|
||||
|
|
@ -1209,14 +1203,7 @@ OASISReader::do_read (db::Layout &layout)
|
|||
|
||||
} else {
|
||||
|
||||
std::pair<bool, db::cell_index_type> c = layout.cell_by_name (name.c_str ());
|
||||
if (c.first) {
|
||||
cell_index = c.second;
|
||||
layout.cell (cell_index).set_ghost_cell (false);
|
||||
} else {
|
||||
cell_index = layout.add_cell (name.c_str ());
|
||||
}
|
||||
|
||||
cell_index = make_cell (layout, name.c_str (), false);
|
||||
m_cells_by_name.insert (std::make_pair (name, cell_index));
|
||||
|
||||
}
|
||||
|
|
@ -1859,6 +1846,54 @@ 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,
|
||||
|
|
@ -1891,17 +1926,7 @@ OASISReader::do_read_placement (unsigned char r,
|
|||
|
||||
} else {
|
||||
|
||||
std::pair<bool, db::cell_index_type> c = layout.cell_by_name (name->second.c_str ());
|
||||
if (c.first) {
|
||||
// take existing cell
|
||||
mm_placement_cell = c.second;
|
||||
} else {
|
||||
// create the cell
|
||||
mm_placement_cell = layout.add_cell (name->second.c_str ());
|
||||
// temporarily mark as "ghost cell"
|
||||
layout.cell (mm_placement_cell.get ()).set_ghost_cell (true);
|
||||
}
|
||||
|
||||
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 ()));
|
||||
|
||||
}
|
||||
|
|
@ -1921,17 +1946,7 @@ OASISReader::do_read_placement (unsigned char r,
|
|||
std::map <std::string, db::cell_index_type>::const_iterator cid = m_cells_by_name.find (name);
|
||||
if (cid == m_cells_by_name.end ()) {
|
||||
|
||||
std::pair<bool, db::cell_index_type> c = layout.cell_by_name (name.c_str ());
|
||||
if (c.first) {
|
||||
// take existing cell
|
||||
mm_placement_cell = c.second;
|
||||
} else {
|
||||
// create the cell
|
||||
mm_placement_cell = layout.add_cell (name.c_str ());
|
||||
// temporarily mark as "ghost cell"
|
||||
layout.cell (mm_placement_cell.get ()).set_ghost_cell (true);
|
||||
}
|
||||
|
||||
mm_placement_cell = make_cell (layout, name.c_str (), true);
|
||||
m_cells_by_name.insert (std::make_pair (name, mm_placement_cell.get ()));
|
||||
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -269,6 +269,7 @@ private:
|
|||
|
||||
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;
|
||||
|
|
@ -291,6 +292,7 @@ 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 ();
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,9 @@
|
|||
|
||||
#include "dbGDS2Reader.h"
|
||||
#include "dbLayoutDiff.h"
|
||||
#include "dbTestSupport.h"
|
||||
#include "tlUnitTest.h"
|
||||
#include "tlStream.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
|
|
@ -347,3 +349,47 @@ TEST(2)
|
|||
}
|
||||
}
|
||||
|
||||
// Ability to merge GDS files with PCells
|
||||
|
||||
TEST(Bug_121_1)
|
||||
{
|
||||
db::Manager m;
|
||||
db::Layout layout (&m);
|
||||
|
||||
{
|
||||
tl::InputStream file (tl::testsrc () + "/testdata/gds/bug_121a.gds");
|
||||
db::GDS2Reader reader (file);
|
||||
reader.read (layout);
|
||||
}
|
||||
|
||||
{
|
||||
tl::InputStream file (tl::testsrc () + "/testdata/gds/bug_121b.gds");
|
||||
db::GDS2Reader reader (file);
|
||||
reader.read (layout);
|
||||
}
|
||||
|
||||
std::string fn_au (tl::testsrc () + "/testdata/gds/bug_121_au1.gds");
|
||||
db::compare_layouts (_this, layout, fn_au, db::WriteGDS2, 1);
|
||||
}
|
||||
|
||||
TEST(Bug_121_2)
|
||||
{
|
||||
db::Manager m;
|
||||
db::Layout layout (&m);
|
||||
|
||||
{
|
||||
tl::InputStream file (tl::testsrc () + "/testdata/gds/bug_121a.gds");
|
||||
db::GDS2Reader reader (file);
|
||||
reader.read (layout);
|
||||
}
|
||||
|
||||
{
|
||||
tl::InputStream file (tl::testsrc () + "/testdata/gds/bug_121c.gds");
|
||||
db::GDS2Reader reader (file);
|
||||
reader.read (layout);
|
||||
}
|
||||
|
||||
std::string fn_au (tl::testsrc () + "/testdata/gds/bug_121_au2.gds");
|
||||
db::compare_layouts (_this, layout, fn_au, db::WriteGDS2, 1);
|
||||
}
|
||||
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -89,4 +89,3 @@ TEST(1)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue