Attempt to auto-import .map files for LEF/DEF reader. Probably needs adjustment.

This commit is contained in:
Matthias Koefferlein 2020-03-29 18:57:07 +02:00
parent df11ff9b85
commit 44503facea
3 changed files with 190 additions and 21 deletions

View File

@ -147,18 +147,25 @@ LEFDEFLayerDelegate::open_layer (db::Layout &layout, const std::string &n, Layer
{
if (purpose == Outline || purpose == PlacementBlockage || purpose == Region) {
// NOTE: the canonical name is independent from the tech component's settings
// as is "(name)". It's used for implementing the automatic map file import
// feature.
std::string ld;
std::string canonical_name;
bool produce;
if (purpose == Outline) {
produce = mp_tech_comp->produce_cell_outlines ();
ld = mp_tech_comp->cell_outline_layer ();
canonical_name = "(OUTLINE)";
} else if (purpose == Region) {
produce = mp_tech_comp->produce_regions ();
ld = mp_tech_comp->region_layer ();
canonical_name = "(REGION)";
} else {
produce = mp_tech_comp->produce_placement_blockages ();
ld = mp_tech_comp->placement_blockage_layer ();
canonical_name = "(BLK)";
}
if (! produce) {
@ -178,10 +185,9 @@ LEFDEFLayerDelegate::open_layer (db::Layout &layout, const std::string &n, Layer
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, m_layer_map.mapping (ll.second));
}
return ll;
} else if ((ll = m_layer_map.logical (db::LayerProperties (canonical_name), layout)).first) {
return ll;
@ -199,67 +205,99 @@ LEFDEFLayerDelegate::open_layer (db::Layout &layout, const std::string &n, Layer
} else {
if (mp_tech_comp) {
bool produce = true;
switch (purpose) {
case Routing:
default:
produce = mp_tech_comp->produce_routing ();
break;
case ViaGeometry:
produce = mp_tech_comp->produce_via_geometry ();
break;
case Label:
produce = mp_tech_comp->produce_labels ();
break;
case Pins:
produce = mp_tech_comp->produce_pins ();
break;
case Obstructions:
produce = mp_tech_comp->produce_obstructions ();
break;
case Blockage:
produce = mp_tech_comp->produce_blockages ();
break;
}
if (! produce) {
return std::make_pair (false, 0);
}
}
// Note: "name" is the decorated name as provided by the tech component's
// x_suffix specifications. As this is a variable entity, we also provide
// a canonical name of the form "(layer,purpose)" where purpose is a
// predefined suffix. The canonical name is the last fallback. Hence this
// allows importing layer mapping files as canonical name mapping.
std::string name (n);
bool produce = true;
int dt = 0;
std::string canonical_purpose;
if (mp_tech_comp) {
switch (purpose) {
case Routing:
default:
produce = mp_tech_comp->produce_routing ();
name += mp_tech_comp->routing_suffix ();
canonical_purpose = "NET";
dt += mp_tech_comp->routing_datatype ();
break;
case ViaGeometry:
produce = mp_tech_comp->produce_via_geometry ();
name += mp_tech_comp->via_geometry_suffix ();
dt += mp_tech_comp->via_geometry_datatype ();
canonical_purpose = "VIA";
break;
case Label:
produce = mp_tech_comp->produce_labels ();
name += mp_tech_comp->labels_suffix ();
dt += mp_tech_comp->labels_datatype ();
canonical_purpose = "LABEL";
break;
case Pins:
produce = mp_tech_comp->produce_pins ();
name += mp_tech_comp->pins_suffix ();
dt += mp_tech_comp->pins_datatype ();
canonical_purpose = "PIN";
break;
case Obstructions:
produce = mp_tech_comp->produce_obstructions ();
name += mp_tech_comp->obstructions_suffix ();
dt += mp_tech_comp->obstructions_datatype ();
canonical_purpose = "OBS";
break;
case Blockage:
produce = mp_tech_comp->produce_blockages ();
name += mp_tech_comp->blockages_suffix ();
dt += mp_tech_comp->blockages_datatype ();
canonical_purpose = "BLK";
break;
}
}
if (! produce) {
return std::make_pair (false, 0);
}
std::string canonical_name = std::string ("(") + n + "," + canonical_purpose + ")";
std::pair<bool, unsigned int> ll = m_layer_map.logical (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, m_layer_map.mapping (ll.second));
}
return ll;
} else if ((ll = m_layer_map.logical (db::LayerProperties (canonical_name), layout)).first) {
// final fallback: try canonical name
return ll;
} else {
std::pair<bool, unsigned int> ll_raw = m_layer_map.logical (n, layout);
ll = m_layer_map.logical (n, layout);
int ln = -1;
if (ll_raw.first && (ln = layout.get_properties (ll_raw.second).layer) >= 0) {
if (ll.first && (ln = layout.get_properties (ll.second).layer) >= 0) {
m_layer_map.map (db::LayerProperties (name), layout.layers (), db::LayerProperties (ln, dt, name));
m_layer_map.prepare (layout);

View File

@ -518,6 +518,14 @@ public:
return m_layer_map;
}
/**
* @brief Get the layer map (non-const version)
*/
db::LayerMap &layer_map ()
{
return m_layer_map;
}
/**
* @brief Create a new layer or return the index of the given layer
*/

View File

@ -77,6 +77,124 @@ static bool is_def_format (const std::string &fn)
return false;
}
/**
* @brief Reads a map file
*
* NOTE: this is rather experimental ... no idea what is the specification of
* the map file.
*/
static void
read_map_file (const std::string &path, db::LEFDEFLayerDelegate &layers)
{
tl::log << tl::to_string (tr ("Reading LEF/DEF map file")) << " " << path;
db::LayerMap &lm = layers.layer_map ();
unsigned int n = lm.next_index ();
tl::InputFile file (path);
tl::InputStream file_stream (file);
tl::TextInputStream ts (file_stream);
std::map<std::string, std::string> purpose_translation;
purpose_translation ["LEFPIN"] = "PIN";
purpose_translation ["LEFOBS"] = "OBS";
purpose_translation ["SPNET"] = "NET";
purpose_translation ["NET"] = "NET";
purpose_translation ["VIA"] = "VIA";
while (! ts.at_end ()) {
const std::string &l = ts.get_line ();
tl::Extractor ex (l.c_str ());
if (ex.at_end () || ex.test ("#")) {
// ignore empty of comment lines
} else {
std::string w1, w2;
int layer = 0, datatype = 0;
if (ex.try_read_word (w1) && ex.try_read_word (w2, "._$,/:") && ex.try_read (layer) && ex.try_read (datatype)) {
if (w1 == "DIEAREA") {
std::string canonical_name = "(OUTLINE)";
lm.map (db::LayerProperties (canonical_name), n++, db::LayerProperties (layer, datatype));
} else if (w1 == "NAME") {
std::vector<std::string> purposes = tl::split (w2, ",");
for (std::vector<std::string>::const_iterator p = purposes.begin (); p != purposes.end (); ++p) {
std::string canonical_name = std::string ("(") + tl::split (*p, "/").front () + ",LABEL)";
lm.map (db::LayerProperties (canonical_name), n++, db::LayerProperties (layer, datatype));
}
} else {
std::vector<std::string> purposes = tl::split (w2, ",");
for (std::vector<std::string>::const_iterator p = purposes.begin (); p != purposes.end (); ++p) {
std::map<std::string, std::string>::const_iterator i = purpose_translation.find (*p);
if (i != purpose_translation.end ()) {
std::string canonical_name = std::string ("(") + w1 + "," + i->second + ")";
lm.map (db::LayerProperties (canonical_name), n++, db::LayerProperties (layer, datatype));
}
}
}
}
}
}
}
/**
* @brief Imports a .map file present next to the input files
*/
static void
import_map_file_heuristics (const std::string &main_path, db::LEFDEFLayerDelegate &layers)
{
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), layers);
tl::log << layers.layer_map ().to_string_file_format (); // @@@
} else if (map_files.size () == 1) {
read_map_file (tl::combine_path (input_dir, map_files.front ()), layers);
tl::log << layers.layer_map ().to_string_file_format (); // @@@
}
} catch (tl::Exception &ex) {
// ignore read errors on map file (this is a heuristics!)
tl::error << ex.msg ();
}
}
class LEFDEFReader
: public db::ReaderBase
{
@ -125,6 +243,9 @@ private:
// Take the layer map and the "read all layers" flag from the reader options - hence we override the
db::LEFDEFLayerDelegate layers (lefdef_options);
import_map_file_heuristics (m_stream.absolute_path (), layers);
layers.prepare (layout);
layout.dbu (lefdef_options->dbu ());
@ -163,9 +284,11 @@ private:
}
// Additionally read all LEF files next to the DEF file
// 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.
std::string input_dir = tl::absolute_path (m_stream.absolute_path ());
if (tl::file_exists (input_dir)) {
std::vector<std::string> entries = tl::dir_entries (input_dir);