Merge branch 'master' into complex_drc_ops

This commit is contained in:
Matthias Koefferlein
2020-12-20 23:50:54 +01:00
92 changed files with 4391 additions and 1538 deletions
@@ -59,22 +59,20 @@ CIFReader::~CIFReader ()
const LayerMap &
CIFReader::read (db::Layout &layout, const db::LoadLayoutOptions &options)
{
prepare_layers ();
const db::CIFReaderOptions &specific_options = options.get_options<db::CIFReaderOptions> ();
m_wire_mode = specific_options.wire_mode;
m_dbu = specific_options.dbu;
db::LayerMap lm = specific_options.layer_map;
lm.prepare (layout);
set_layer_map (lm);
set_layer_map (specific_options.layer_map);
set_create_layers (specific_options.create_other_layers);
set_keep_layer_names (specific_options.keep_layer_names);
prepare_layers (layout);
do_read (layout);
finish_layers (layout);
return layer_map ();
return layer_map_out ();
}
const LayerMap &
@@ -39,13 +39,8 @@ static void run_test (tl::TestBase *_this, const std::string &base, const char *
unsigned int ln = 0;
tl::Extractor ex (map);
while (! ex.at_end ()) {
std::string n;
int l;
ex.read_word_or_quoted (n);
ex.test (":");
ex.read (l);
lm.add_expr (ex, ln++);
ex.test (",");
lm.map (n, ln++, db::LayerProperties (l, 0));
}
opt->layer_map = lm;
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);
}
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)
{
run_test (_this, tl::testsrc_private (), "t4.cif.gz", "t4_au.gds.gz");
@@ -318,9 +318,7 @@ DXFReader::read (db::Layout &layout, const db::LoadLayoutOptions &options)
m_stream.reset ();
m_initial = true;
m_line_number = 0;
db::LayerMap lm = specific_options.layer_map;
lm.prepare (layout);
set_layer_map (lm);
set_layer_map (specific_options.layer_map);
set_create_layers (specific_options.create_other_layers);
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);
cleanup (layout, top);
return layer_map ();
return layer_map_out ();
}
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
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
// 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.
if (! layout.is_valid_layer (ll.second)) {
layout.insert_layer (ll.second, layer_map ().mapping (ll.second));
}
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 (li.first) {
m_zero_layer = ll.second;
// we got one from the layer mapping
m_zero_layer = li.second;
} else {
// or explicitly create the layer:
m_zero_layer = layer_map ().next_index ();
layout.insert_layer (m_zero_layer, db::LayerProperties (0, 0, zero_layer_name));
// or we explicitly create the layer
db::LayerProperties lp_zero (0, 0, zero_layer_name);
m_zero_layer = layout.insert_layer (lp_zero);
map_layer (zero_layer_name, m_zero_layer);
}
prepare_layers ();
// Read sections
// Read sections
int g;
while (true) {
@@ -193,7 +193,6 @@ private:
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);
void cleanup (db::Layout &layout, db::cell_index_type top);
@@ -6,7 +6,7 @@ TARGET = dxf_tests
include($$PWD/../../../../lib_ut.pri)
SOURCES = \
dbDXFReader.cc \
dbDXFReaderTests.cc
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
@@ -51,23 +51,11 @@ GDS2ReaderText::~GDS2ReaderText()
// .. nothing yet ..
}
const LayerMap &
GDS2ReaderText::read (db::Layout &layout, const db::LoadLayoutOptions &options)
void
GDS2ReaderText::init (const db::LoadLayoutOptions &options)
{
GDS2ReaderBase::init (options);
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
@@ -64,43 +64,14 @@ public:
*/
~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
*/
const char *format () const { return "GDS2Text"; }
protected:
virtual void init (const LoadLayoutOptions &options);
private:
tl::TextInputStream sStream;
std::string sExtractedValue;
@@ -43,6 +43,7 @@ GDS2Reader::GDS2Reader (tl::InputStream &s)
m_recptr (0),
mp_rec_buf (0),
m_stored_rec (0),
m_allow_big_records (true),
m_progress (tl::to_string (tr ("Reading GDS2 file")), 10000)
{
m_progress.set_format (tl::to_string (tr ("%.0f MB")));
@@ -54,23 +55,16 @@ GDS2Reader::~GDS2Reader ()
// .. nothing yet ..
}
const LayerMap &
GDS2Reader::read (db::Layout &layout, const db::LoadLayoutOptions &options)
void
GDS2Reader::init (const db::LoadLayoutOptions &options)
{
m_options = options.get_options<db::GDS2ReaderOptions> ();
m_common_options = options.get_options<db::CommonReaderOptions> ();
GDS2ReaderBase::init (options);
m_allow_big_records = options.get_options<db::GDS2ReaderOptions> ().allow_big_records;
m_recnum = 0;
--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, m_common_options.cell_conflict_resolution);
}
const LayerMap &
GDS2Reader::read (db::Layout &layout)
{
return read (layout, db::LoadLayoutOptions ());
}
void
@@ -108,7 +102,7 @@ GDS2Reader::get_record ()
error (tl::to_string (tr ("Invalid record length (less than 4)")));
}
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")));
} else {
error (tl::to_string (tr ("Record length larger than 0x8000 encountered (reader is configured not to allow such records)")));
@@ -72,43 +72,14 @@ public:
*/
~GDS2Reader ();
/**
* @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
*/
virtual const char *format () const { return "GDS2"; }
protected:
virtual void init (const LoadLayoutOptions &options);
private:
tl::InputStream &m_stream;
size_t m_recnum;
@@ -117,8 +88,7 @@ private:
unsigned char *mp_rec_buf;
tl::string m_string_buf;
short m_stored_rec;
db::GDS2ReaderOptions m_options;
db::CommonReaderOptions m_common_options;
bool m_allow_big_records;
tl::AbsoluteProgress m_progress;
virtual void error (const std::string &txt);
@@ -22,6 +22,7 @@
#include "dbGDS2ReaderBase.h"
#include "dbGDS2Format.h"
#include "dbGDS2.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 ()
: m_dbu (0.001),
m_dbuu (1.0),
m_create_layers (true),
m_read_texts (true),
m_read_properties (true),
m_allow_multi_xy_records (false),
@@ -83,31 +54,18 @@ GDS2ReaderBase::~GDS2ReaderBase ()
// .. nothing yet ..
}
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, db::CommonReader::CellConflictResolution cc_resolution)
void
GDS2ReaderBase::init (const db::LoadLayoutOptions &options)
{
m_layer_map = layer_map;
m_layer_map.prepare (layout);
m_read_texts = enable_text_objects;
m_read_properties = enable_properties;
CommonReader::init (options);
m_allow_multi_xy_records = allow_multi_xy_records;
m_box_mode = box_mode;
m_create_layers = create_other_layers;
db::GDS2ReaderOptions gds2_options = options.get_options<db::GDS2ReaderOptions> ();
set_cell_conflict_resolution (cc_resolution);
m_read_texts = common_options ().enable_text_objects;
m_read_properties = common_options ().enable_properties;
layout.start_changes ();
try {
do_read (layout);
finish (layout);
layout.end_changes ();
} catch (...) {
layout.end_changes ();
throw;
}
return m_layer_map;
m_allow_multi_xy_records = gds2_options.allow_multi_xy_records;
m_box_mode = gds2_options.box_mode;
}
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
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 *cell = &layout.cell (cell_index);
bool ignore_cell = false;
std::map <tl::string, std::vector <std::string> >::const_iterator ctx = m_context_info.find (m_cellname);
if (ctx != m_context_info.end ()) {
GDS2ReaderLayerMapping layer_mapping (this, &layout, m_create_layers);
CommonReaderLayerMapping layer_mapping (this, &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;
ignore_cell = true;
}
}
db::Cell *cell = 0;
if (! ignore_cell) {
cell = &layout.cell (cell_index);
}
long attr = 0;
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;
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) {
// create a box object if possible
@@ -734,7 +668,7 @@ GDS2ReaderBase::read_path (db::Layout &layout, db::Cell &cell)
unsigned int xy_length = 0;
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) {
// 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);
if (m_read_texts) {
ll = open_dl (layout, ld, m_create_layers);
ll = open_dl (layout, ld);
}
rec_id = get_record ();
@@ -947,7 +881,7 @@ GDS2ReaderBase::read_box (db::Layout &layout, db::Cell &cell)
}
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) {
error (tl::to_string (tr ("XY record expected")));
@@ -69,42 +69,20 @@ public:
const std::string &libname () const { return m_libname; }
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
*/
const std::string &cellname () const { return m_cellname; }
virtual void do_read (db::Layout &layout);
virtual void init (const LoadLayoutOptions &options);
private:
friend class GDS2ReaderLayerMapping;
LayerMap m_layer_map;
std::string m_cellname;
std::string m_libname;
double m_dbu, m_dbuu;
bool m_create_layers;
bool m_read_texts;
bool m_read_properties;
bool m_allow_multi_xy_records;
@@ -119,9 +97,6 @@ private:
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 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);
void finish_element ();
@@ -332,7 +332,7 @@ TEST(2)
db::Layout layout_piece (&m);
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);
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 (),
"1/10 : 1/0\n"
"2/0-9,21-*\n"
"2/0-1 : 2/0\n"
"1/0 : 1/0\n"
"1/1 : 1/1\n"
"1/20 : 1/1020\n"
@@ -427,23 +427,103 @@ TEST(3_AdvancedMapping)
"2/11 : 2/11\n"
"42/42 : 142/42\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");
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)
{
db::Manager m (false);
db::Layout layout (&m);
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");
@@ -467,7 +547,7 @@ TEST(4_CollectModeOverwrite)
db::Layout layout (&m);
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");
@@ -491,7 +571,7 @@ TEST(4_CollectModeSkip)
db::Layout layout (&m);
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");
@@ -515,7 +595,7 @@ TEST(4_CollectModeAdd)
db::Layout layout (&m);
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");
@@ -157,14 +157,14 @@ DEFImporter::read_diearea (db::Layout &layout, db::Cell &design, double scale)
if (points.size () >= 2) {
// create outline shape
std::pair <bool, unsigned int> dl = open_layer (layout, std::string (), Outline, 0);
if (dl.first) {
std::set<unsigned int> dl = open_layer (layout, std::string (), Outline, 0);
for (std::set<unsigned int>::const_iterator l = dl.begin (); l != dl.end (); ++l) {
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 {
db::Polygon p;
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;
read_polygon (p, scale);
std::pair <bool, unsigned int> dl = open_layer (layout, layer, layer.empty () ? PlacementBlockage : Blockage, 0);
if (dl.first) {
design.shapes (dl.second).insert (p);
std::set <unsigned int> dl = open_layer (layout, layer, layer.empty () ? PlacementBlockage : Blockage, 0);
for (std::set<unsigned int>::const_iterator l = dl.begin (); l != dl.end (); ++l) {
design.shapes (*l).insert (p);
}
} else if (test ("RECT")) {
@@ -315,9 +315,9 @@ DEFImporter::read_blockages (db::Layout &layout, db::Cell &design, double scale)
db::Polygon p;
read_rect (p, scale);
std::pair <bool, unsigned int> dl = open_layer (layout, layer, layer.empty () ? PlacementBlockage : Blockage, 0);
if (dl.first) {
design.shapes (dl.second).insert (p);
std::set <unsigned int> dl = open_layer (layout, layer, layer.empty () ? PlacementBlockage : Blockage, 0);
for (std::set<unsigned int>::const_iterator l = dl.begin (); l != dl.end (); ++l) {
design.shapes (*l).insert (p);
}
} else {
@@ -554,17 +554,19 @@ DEFImporter::read_single_net (std::string &nondefaultrule, Layout &layout, db::C
test (")");
std::pair <bool, unsigned int> dl = open_layer (layout, ln, specialnets ? SpecialRouting : Routing, mask);
if (dl.first) {
std::set <unsigned int> dl = open_layer (layout, ln, specialnets ? SpecialRouting : Routing, mask);
if (! dl.empty ()) {
db::Point p (x, y);
db::Box rect (db::Point (db::DPoint ((x + x1) * scale, (y + y1) * scale)),
db::Point (db::DPoint ((x + x2) * scale, (y + y2) * scale)));
if (prop_id != 0) {
design.shapes (dl.second).insert (db::object_with_properties<db::Box> (rect, prop_id));
} else {
design.shapes (dl.second).insert (rect);
for (std::set<unsigned int>::const_iterator l = dl.begin (); l != dl.end (); ++l) {
if (prop_id != 0) {
design.shapes (*l).insert (db::object_with_properties<db::Box> (rect, prop_id));
} 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) {
std::pair <bool, unsigned int> dl = open_layer (layout, ln, specialnets ? SpecialRouting : Routing, mask);
if (dl.first) {
produce_routing_geometry (design, style, dl.second, prop_id, pts, ext, w);
std::set <unsigned int> dl = open_layer (layout, ln, specialnets ? SpecialRouting : Routing, mask);
for (std::set<unsigned int>::const_iterator l = dl.begin (); l != dl.end (); ++l) {
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;
read_polygon (p, scale);
std::pair <bool, unsigned int> dl = open_layer (layout, ln, specialnets ? SpecialRouting : Routing, mask);
if (dl.first) {
std::set <unsigned int> dl = open_layer (layout, ln, specialnets ? SpecialRouting : Routing, mask);
for (std::set<unsigned int>::const_iterator l = dl.begin (); l != dl.end (); ++l) {
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 {
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;
read_rect (p, scale);
std::pair <bool, unsigned int> dl = open_layer (layout, ln, specialnets ? SpecialRouting : Routing, mask);
if (dl.first) {
std::set <unsigned int> dl = open_layer (layout, ln, specialnets ? SpecialRouting : Routing, mask);
for (std::set<unsigned int>::const_iterator l = dl.begin (); l != dl.end (); ++l) {
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 {
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
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);
if (dl.first) {
std::set<unsigned int> dl = open_layer (layout, g->first.first, Pins, g->first.second);
if (! dl.empty ()) {
db::properties_id_type prop_id = 0;
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) {
db::Polygon pt = p->transformed (trans);
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 {
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);
if (dl.first) {
if (! dl.empty ()) {
db::Box bbox;
if (! g->second.empty ()) {
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 {
std::pair <bool, unsigned int> dl = open_layer (layout, std::string (), Regions, 0);
if (dl.first) {
std::set<unsigned int> dl = open_layer (layout, std::string (), Regions, 0);
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) {
group_cell->shapes (dl.second).insert (*p);
group_cell->shapes (*l).insert (*p);
}
}
regions.erase (r);
@@ -1597,12 +1605,12 @@ DEFImporter::do_read (db::Layout &layout)
if (! regions.empty ()) {
std::pair <bool, unsigned int> dl = open_layer (layout, std::string (), Regions, 0);
if (dl.first) {
std::set<unsigned int> dl = open_layer (layout, std::string (), Regions, 0);
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::vector<db::Polygon>::const_iterator p = r->second.begin (); p != r->second.end (); ++p) {
others_cell->shapes (dl.second).insert (*p);
others_cell->shapes (*l).insert (*p);
}
}
@@ -43,11 +43,7 @@ std::string correct_path (const std::string &fn, const db::Layout &layout, const
// if a technology is given and the file can be found in the technology's base path, take it
// from there.
std::string tn = layout.meta_info_value ("technology");
const db::Technology *tech = 0;
if (! tn.empty ()) {
tech = db::Technologies::instance ()->technology_by_name (tn);
}
const db::Technology *tech = layout.technology ();
if (tech && ! tech->base_path ().empty ()) {
std::string new_fn = tl::combine_path (tech->base_path (), fn);
@@ -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::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);
if (dl.first) {
cell.shapes (dl.second).insert (db::Polygon (via_box.enlarged (m_be).moved (m_bo)));
for (std::set<unsigned int>::const_iterator l = dl.begin (); l != dl.end (); ++l) {
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);
if (dl.first) {
cell.shapes (dl.second).insert (db::Polygon (via_box.enlarged (m_te).moved (m_bo)));
for (std::set<unsigned int>::const_iterator l = dl.begin (); l != dl.end (); ++l) {
cell.shapes (*l).insert (db::Polygon (via_box.enlarged (m_te).moved (m_bo)));
}
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);
if (dl.first) {
cell.shapes (dl.second).insert (db::Polygon (vb));
for (std::set<unsigned int>::const_iterator l = dl.begin (); l != dl.end (); ++l) {
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 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);
if (dl.first) {
cell.shapes (dl.second).insert (g->second);
std::set <unsigned int> dl = reader.open_layer (layout, g->first.first, g->first.second.first, mask);
for (std::set<unsigned int>::const_iterator l = dl.begin (); l != dl.end (); ++l) {
cell.shapes (*l).insert (g->second);
}
}
@@ -805,12 +801,24 @@ LEFDEFReaderState::register_layer (const std::string &ln)
++m_laynum;
}
void
LEFDEFReaderState::map_layer_explicit (const std::string &n, LayerPurpose purpose, const db::LayerProperties &lp, unsigned int layer, unsigned int mask)
static bool try_read_layers (tl::Extractor &ex, std::vector<int> &layers)
{
tl_assert (m_has_explicit_layer_mapping);
m_layers [std::make_pair (n, std::make_pair (purpose, mask))] = std::make_pair (true, layer);
m_layer_map.map (lp, layer);
int l = 0;
if (! ex.try_read (l)) {
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
@@ -832,13 +840,14 @@ LEFDEFReaderState::read_map_file (const std::string &path, db::Layout &layout)
purpose_translation ["NET"] = Routing;
purpose_translation ["VIA"] = ViaGeometry;
purpose_translation ["BLOCKAGE"] = Blockage;
purpose_translation ["ALL"] = All;
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) {
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 ()) {
@@ -852,113 +861,173 @@ LEFDEFReaderState::read_map_file (const std::string &path, db::Layout &layout)
} else {
std::string w1, w2;
int layer = 0, datatype = 0;
std::vector<int> layers, datatypes;
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
// "NAME M1/PINS,M2/PINS ..."
// into a canonical name mapping like
// "(M1/LABELS): M1.LABEL"
// "(M2/LABELS): M2.LABEL"
// converts a line like
// "NAME M1/PINS,M2/PINS ..."
// into a canonical name mapping like
// "(M1/LABELS): M1.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";
for (std::vector<std::string>::const_iterator l = layers.begin (); l != layers.end (); ++l) {
layer_map [std::make_pair (*l, std::make_pair (Label, (unsigned int) 0))] = db::LayerProperties (layer, datatype, final_name);
if (ex.test (":MASK:")) {
ex.read (mask);
}
} 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
// "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);
if (ex.test (":")) {
if (ex.test ("MASK") && ex.test (":")) {
ex.read (mask);
for (std::map<std::string, LayerPurpose>::const_iterator p = purpose_translation.begin (); p != purpose_translation.end (); ++p) {
if (p->second != All) {
translated_purposes.insert (std::make_pair (p->second, mask));
}
}
std::map<std::string, LayerPurpose>::const_iterator i = purpose_translation.find (ps);
if (i != purpose_translation.end ()) {
translated_purposes.insert (std::make_pair (i->second, mask));
}
} else {
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 ()) {
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;
}
for (std::set<std::pair<LayerPurpose, unsigned int> >::const_iterator p = translated_purposes.begin (); p != translated_purposes.end (); ++p) {
if (p != translated_purposes.begin ()) {
purpose_str += "/";
}
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) {
layer_map [std::make_pair (w1, *p)] = db::LayerProperties (layer, datatype, final_name);
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;
}
}
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);
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) {
map_layer_explicit (i->first.first, i->first.second.first, i->second, lm.map_layer (i->second).second, i->first.second.second);
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) {
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)
{
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 ()) {
std::pair <bool, unsigned int> ll (false, 0);
std::set <unsigned int> ll;
if (n.empty () || ! m_has_explicit_layer_mapping) {
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>
LEFDEFReaderState::open_layer_uncached (db::Layout &layout, const std::string &n, LayerPurpose purpose, unsigned int mask)
static std::string purpose_to_name (LayerPurpose purpose)
{
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 ()) {
// 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;
bool produce = false;
@@ -1016,7 +1165,7 @@ LEFDEFReaderState::open_layer_uncached (db::Layout &layout, const std::string &n
}
if (! produce) {
return std::make_pair (false, 0);
return std::set<unsigned int> ();
}
db::LayerProperties lp;
@@ -1028,13 +1177,69 @@ LEFDEFReaderState::open_layer_uncached (db::Layout &layout, const std::string &n
lp.datatype = 0;
}
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 no name is given, derive one from the purpose
if (lp.name.empty ()) {
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 {
@@ -1068,12 +1273,10 @@ LEFDEFReaderState::open_layer_uncached (db::Layout &layout, const std::string &n
break;
}
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;
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;
// Assign a layer number (a default one for now) and the datatype from the tech component's x_datatype specification.
db::LayerProperties lp (name);
lp.datatype = dt;
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;
}
std::pair<bool, unsigned int> ll = m_layer_map.logical (name, layout);
if (! ll.first) {
// Route the layer through the layer map, first the decorated name and if there is no mapping, the
// 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);
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) {
lp = *lpp;
if (lp.datatype >= 0) {
lp.datatype += dt;
lp_new = *lpp;
if (lp_new.datatype < 0) {
lp_new.datatype = dt;
} else if (generic_match) {
lp_new.datatype += dt;
}
if (lp.name.empty ()) {
lp.name = name;
if (lp_new.name.empty ()) {
lp_new.name = name;
} else if (generic_match) {
lp_new.name += name_suffix;
}
}
} else if (! m_create_layers) {
return std::make_pair (false, 0);
}
if (lp.layer >= 0 && lp.datatype >= 0) {
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);
int lfound = -1;
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)) {
lfound = int ((*i).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;
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;
}
std::string ps;
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 ps = purpose_to_name (l->first.second.first);
std::string n = l->first.first;
if (! n.empty ()) {
@@ -1265,11 +1439,43 @@ LEFDEFReaderState::finish (db::Layout &layout)
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;
}
@@ -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:
* 0: propduce LEF geometry unless a FOREIGN cell is specified (default)
* 1: produce LEF geometry always and ignore FOREIGN
@@ -884,6 +884,7 @@ enum LayerPurpose
Blockage, // from DEF only
PlacementBlockage, // 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
*/
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)
@@ -1187,7 +1188,7 @@ private:
LEFDEFReaderState (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;
bool m_create_layers;
bool m_has_explicit_layer_mapping;
@@ -1200,8 +1201,7 @@ private:
std::map<std::string, LEFDEFLayoutGenerator *> m_macro_generators;
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);
void map_layer_explicit (const std::string &n, LayerPurpose purpose, const LayerProperties &lp, unsigned int layer, unsigned int mask);
std::set<unsigned int> open_layer_uncached (db::Layout &layout, const std::string &name, LayerPurpose purpose, unsigned int mask);
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
*/
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);
}
@@ -113,22 +113,25 @@ private:
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 ()));
static db::LEFDEFReaderOptions default_options;
if (! lefdef_options) {
lefdef_options = &default_options;
db::LEFDEFReaderOptions effective_options;
if (lefdef_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) {
// 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")));
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 ()));
@@ -149,7 +152,7 @@ private:
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 ()));
@@ -163,7 +166,7 @@ private:
// 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 ());
@@ -198,7 +201,7 @@ private:
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 ();
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) {
std::vector<db::cell_index_type> target_cells, source_cells;
@@ -937,6 +937,24 @@ LEFImporter::read_macro (Layout &layout)
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")) {
mg->set_fixedmask (true);
@@ -770,8 +770,8 @@ gsi::Class<db::LEFDEFReaderOptions> decl_lefdef_config ("db", "LEFDEFReaderConfi
"This property has been added in version 0.27.\n"
) +
gsi::method ("macro_resolution_mode", &db::LEFDEFReaderOptions::macro_resolution_mode,
"@brief Gets the macro resolution mode.\n"
"This property describes the way LEF macros are turned into GDS cells. There "
"@brief Gets the macro resolution mode (LEF macros into DEF).\n"
"This property describes the way LEF macros are turned into layout cells when reading DEF. There "
"are three modes available:\n"
"\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"
) +
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"
"\n"
"This property has been added in version 0.27.\n"
@@ -294,7 +294,7 @@
<item row="1" column="4">
<widget class="QLabel" name="label">
<property name="text">
<string>LEF import</string>
<string>LEF import into DEF</string>
</property>
</widget>
</item>
@@ -708,6 +708,8 @@
<property name="text">
<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.
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>
</property>
<property name="wordWrap">
@@ -50,16 +50,13 @@ static db::LEFDEFReaderOptions default_options ()
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 ());
fn_path += "/testdata/lefdef/";
fn_path += lef_dir;
fn_path += "/";
db::Manager m (false);
db::Layout layout (&m), layout2 (&m), layout_au (&m);
tl::Extractor ex (filename);
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);
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 ..
// 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)
@@ -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);
}
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)
{
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);
}
@@ -72,13 +72,9 @@ MAGReader::read (db::Layout &layout)
const LayerMap &
MAGReader::read (db::Layout &layout, const db::LoadLayoutOptions &options)
{
prepare_layers ();
prepare_layers (layout);
mp_klayout_tech = 0;
std::string klayout_tech_name = layout.meta_info_value ("technology");
if (! klayout_tech_name.empty () && db::Technologies::instance ()->has_technology (klayout_tech_name)) {
mp_klayout_tech = db::Technologies::instance ()->technology_by_name (klayout_tech_name);
}
mp_klayout_tech = layout.technology ();
const db::MAGReaderOptions &specific_options = options.get_options<db::MAGReaderOptions> ();
m_lambda = specific_options.lambda;
@@ -87,9 +83,7 @@ MAGReader::read (db::Layout &layout, const db::LoadLayoutOptions &options)
m_merge = specific_options.merge;
mp_current_stream = 0;
db::LayerMap lm = specific_options.layer_map;
lm.prepare (layout);
set_layer_map (lm);
set_layer_map (specific_options.layer_map);
set_create_layers (specific_options.create_other_layers);
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_tech.clear ();
prepare_layers (layout);
{
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);
return layer_map ();
return layer_map_out ();
}
void
@@ -145,7 +145,7 @@ private:
std::map<std::string, std::string> m_use_lib_paths;
db::VCplxTrans m_dbu_trans_inv;
std::string m_tech;
db::Technology *mp_klayout_tech;
const db::Technology *mp_klayout_tech;
void do_read (db::Layout &layout, db::cell_index_type to_cell, tl::TextInputStream &stream);
void do_read_part (db::Layout &layout, db::cell_index_type cell_index, tl::TextInputStream &stream);
@@ -122,7 +122,7 @@ MAGWriter::write_dummmy_top (const std::set<db::cell_index_type> &cell_set, cons
std::string tech = m_options.tech;
if (tech.empty ()) {
tech = layout.meta_info_value ("technology");
tech = layout.technology_name ();
}
if (! tech.empty ()) {
os << "tech " << make_string (tl::to_lower_case (tech)) << "\n";
@@ -177,7 +177,7 @@ MAGWriter::do_write_cell (db::cell_index_type ci, const std::vector <std::pair <
std::string tech = m_options.tech;
if (tech.empty ()) {
tech = layout.meta_info_value ("technology");
tech = layout.technology_name ();
}
if (! tech.empty ()) {
os << "tech " << make_string (tl::to_lower_case (tech)) << "\n";
@@ -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
@@ -101,7 +72,6 @@ OASISReader::OASISReader (tl::InputStream &s)
mm_last_property_name (this, "last-property-name"),
mm_last_property_is_sprop (this, "last-property-is-stdprop"),
mm_last_value_list(this, "last-value-list"),
m_create_layers (false),
m_read_texts (true),
m_read_properties (true),
m_read_all_properties (false),
@@ -129,40 +99,17 @@ OASISReader::~OASISReader ()
// .. nothing yet ..
}
const LayerMap &
OASISReader::read (db::Layout &layout, const db::LoadLayoutOptions &options)
void
OASISReader::init (const db::LoadLayoutOptions &options)
{
db::OASISReaderOptions oasis_options = options.get_options<db::OASISReaderOptions> ();
db::CommonReaderOptions common_options = options.get_options<db::CommonReaderOptions> ();
CommonReader::init (options);
m_layer_map = common_options.layer_map;
m_layer_map.prepare (layout);
m_layers_created.clear ();
m_read_texts = common_options.enable_text_objects;
m_read_properties = common_options.enable_properties;
m_create_layers = common_options.create_other_layers;
m_read_texts = common_options ().enable_text_objects;
m_read_properties = common_options ().enable_properties;
db::OASISReaderOptions oasis_options = options.get_options<db::OASISReaderOptions> ();
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 ();
throw;
}
return m_layer_map;
}
const LayerMap &
OASISReader::read (db::Layout &layout)
{
return read (layout, db::LoadLayoutOptions ());
}
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
*/
@@ -599,12 +508,7 @@ struct LNameJoinOp1
{
void operator() (std::string &a, const std::string &b)
{
if (a != b) {
if (! a.empty ()) {
a += ";";
}
a += b;
}
join_layer_names (a, b);
}
};
@@ -765,7 +669,6 @@ OASISReader::do_read (db::Layout &layout)
m_textstrings.clear ();
m_propstrings.clear ();
m_propnames.clear ();
m_layernames.clear ();
m_instances.clear ();
m_instances_with_props.clear ();
@@ -1077,21 +980,8 @@ OASISReader::do_read (db::Layout &layout)
LNameJoinOp1 op1;
dt_map.add (dt1, dt2 + 1, name, op1);
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 ();
// ignore properties attached to this name item
@@ -2038,7 +1928,7 @@ OASISReader::do_read_text (bool xy_absolute,
std::pair<bool, unsigned int> ll (false, 0);
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 ()) {
@@ -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::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 ()) {
@@ -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 ());
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 ()) {
@@ -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 ());
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 ()) {
@@ -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 ());
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];
@@ -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 ());
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];
@@ -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 ());
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
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)
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);
}
@@ -81,39 +81,6 @@ public:
*/
~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
*/
@@ -136,6 +103,8 @@ protected:
virtual void common_reader_error (const std::string &msg) { error (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:
friend class OASISReaderLayerMapping;
@@ -153,8 +122,6 @@ private:
};
tl::InputStream &m_stream;
LayerMap m_layer_map;
std::set<unsigned int> m_layers_created;
tl::AbsoluteProgress m_progress;
std::string m_cellname;
double m_dbu;
@@ -204,12 +171,10 @@ private:
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_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::CellInstArrayWithProperties> m_instances_with_props;
bool m_create_layers;
bool m_read_texts;
bool m_read_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_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_placement (unsigned char r,
@@ -310,8 +274,6 @@ private:
db::Coord get_coord (long grid = 1);
db::Coord get_ucoord (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);
};
}