Layer mapping scheme enhancements, UI enhancements

* A map file can now be specified and should be read relative
  to the technology
* Giving a map file will disable the pattern-based mapping
* UI enhanced accordingly
* Added UI option to configure macro resolution mode
* Bugfix: LEF files have not been read relative to the tech
* Bugfix: Some options where not persistent
This commit is contained in:
Matthias Koefferlein 2020-05-02 00:14:06 +02:00
parent 0e68b910fa
commit 97022a3a87
8 changed files with 781 additions and 632 deletions

View File

@ -77,7 +77,7 @@ LEFDEFReaderOptions::LEFDEFReaderOptions ()
m_special_routing_suffix (""),
m_special_routing_datatype (0),
m_separate_groups (false),
m_consider_map_file (true),
m_map_file (),
m_macro_resolution_mode (0)
{
// .. nothing yet ..
@ -125,7 +125,7 @@ LEFDEFReaderOptions::LEFDEFReaderOptions (const LEFDEFReaderOptions &d)
m_special_routing_suffix (d.m_special_routing_suffix),
m_special_routing_datatype (d.m_special_routing_datatype),
m_separate_groups (d.m_separate_groups),
m_consider_map_file (d.m_consider_map_file),
m_map_file (d.m_map_file),
m_macro_resolution_mode (d.m_macro_resolution_mode),
m_lef_files (d.m_lef_files)
{
@ -298,45 +298,6 @@ LEFDEFReaderState::read_map_file (const std::string &path, db::Layout &layout)
}
}
void
LEFDEFReaderState::import_map_file_heuristics (const std::string &main_path, db::Layout &layout)
{
std::string input_dir = tl::absolute_path (main_path);
if (! tl::file_exists (input_dir)) {
return;
}
std::string bn = tl::basename (tl::filename (main_path));
std::vector<std::string> map_files;
std::string map_file_exact;
std::vector<std::string> entries = tl::dir_entries (input_dir);
for (std::vector<std::string>::const_iterator e = entries.begin (); e != entries.end (); ++e) {
if (tl::to_lower_case (tl::extension (*e)) == "map") {
if (tl::basename (*e) == bn) {
map_file_exact = *e;
} else {
map_files.push_back (*e);
}
}
}
try {
if (! map_file_exact.empty ()) {
read_map_file (tl::combine_path (input_dir, map_file_exact), layout);
} else if (map_files.size () == 1) {
read_map_file (tl::combine_path (input_dir, map_files.front ()), layout);
}
} catch (tl::Exception &ex) {
// ignore read errors on map file (this is a heuristics!)
tl::error << ex.msg ();
}
}
std::pair <bool, unsigned int>
LEFDEFReaderState::open_layer (db::Layout &layout, const std::string &n, LayerPurpose purpose)
{

View File

@ -515,14 +515,14 @@ public:
m_separate_groups = f;
}
bool consider_map_file () const
const std::string &map_file () const
{
return m_consider_map_file;
return m_map_file;
}
void set_consider_map_file (bool f)
void set_map_file (const std::string &f)
{
m_consider_map_file = f;
m_map_file = f;
}
/**
@ -584,7 +584,7 @@ private:
std::string m_special_routing_suffix;
int m_special_routing_datatype;
bool m_separate_groups;
bool m_consider_map_file;
std::string m_map_file;
unsigned int m_macro_resolution_mode;
std::vector<std::string> m_lef_files;
};
@ -637,14 +637,6 @@ public:
*/
void read_map_file (const std::string &path, db::Layout &layout);
/**
* @brief Imports a .map file present next to the input files
* "main_path" path of an input file (DEF). If a suitable .map file is found at this path,
* it is loaded into the reader state object. This will eventually disable any other layer
* mapping except for the global layers (region, outline, placement blockage).
*/
void import_map_file_heuristics (const std::string &main_path, db::Layout &layout);
/**
* @brief Sets the layer map
*/

View File

@ -31,6 +31,7 @@
#include "dbDEFImporter.h"
#include "dbLEFDEFImporter.h"
#include "dbLayoutUtils.h"
#include "dbTechnology.h"
namespace db
{
@ -103,14 +104,32 @@ public:
{
return "LEFDEF";
}
private:
tl::InputStream &m_stream;
db::LayerMap m_layer_map;
std::string correct_path (const std::string &fn)
std::string correct_path (const std::string &fn, const db::Layout &layout)
{
if (! tl::is_absolute (fn)) {
// 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);
}
if (tech && ! tech->base_path ().empty ()) {
std::string new_fn = tl::combine_path (tech->base_path (), fn);
if (tl::file_exists (new_fn)) {
return new_fn;
}
}
return tl::combine_path (m_stream.absolute_path (), fn);
} else {
return fn;
}
@ -126,8 +145,8 @@ private:
db::LEFDEFReaderState state (lefdef_options, layout);
if (lefdef_options->consider_map_file ()) {
state.import_map_file_heuristics (m_stream.absolute_path (), layout);
if (! lefdef_options->map_file ().empty ()) {
state.read_map_file (correct_path (lefdef_options->map_file (), layout), layout);
}
layout.dbu (lefdef_options->dbu ());
@ -140,7 +159,7 @@ private:
for (std::vector<std::string>::const_iterator l = lefdef_options->begin_lef_files (); l != lefdef_options->end_lef_files (); ++l) {
std::string lp = correct_path (*l);
std::string lp = correct_path (*l, layout);
tl::InputStream lef_stream (lp);
tl::log << tl::to_string (tr ("Reading")) << " " << lp;
@ -159,7 +178,7 @@ private:
for (std::vector<std::string>::const_iterator l = lefdef_options->begin_lef_files (); l != lefdef_options->end_lef_files (); ++l) {
std::string lp = correct_path (*l);
std::string lp = correct_path (*l, layout);
tl::InputStream lef_stream (lp);
tl::log << tl::to_string (tr ("Reading")) << " " << lp;
@ -167,8 +186,7 @@ private:
}
// Additionally read all LEF files next to the DEF file and if there is a single .map file
// or one with the same name than the input file with ".map" suffix, try to read this one too.
// Additionally read all LEF files next to the DEF file
std::string input_dir = tl::absolute_path (m_stream.absolute_path ());
@ -205,6 +223,39 @@ private:
}
};
namespace {
struct MacroResolutionModeConverter
{
public:
MacroResolutionModeConverter ()
{
m_values.push_back ("default");
m_values.push_back ("always-lef");
m_values.push_back ("always-cellref");
}
std::string to_string (unsigned int v) const
{
return v < m_values.size () ? m_values[v] : std::string ();
}
void from_string (const std::string &s, unsigned int &v) const
{
v = 0;
for (unsigned int i = 0; i < (unsigned int) m_values.size (); ++i) {
if (m_values [i] == s) {
v = i;
}
}
}
private:
std::vector<std::string> m_values;
};
}
class LEFDEFFormatDeclaration
: public db::StreamFormatDeclaration
{
@ -280,7 +331,10 @@ class LEFDEFFormatDeclaration
tl::make_member (&LEFDEFReaderOptions::produce_special_routing, &LEFDEFReaderOptions::set_produce_special_routing, "produce-special-routing") +
tl::make_member (&LEFDEFReaderOptions::special_routing_suffix, &LEFDEFReaderOptions::set_special_routing_suffix, "special-routing-suffix") +
tl::make_member (&LEFDEFReaderOptions::special_routing_datatype, &LEFDEFReaderOptions::set_special_routing_datatype, "special-routing-datatype") +
tl::make_member (&LEFDEFReaderOptions::begin_lef_files, &LEFDEFReaderOptions::end_lef_files, &LEFDEFReaderOptions::push_lef_file, "lef-files")
tl::make_member (&LEFDEFReaderOptions::begin_lef_files, &LEFDEFReaderOptions::end_lef_files, &LEFDEFReaderOptions::push_lef_file, "lef-files") +
tl::make_member (&LEFDEFReaderOptions::macro_resolution_mode, &LEFDEFReaderOptions::set_macro_resolution_mode, "macro-resolution-mode", MacroResolutionModeConverter ()) +
tl::make_member (&LEFDEFReaderOptions::separate_groups, &LEFDEFReaderOptions::set_separate_groups, "separate-groups") +
tl::make_member (&LEFDEFReaderOptions::map_file, &LEFDEFReaderOptions::set_map_file, "map-file")
);
}
};

View File

@ -347,7 +347,7 @@ LEFImporter::read_geometries (db::Layout &layout, db::Cell &cell, LayerPurpose p
std::string vn = get ();
db::Cell *vc = reader_state ()->via_cell (vn);
if (! vc) {
warn ("Unknown via: " + vn);
warn (tl::to_string (tr ("Unknown via: ")) + vn);
}
if (iterate) {
@ -549,7 +549,7 @@ LEFImporter::read_viadef_by_geometry (Layout &layout, db::Cell &cell, ViaDesc &v
via_desc.m1 = routing_layers[0];
via_desc.m2 = routing_layers[1];
} else {
warn ("Can't determine routing layers for via: " + n);
warn (tl::to_string (tr ("Can't determine routing layers for via: ")) + n);
}
reset_cellname ();
@ -724,6 +724,11 @@ void
LEFImporter::read_macro (Layout &layout)
{
std::string mn = get ();
if (m_macros_by_name.find (mn) != m_macros_by_name.end ()) {
error (tl::to_string (tr ("Duplicate MACRO name: ")) + mn);
}
set_cellname (mn);
db::Cell &cell = layout.cell (layout.add_cell ());
@ -813,20 +818,11 @@ LEFImporter::read_macro (Layout &layout)
} else if (test ("FOREIGN")) {
if (foreign_cell) {
error ("Duplicate FOREIGN definition");
error (tl::to_string (tr ("Duplicate FOREIGN definition")));
}
std::string cn = get ();
db::cell_index_type ci;
std::pair<bool, db::cell_index_type> c = layout.cell_by_name (cn.c_str ());
if (c.first) {
ci = c.second;
} else {
ci = layout.add_cell (cn.c_str ());
layout.cell (ci).set_ghost_cell (true);
}
db::Point vec;
db::FTrans ft;
if (! peek (";")) {
@ -836,11 +832,24 @@ LEFImporter::read_macro (Layout &layout)
expect (";");
foreign_cell = &layout.cell (ci);
// What is the definition of the FOREIGN transformation?
// Guessing: this transformation moves the lower-left origin to 0,0
foreign_trans = db::Trans (db::Point () - vec) * db::Trans (ft);
foreign_name = cn;
if (options ().macro_resolution_mode () != 1) {
db::cell_index_type ci;
std::pair<bool, db::cell_index_type> c = layout.cell_by_name (cn.c_str ());
if (c.first) {
ci = c.second;
} else {
ci = layout.add_cell (cn.c_str ());
layout.cell (ci).set_ghost_cell (true);
}
foreign_cell = &layout.cell (ci);
// What is the definition of the FOREIGN transformation?
// Guessing: this transformation moves the lower-left origin to 0,0
foreign_trans = db::Trans (db::Point () - vec) * db::Trans (ft);
foreign_name = cn;
}
} else if (test ("OBS")) {
@ -855,38 +864,42 @@ LEFImporter::read_macro (Layout &layout)
}
if (options ().macro_resolution_mode () == 1 || (! foreign_cell && options ().macro_resolution_mode () != 2)) {
if (! foreign_cell) {
// actually implement the real cell
if (options ().macro_resolution_mode () != 2) {
layout.rename_cell (cell.cell_index (), mn.c_str ());
// actually implement the real cell
std::pair <bool, unsigned int> dl = open_layer (layout, std::string (), Outline);
if (dl.first) {
cell.shapes (dl.second).insert (db::Box (-origin, -origin + size));
}
layout.rename_cell (cell.cell_index (), mn.c_str ());
m_macros_by_name.insert (std::make_pair (mn, std::make_pair (&cell, db::Trans ())));
std::pair <bool, unsigned int> dl = open_layer (layout, std::string (), Outline);
if (dl.first) {
cell.shapes (dl.second).insert (db::Box (-origin, -origin + size));
}
} else if (! foreign_cell) {
m_macros_by_name.insert (std::make_pair (mn, std::make_pair (&cell, db::Trans ())));
// macro resolution mode #2 (always create a MACRO reference, no LEF geometry)
db::cell_index_type ci;
std::pair<bool, db::cell_index_type> c = layout.cell_by_name (mn.c_str ());
if (c.first) {
ci = c.second;
} else {
ci = layout.add_cell (mn.c_str ());
layout.cell (ci).set_ghost_cell (true);
}
layout.delete_cell (cell.cell_index ());
m_macros_by_name.insert (std::make_pair (mn, std::make_pair (&layout.cell (ci), db::Trans ())));
// macro resolution mode #2 (always create a MACRO reference, no LEF geometry)
db::cell_index_type ci;
std::pair<bool, db::cell_index_type> c = layout.cell_by_name (mn.c_str ());
if (c.first) {
ci = c.second;
} else {
ci = layout.add_cell (mn.c_str ());
layout.cell (ci).set_ghost_cell (true);
}
layout.delete_cell (cell.cell_index ());
m_macros_by_name.insert (std::make_pair (mn, std::make_pair (&layout.cell (ci), db::Trans ())));
}
} else if (foreign_name != mn) {
warn ("FOREIGN name differs from MACRO name in macro: " + mn);
warn (tl::to_string (tr ("FOREIGN name differs from MACRO name in macro: ")) + mn);
layout.rename_cell (cell.cell_index (), mn.c_str ());

View File

@ -466,17 +466,20 @@ gsi::Class<db::LEFDEFReaderOptions> decl_lefdef_config ("db", "LEFDEFReaderConfi
"\n"
"This property has been added in version 0.26.5.\n"
) +
gsi::method ("consider_map_file", &db::LEFDEFReaderOptions::consider_map_file,
"@brief Gets a value indicating whether to consider reading .map files next to DEF files.\n"
"If this property is set to true (the default), the DEF reader will look for .map files next to the "
"DEF file. If such a file is found, it will be used to map DEF layers to layout layers. The layer mapping "
"settings specified in the reader options are ignored in this case.\n"
gsi::method ("map_file", &db::LEFDEFReaderOptions::map_file,
"@brief Gets the layer map file to use.\n"
"If a layer map file is given, the reader will pull the layer mapping from this file. The layer mapping rules "
"specified in the reader options are ignored in this case. These are the name suffix rules for vias, blockages, routing, "
"special routing, pins etc. and the corresponding datatype rules. The \\layer_map attribute will also be ignored. "
"\n"
"The layer map file path will be resolved relative to the technology base path if the LEF/DEF reader options are "
"used in the context of a technology.\n"
"\n"
"This property has been added in version 0.26.5.\n"
) +
gsi::method ("consider_map_file=", &db::LEFDEFReaderOptions::set_consider_map_file, gsi::arg ("flag"),
"@brief Sets a value indicating whether to consider reading .map files next to DEF files.\n"
"See \\consider_map_file for details about this property.\n"
gsi::method ("map_file=", &db::LEFDEFReaderOptions::set_map_file, gsi::arg ("file"),
"@brief Sets the layer map file to use.\n"
"See \\map_file for details about this property.\n"
"\n"
"This property has been added in version 0.26.5.\n"
) +
@ -513,6 +516,21 @@ gsi::Class<db::LEFDEFReaderOptions> decl_lefdef_config ("db", "LEFDEFReaderConfi
"@brief Detailed LEF/DEF reader options\n"
"This class is a aggregate belonging to the \\LoadLayoutOptions class. It provides options for the LEF/DEF reader. "
"These options have been placed into a separate class to account for their complexity."
"\n"
"This class specifically handles layer mapping. This is the process of generating layer names or GDS layer/datatypes "
"from LEF/DEF layers and purpose combinations. There are basically two ways: to use a map file or to use pattern-based production rules.\n"
"\n"
"To use a layer map file, set the \\map_file attribute to the name of the layer map file. The layer map "
"file lists the GDS layer and datatype numbers to generate for the geometry.\n"
"\n"
"The pattern-based approach will use the layer name and attach a purpose-dependent suffix to it. "
"Use the ..._suffix attributes to specify this suffix. For routing, the corresponding attribute is \\routing_suffix for example. "
"A purpose can also be mapped to a specific GDS datatype using the corresponding ..._datatype attributes.\n"
"The decorated or undecorated names are looked up in a layer mapping table in the next step. The layer mapping table "
"is specified using the \\layer_map attribute. This table can be used to map layer names to specific GDS layers "
"by using entries of the form 'NAME: layer-number'.\n"
"\n"
"If a layer map file is present, the pattern-based attributes are ignored.\n"
);
}

View File

@ -363,7 +363,7 @@ LEFDEFReaderOptionsEditor::LEFDEFReaderOptionsEditor (QWidget *parent)
connect (del_lef_files, SIGNAL (clicked ()), this, SLOT (del_lef_files_clicked ()));
connect (move_lef_files_up, SIGNAL (clicked ()), this, SLOT (move_lef_files_up_clicked ()));
connect (move_lef_files_down, SIGNAL (clicked ()), this, SLOT (move_lef_files_down_clicked ()));
connect (consider_map_file, SIGNAL (stateChanged (int)), this, SLOT (consider_map_file_state_changed ()));
connect (browse_mapfile, SIGNAL (clicked ()), this, SLOT (browse_mapfile_clicked ()));
lay::activate_help_links (help_label);
}
@ -451,7 +451,8 @@ LEFDEFReaderOptionsEditor::commit (db::FormatSpecificReaderOptions *options, con
data->set_labels_suffix (tl::to_string (suffix_labels->text ()));
data->set_labels_datatype (datatype_labels->text ().toInt ());
data->set_separate_groups (separate_groups->isChecked ());
data->set_consider_map_file (consider_map_file->isChecked ());
data->set_map_file (tl::to_string (mapfile_path->text ()));
data->set_macro_resolution_mode (foreign_mode->currentIndex ());
data->clear_lef_files ();
for (int i = 0; i < lef_files->count (); ++i) {
@ -512,7 +513,9 @@ LEFDEFReaderOptionsEditor::setup (const db::FormatSpecificReaderOptions *options
suffix_labels->setText (tl::to_qstring (data->labels_suffix ()));
datatype_labels->setText (QString::number (data->labels_datatype ()));
separate_groups->setChecked (data->separate_groups ());
consider_map_file->setChecked (data->consider_map_file ());
mapfile_path->setText (tl::to_qstring (data->map_file ()));
layer_map_mode->setCurrentIndex (data->map_file ().empty () ? 1 : 0);
foreign_mode->setCurrentIndex (data->macro_resolution_mode ());
checkbox_changed ();
@ -529,13 +532,6 @@ LEFDEFReaderOptionsEditor::setup (const db::FormatSpecificReaderOptions *options
}
}
void
LEFDEFReaderOptionsEditor::consider_map_file_state_changed ()
{
warn1->setVisible (consider_map_file->isChecked ());
warn2->setVisible (consider_map_file->isChecked ());
}
void
LEFDEFReaderOptionsEditor::checkbox_changed ()
{
@ -563,6 +559,22 @@ LEFDEFReaderOptionsEditor::checkbox_changed ()
datatype_labels->setEnabled (produce_labels->isChecked ());
}
void
LEFDEFReaderOptionsEditor::browse_mapfile_clicked ()
{
std::string title, filters;
title = tl::to_string (QObject::tr ("Select Layer Map File"));
filters = tl::to_string (QObject::tr ("LEF/DEF layer map files (*.map);;All files (*)"));
QString file = QFileDialog::getOpenFileName (this, tl::to_qstring (title), QString (), tl::to_qstring (filters));
if (! file.isNull ()) {
if (mp_tech) {
mapfile_path->setText (tl::to_qstring (mp_tech->correct_path (tl::to_string (file))));
} else {
mapfile_path->setText (file);
}
}
}
void
LEFDEFReaderOptionsEditor::add_lef_file_clicked ()
{

View File

@ -98,7 +98,7 @@ private slots:
void del_lef_files_clicked ();
void move_lef_files_up_clicked ();
void move_lef_files_down_clicked ();
void consider_map_file_state_changed ();
void browse_mapfile_clicked ();
private:
tl::weak_ptr<db::Technology> mp_tech;