mirror of https://github.com/KLayout/klayout.git
Attempt to auto-import .map files for LEF/DEF reader. Probably needs adjustment.
This commit is contained in:
parent
df11ff9b85
commit
44503facea
|
|
@ -147,18 +147,25 @@ LEFDEFLayerDelegate::open_layer (db::Layout &layout, const std::string &n, Layer
|
||||||
{
|
{
|
||||||
if (purpose == Outline || purpose == PlacementBlockage || purpose == Region) {
|
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 ld;
|
||||||
|
std::string canonical_name;
|
||||||
bool produce;
|
bool produce;
|
||||||
|
|
||||||
if (purpose == Outline) {
|
if (purpose == Outline) {
|
||||||
produce = mp_tech_comp->produce_cell_outlines ();
|
produce = mp_tech_comp->produce_cell_outlines ();
|
||||||
ld = mp_tech_comp->cell_outline_layer ();
|
ld = mp_tech_comp->cell_outline_layer ();
|
||||||
|
canonical_name = "(OUTLINE)";
|
||||||
} else if (purpose == Region) {
|
} else if (purpose == Region) {
|
||||||
produce = mp_tech_comp->produce_regions ();
|
produce = mp_tech_comp->produce_regions ();
|
||||||
ld = mp_tech_comp->region_layer ();
|
ld = mp_tech_comp->region_layer ();
|
||||||
|
canonical_name = "(REGION)";
|
||||||
} else {
|
} else {
|
||||||
produce = mp_tech_comp->produce_placement_blockages ();
|
produce = mp_tech_comp->produce_placement_blockages ();
|
||||||
ld = mp_tech_comp->placement_blockage_layer ();
|
ld = mp_tech_comp->placement_blockage_layer ();
|
||||||
|
canonical_name = "(BLK)";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! produce) {
|
if (! produce) {
|
||||||
|
|
@ -178,10 +185,9 @@ LEFDEFLayerDelegate::open_layer (db::Layout &layout, const std::string &n, Layer
|
||||||
|
|
||||||
if (ll.first) {
|
if (ll.first) {
|
||||||
|
|
||||||
// create the layer if it is not part of the layout yet.
|
return ll;
|
||||||
if (! layout.is_valid_layer (ll.second)) {
|
|
||||||
layout.insert_layer (ll.second, m_layer_map.mapping (ll.second));
|
} else if ((ll = m_layer_map.logical (db::LayerProperties (canonical_name), layout)).first) {
|
||||||
}
|
|
||||||
|
|
||||||
return ll;
|
return ll;
|
||||||
|
|
||||||
|
|
@ -199,67 +205,99 @@ LEFDEFLayerDelegate::open_layer (db::Layout &layout, const std::string &n, Layer
|
||||||
|
|
||||||
} else {
|
} 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);
|
std::string name (n);
|
||||||
bool produce = true;
|
|
||||||
int dt = 0;
|
int dt = 0;
|
||||||
|
|
||||||
|
std::string canonical_purpose;
|
||||||
|
|
||||||
if (mp_tech_comp) {
|
if (mp_tech_comp) {
|
||||||
switch (purpose) {
|
switch (purpose) {
|
||||||
case Routing:
|
case Routing:
|
||||||
default:
|
default:
|
||||||
produce = mp_tech_comp->produce_routing ();
|
|
||||||
name += mp_tech_comp->routing_suffix ();
|
name += mp_tech_comp->routing_suffix ();
|
||||||
|
canonical_purpose = "NET";
|
||||||
dt += mp_tech_comp->routing_datatype ();
|
dt += mp_tech_comp->routing_datatype ();
|
||||||
break;
|
break;
|
||||||
case ViaGeometry:
|
case ViaGeometry:
|
||||||
produce = mp_tech_comp->produce_via_geometry ();
|
|
||||||
name += mp_tech_comp->via_geometry_suffix ();
|
name += mp_tech_comp->via_geometry_suffix ();
|
||||||
dt += mp_tech_comp->via_geometry_datatype ();
|
dt += mp_tech_comp->via_geometry_datatype ();
|
||||||
|
canonical_purpose = "VIA";
|
||||||
break;
|
break;
|
||||||
case Label:
|
case Label:
|
||||||
produce = mp_tech_comp->produce_labels ();
|
|
||||||
name += mp_tech_comp->labels_suffix ();
|
name += mp_tech_comp->labels_suffix ();
|
||||||
dt += mp_tech_comp->labels_datatype ();
|
dt += mp_tech_comp->labels_datatype ();
|
||||||
|
canonical_purpose = "LABEL";
|
||||||
break;
|
break;
|
||||||
case Pins:
|
case Pins:
|
||||||
produce = mp_tech_comp->produce_pins ();
|
|
||||||
name += mp_tech_comp->pins_suffix ();
|
name += mp_tech_comp->pins_suffix ();
|
||||||
dt += mp_tech_comp->pins_datatype ();
|
dt += mp_tech_comp->pins_datatype ();
|
||||||
|
canonical_purpose = "PIN";
|
||||||
break;
|
break;
|
||||||
case Obstructions:
|
case Obstructions:
|
||||||
produce = mp_tech_comp->produce_obstructions ();
|
|
||||||
name += mp_tech_comp->obstructions_suffix ();
|
name += mp_tech_comp->obstructions_suffix ();
|
||||||
dt += mp_tech_comp->obstructions_datatype ();
|
dt += mp_tech_comp->obstructions_datatype ();
|
||||||
|
canonical_purpose = "OBS";
|
||||||
break;
|
break;
|
||||||
case Blockage:
|
case Blockage:
|
||||||
produce = mp_tech_comp->produce_blockages ();
|
|
||||||
name += mp_tech_comp->blockages_suffix ();
|
name += mp_tech_comp->blockages_suffix ();
|
||||||
dt += mp_tech_comp->blockages_datatype ();
|
dt += mp_tech_comp->blockages_datatype ();
|
||||||
|
canonical_purpose = "BLK";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! produce) {
|
std::string canonical_name = std::string ("(") + n + "," + canonical_purpose + ")";
|
||||||
return std::make_pair (false, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::pair<bool, unsigned int> ll = m_layer_map.logical (name, layout);
|
std::pair<bool, unsigned int> ll = m_layer_map.logical (name, layout);
|
||||||
|
|
||||||
if (ll.first) {
|
if (ll.first) {
|
||||||
|
|
||||||
// create the layer if it is not part of the layout yet.
|
return ll;
|
||||||
if (! layout.is_valid_layer (ll.second)) {
|
|
||||||
layout.insert_layer (ll.second, m_layer_map.mapping (ll.second));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
} else if ((ll = m_layer_map.logical (db::LayerProperties (canonical_name), layout)).first) {
|
||||||
|
|
||||||
|
// final fallback: try canonical name
|
||||||
return ll;
|
return ll;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
std::pair<bool, unsigned int> ll_raw = m_layer_map.logical (n, layout);
|
ll = m_layer_map.logical (n, layout);
|
||||||
int ln = -1;
|
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.map (db::LayerProperties (name), layout.layers (), db::LayerProperties (ln, dt, name));
|
||||||
m_layer_map.prepare (layout);
|
m_layer_map.prepare (layout);
|
||||||
|
|
|
||||||
|
|
@ -518,6 +518,14 @@ public:
|
||||||
return m_layer_map;
|
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
|
* @brief Create a new layer or return the index of the given layer
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -77,6 +77,124 @@ static bool is_def_format (const std::string &fn)
|
||||||
return false;
|
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
|
class LEFDEFReader
|
||||||
: public db::ReaderBase
|
: 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
|
// Take the layer map and the "read all layers" flag from the reader options - hence we override the
|
||||||
db::LEFDEFLayerDelegate layers (lefdef_options);
|
db::LEFDEFLayerDelegate layers (lefdef_options);
|
||||||
|
|
||||||
|
import_map_file_heuristics (m_stream.absolute_path (), layers);
|
||||||
|
|
||||||
layers.prepare (layout);
|
layers.prepare (layout);
|
||||||
layout.dbu (lefdef_options->dbu ());
|
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 ());
|
std::string input_dir = tl::absolute_path (m_stream.absolute_path ());
|
||||||
|
|
||||||
if (tl::file_exists (input_dir)) {
|
if (tl::file_exists (input_dir)) {
|
||||||
|
|
||||||
std::vector<std::string> entries = tl::dir_entries (input_dir);
|
std::vector<std::string> entries = tl::dir_entries (input_dir);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue