mirror of https://github.com/KLayout/klayout.git
WIP: refactoring of map file reading.
This commit is contained in:
parent
e51f15b116
commit
040af426dc
|
|
@ -42,7 +42,7 @@ namespace db
|
|||
*
|
||||
* This implementation will create new layers if required.
|
||||
*/
|
||||
class DirectLayerMapping
|
||||
class DB_PUBLIC DirectLayerMapping
|
||||
: public ImportLayerMapping
|
||||
{
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -22,9 +22,11 @@
|
|||
|
||||
|
||||
#include "dbLEFDEFImporter.h"
|
||||
#include "dbLayoutUtils.h"
|
||||
|
||||
#include "tlStream.h"
|
||||
#include "tlProgress.h"
|
||||
#include "tlFileUtils.h"
|
||||
|
||||
#include <cctype>
|
||||
|
||||
|
|
@ -74,7 +76,8 @@ LEFDEFReaderOptions::LEFDEFReaderOptions ()
|
|||
m_produce_special_routing (true),
|
||||
m_special_routing_suffix (""),
|
||||
m_special_routing_datatype (0),
|
||||
m_separate_groups (false)
|
||||
m_separate_groups (false),
|
||||
m_consider_map_file (true)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
@ -121,6 +124,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_lef_files (d.m_lef_files)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
|
|
@ -142,8 +146,20 @@ LEFDEFReaderOptions::format_name () const
|
|||
// -----------------------------------------------------------------------------------
|
||||
// LEFDEFLayerDelegate implementation
|
||||
|
||||
static db::LayerProperties lp_from_string (const std::string &ld)
|
||||
{
|
||||
db::LayerProperties lp;
|
||||
tl::Extractor ex (ld.c_str ());
|
||||
try {
|
||||
ex.read (lp);
|
||||
return lp;
|
||||
} catch (...) {
|
||||
return db::LayerProperties (0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
LEFDEFReaderState::LEFDEFReaderState (const LEFDEFReaderOptions *tc)
|
||||
: m_create_layers (true), m_laynum (1), mp_tech_comp (tc)
|
||||
: m_create_layers (true), m_has_explicit_layer_mapping (false), m_laynum (1), mp_tech_comp (tc)
|
||||
{
|
||||
if (tc) {
|
||||
m_layer_map = tc->layer_map ();
|
||||
|
|
@ -158,8 +174,208 @@ LEFDEFReaderState::register_layer (const std::string &ln)
|
|||
++m_laynum;
|
||||
}
|
||||
|
||||
std::pair <bool, unsigned int>
|
||||
void
|
||||
LEFDEFReaderState::set_explicit_layer_mapping (bool f)
|
||||
{
|
||||
m_has_explicit_layer_mapping = f;
|
||||
if (! f) {
|
||||
m_layers.clear ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
LEFDEFReaderState::map_layer_explicit (const std::string &n, LayerPurpose purpose, unsigned int layer)
|
||||
{
|
||||
m_layers [std::make_pair (n, purpose)] = std::make_pair (true, layer);
|
||||
}
|
||||
|
||||
void
|
||||
LEFDEFReaderState::read_map_file (const std::string &path, db::Layout &layout)
|
||||
{
|
||||
tl::log << tl::to_string (tr ("Reading LEF/DEF map file")) << " " << path;
|
||||
|
||||
tl::InputFile file (path);
|
||||
tl::InputStream file_stream (file);
|
||||
tl::TextInputStream ts (file_stream);
|
||||
|
||||
std::map<std::string, LayerPurpose> purpose_translation;
|
||||
purpose_translation ["LEFPIN"] = LEFPins;
|
||||
purpose_translation ["PIN"] = Pins;
|
||||
purpose_translation ["LEFOBS"] = Obstructions;
|
||||
purpose_translation ["SPNET"] = SpecialRouting;
|
||||
purpose_translation ["NET"] = Routing;
|
||||
purpose_translation ["VIA"] = ViaGeometry;
|
||||
purpose_translation ["BLOCKAGE"] = Blockage;
|
||||
|
||||
std::map<std::pair<std::string, LayerPurpose>, db::LayerProperties> layer_map;
|
||||
|
||||
if (tech_comp ()) {
|
||||
|
||||
const db::LEFDEFReaderOptions &options = *tech_comp ();
|
||||
|
||||
if (options.produce_placement_blockages ()) {
|
||||
layer_map [std::make_pair (std::string (), Blockage)] = lp_from_string (options.placement_blockage_layer ());
|
||||
}
|
||||
if (options.produce_cell_outlines ()) {
|
||||
layer_map [std::make_pair (std::string (), Outline)] = lp_from_string (options.cell_outline_layer ());
|
||||
}
|
||||
if (options.produce_regions ()) {
|
||||
layer_map [std::make_pair (std::string (), Region)] = lp_from_string (options.region_layer ());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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") {
|
||||
|
||||
layer_map [std::make_pair (std::string (), Outline)] = db::LayerProperties (layer, datatype, "OUTLINE");
|
||||
|
||||
} 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"
|
||||
|
||||
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, Label)] = db::LayerProperties (layer, datatype, final_name);
|
||||
}
|
||||
|
||||
} 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<LayerPurpose> translated_purposes;
|
||||
std::string purpose_str;
|
||||
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, LayerPurpose>::const_iterator i = purpose_translation.find (tl::to_upper_case (*p));
|
||||
if (i != purpose_translation.end ()) {
|
||||
|
||||
translated_purposes.insert (i->second);
|
||||
|
||||
if (! purpose_str.empty ()) {
|
||||
purpose_str += "/";
|
||||
}
|
||||
purpose_str += i->first;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
std::string final_name = w1 + "." + purpose_str;
|
||||
|
||||
for (std::set<LayerPurpose>::const_iterator p = translated_purposes.begin (); p != translated_purposes.end (); ++p) {
|
||||
layer_map [std::make_pair (w1, *p)] = db::LayerProperties (layer, datatype, final_name);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
set_explicit_layer_mapping (true);
|
||||
|
||||
db::DirectLayerMapping lm (&layout);
|
||||
for (std::map<std::pair<std::string, LayerPurpose>, db::LayerProperties>::const_iterator i = layer_map.begin (); i != layer_map.end (); ++i) {
|
||||
map_layer_explicit (i->first.first, i->first.second, lm.map_layer (i->second).second);
|
||||
}
|
||||
|
||||
// @@@ TODO: need to assign layer/datatype for all layers present.
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
std::map <std::pair<std::string, LayerPurpose>, std::pair<bool, unsigned int> >::const_iterator nl = m_layers.find (std::make_pair (n, purpose));
|
||||
if (nl == m_layers.end ()) {
|
||||
|
||||
std::pair <bool, unsigned int> ll (false, 0);
|
||||
|
||||
if (! m_has_explicit_layer_mapping) {
|
||||
ll = open_layer_uncached (layout, n, purpose);
|
||||
}
|
||||
|
||||
m_layers.insert (std::make_pair (std::make_pair (n, purpose), ll));
|
||||
return ll;
|
||||
|
||||
} else {
|
||||
return nl->second;
|
||||
}
|
||||
}
|
||||
|
||||
std::pair <bool, unsigned int>
|
||||
LEFDEFReaderState::open_layer_uncached (db::Layout &layout, const std::string &n, LayerPurpose purpose)
|
||||
{
|
||||
if (purpose == Outline || purpose == PlacementBlockage || purpose == Region) {
|
||||
|
||||
|
|
@ -167,21 +383,17 @@ LEFDEFReaderState::open_layer (db::Layout &layout, const std::string &n, LayerPu
|
|||
// 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) {
|
||||
|
|
@ -203,10 +415,6 @@ LEFDEFReaderState::open_layer (db::Layout &layout, const std::string &n, LayerPu
|
|||
|
||||
return ll;
|
||||
|
||||
} else if ((ll = m_layer_map.logical (db::LayerProperties (canonical_name), layout)).first) {
|
||||
|
||||
return ll;
|
||||
|
||||
} else if (! m_create_layers) {
|
||||
|
||||
return std::pair<bool, unsigned int> (false, 0);
|
||||
|
|
@ -256,74 +464,54 @@ LEFDEFReaderState::open_layer (db::Layout &layout, const std::string &n, LayerPu
|
|||
}
|
||||
|
||||
// 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.
|
||||
// x_suffix specifications.
|
||||
std::string name (n);
|
||||
int dt = 0;
|
||||
|
||||
std::string canonical_purpose;
|
||||
|
||||
if (mp_tech_comp) {
|
||||
switch (purpose) {
|
||||
case Routing:
|
||||
default:
|
||||
name += mp_tech_comp->routing_suffix ();
|
||||
canonical_purpose = "NET";
|
||||
dt += mp_tech_comp->routing_datatype ();
|
||||
break;
|
||||
case SpecialRouting:
|
||||
name += mp_tech_comp->special_routing_suffix ();
|
||||
canonical_purpose = "SPNET";
|
||||
dt += mp_tech_comp->special_routing_datatype ();
|
||||
break;
|
||||
case ViaGeometry:
|
||||
name += mp_tech_comp->via_geometry_suffix ();
|
||||
dt += mp_tech_comp->via_geometry_datatype ();
|
||||
canonical_purpose = "VIA";
|
||||
break;
|
||||
case Label:
|
||||
name += mp_tech_comp->labels_suffix ();
|
||||
dt += mp_tech_comp->labels_datatype ();
|
||||
canonical_purpose = "LABEL";
|
||||
break;
|
||||
case Pins:
|
||||
name += mp_tech_comp->pins_suffix ();
|
||||
dt += mp_tech_comp->pins_datatype ();
|
||||
canonical_purpose = "PIN";
|
||||
break;
|
||||
case LEFPins:
|
||||
name += mp_tech_comp->lef_pins_suffix ();
|
||||
dt += mp_tech_comp->lef_pins_datatype ();
|
||||
canonical_purpose = "LEFPIN";
|
||||
break;
|
||||
case Obstructions:
|
||||
name += mp_tech_comp->obstructions_suffix ();
|
||||
dt += mp_tech_comp->obstructions_datatype ();
|
||||
canonical_purpose = "OBS";
|
||||
break;
|
||||
case Blockage:
|
||||
name += mp_tech_comp->blockages_suffix ();
|
||||
dt += mp_tech_comp->blockages_datatype ();
|
||||
canonical_purpose = "BLK";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::string canonical_name = std::string ("(") + n + "," + canonical_purpose + ")";
|
||||
|
||||
std::pair<bool, unsigned int> ll = m_layer_map.logical (name, layout);
|
||||
|
||||
if (ll.first) {
|
||||
|
||||
return ll;
|
||||
|
||||
} else if ((ll = m_layer_map.logical (db::LayerProperties (canonical_name), layout)).first) {
|
||||
|
||||
// final fallback: try canonical name
|
||||
return ll;
|
||||
|
||||
} else {
|
||||
|
||||
ll = m_layer_map.logical (n, layout);
|
||||
|
|
@ -341,14 +529,14 @@ LEFDEFReaderState::open_layer (db::Layout &layout, const std::string &n, LayerPu
|
|||
|
||||
} else {
|
||||
|
||||
std::map <std::pair<std::string, LayerPurpose>, unsigned int>::const_iterator nl = m_layers.find (std::make_pair (n, purpose));
|
||||
if (nl == m_layers.end ()) {
|
||||
unsigned int li = layout.insert_layer (db::LayerProperties (name));
|
||||
m_layer_map.map (db::LayerProperties (name), li);
|
||||
m_layers.insert (std::make_pair (std::make_pair (n, purpose), li));
|
||||
return std::pair<bool, unsigned int> (true, li);
|
||||
std::map <std::pair<std::string, LayerPurpose>, unsigned int>::const_iterator l = m_unassigned_layers.find (std::make_pair (n, purpose));
|
||||
if (l != m_unassigned_layers.end ()) {
|
||||
return std::pair<bool, unsigned int> (true, l->second);
|
||||
} else {
|
||||
return std::pair<bool, unsigned int> (true, nl->second);
|
||||
unsigned int li = layout.insert_layer (db::LayerProperties (name));
|
||||
m_unassigned_layers.insert (std::make_pair (std::make_pair (n, purpose), li));
|
||||
m_layer_map.map (db::LayerProperties (name), li);
|
||||
return std::pair<bool, unsigned int> (true, li);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -380,7 +568,7 @@ LEFDEFReaderState::finish (db::Layout &layout)
|
|||
used_numbers.insert (ln->second);
|
||||
}
|
||||
|
||||
for (std::map<std::pair<std::string, LayerPurpose>, unsigned int>::const_iterator l = m_layers.begin (); l != m_layers.end (); ++l) {
|
||||
for (std::map<std::pair<std::string, LayerPurpose>, unsigned int>::const_iterator l = m_unassigned_layers.begin (); l != m_unassigned_layers.end (); ++l) {
|
||||
|
||||
int dt = 0;
|
||||
switch (l->first.second) {
|
||||
|
|
|
|||
|
|
@ -515,6 +515,16 @@ public:
|
|||
m_separate_groups = f;
|
||||
}
|
||||
|
||||
bool consider_map_file () const
|
||||
{
|
||||
return m_consider_map_file;
|
||||
}
|
||||
|
||||
void set_consider_map_file (bool f)
|
||||
{
|
||||
m_consider_map_file = f;
|
||||
}
|
||||
|
||||
private:
|
||||
bool m_read_all_layers;
|
||||
db::LayerMap m_layer_map;
|
||||
|
|
@ -557,6 +567,7 @@ private:
|
|||
std::string m_special_routing_suffix;
|
||||
int m_special_routing_datatype;
|
||||
bool m_separate_groups;
|
||||
bool m_consider_map_file;
|
||||
std::vector<std::string> m_lef_files;
|
||||
};
|
||||
|
||||
|
|
@ -592,7 +603,32 @@ public:
|
|||
LEFDEFReaderState (const LEFDEFReaderOptions *tc);
|
||||
|
||||
/**
|
||||
* @brief Set the layer map
|
||||
* @brief Provides an explicit layer mapping
|
||||
* This method is used when reading the layer map file.
|
||||
*/
|
||||
void map_layer_explicit (const std::string &n, LayerPurpose purpose, unsigned int layer);
|
||||
|
||||
/**
|
||||
* @brief Provides an explicit layer mapping
|
||||
* If this flag is set, the layer mapping specified in the reader options are ignored.
|
||||
*/
|
||||
void set_explicit_layer_mapping (bool f);
|
||||
|
||||
/**
|
||||
* @brief Reads a map file
|
||||
*/
|
||||
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
|
||||
*/
|
||||
virtual void set_layer_map (const db::LayerMap &lm, bool create_layers)
|
||||
{
|
||||
|
|
@ -601,7 +637,7 @@ public:
|
|||
}
|
||||
|
||||
/**
|
||||
* @brief Get the layer map
|
||||
* @brief Gets the layer map
|
||||
*/
|
||||
const db::LayerMap &layer_map () const
|
||||
{
|
||||
|
|
@ -609,7 +645,7 @@ public:
|
|||
}
|
||||
|
||||
/**
|
||||
* @brief Get the layer map (non-const version)
|
||||
* @brief Gets the layer map (non-const version)
|
||||
*/
|
||||
db::LayerMap &layer_map ()
|
||||
{
|
||||
|
|
@ -655,13 +691,17 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
std::map <std::pair<std::string, LayerPurpose>, unsigned int> m_layers;
|
||||
std::map <std::pair<std::string, LayerPurpose>, std::pair<bool, unsigned int> > m_layers;
|
||||
std::map <std::pair<std::string, LayerPurpose>, unsigned int> m_unassigned_layers;
|
||||
db::LayerMap m_layer_map;
|
||||
bool m_create_layers;
|
||||
bool m_has_explicit_layer_mapping;
|
||||
int m_laynum;
|
||||
std::map<std::string, int> m_default_number;
|
||||
std::map<std::string, db::Cell *> m_via_cells;
|
||||
const LEFDEFReaderOptions *mp_tech_comp;
|
||||
|
||||
std::pair <bool, unsigned int> open_layer_uncached (db::Layout &layout, const std::string &name, LayerPurpose purpose);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
#include "dbLEFImporter.h"
|
||||
#include "dbDEFImporter.h"
|
||||
#include "dbLEFDEFImporter.h"
|
||||
#include "dbLayoutUtils.h"
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
|
@ -77,156 +78,6 @@ 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::LEFDEFReaderState &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"] = "LEFPIN";
|
||||
purpose_translation ["PIN"] = "PIN";
|
||||
purpose_translation ["LEFOBS"] = "OBS";
|
||||
purpose_translation ["SPNET"] = "SPNET";
|
||||
purpose_translation ["NET"] = "NET";
|
||||
purpose_translation ["VIA"] = "VIA";
|
||||
purpose_translation ["BLOCKAGE"] = "BLK";
|
||||
|
||||
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") {
|
||||
|
||||
// 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> 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) {
|
||||
std::string canonical_name = std::string ("(") + *l + ",LABEL)";
|
||||
lm.map (db::LayerProperties (canonical_name), n, db::LayerProperties (layer, datatype, final_name));
|
||||
}
|
||||
++n;
|
||||
|
||||
} 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::vector<std::string> translated_purposes;
|
||||
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 (tl::to_upper_case (*p));
|
||||
if (i != purpose_translation.end ()) {
|
||||
translated_purposes.push_back (i->second);
|
||||
}
|
||||
}
|
||||
|
||||
std::sort (translated_purposes.begin (), translated_purposes.end ());
|
||||
translated_purposes.erase (std::unique (translated_purposes.begin (), translated_purposes.end ()), translated_purposes.end ());
|
||||
std::string final_name = w1 + "." + tl::join (translated_purposes, "/");
|
||||
|
||||
for (std::vector<std::string>::const_iterator p = translated_purposes.begin (); p != translated_purposes.end (); ++p) {
|
||||
std::string canonical_name = std::string ("(") + w1 + "," + *p + ")";
|
||||
lm.map (db::LayerProperties (canonical_name), n, db::LayerProperties (layer, datatype, final_name));
|
||||
}
|
||||
++n;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Imports a .map file present next to the input files
|
||||
*/
|
||||
static void
|
||||
import_map_file_heuristics (const std::string &main_path, db::LEFDEFReaderState &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
|
||||
{
|
||||
|
|
@ -275,7 +126,9 @@ private:
|
|||
|
||||
db::LEFDEFReaderState state (lefdef_options);
|
||||
|
||||
import_map_file_heuristics (m_stream.absolute_path (), state);
|
||||
if (lefdef_options->consider_map_file ()) {
|
||||
state.import_map_file_heuristics (m_stream.absolute_path (), layout);
|
||||
}
|
||||
|
||||
state.prepare (layout);
|
||||
layout.dbu (lefdef_options->dbu ());
|
||||
|
|
|
|||
|
|
@ -461,11 +461,25 @@ gsi::Class<db::LEFDEFReaderOptions> decl_lefdef_config ("db", "LEFDEFReaderConfi
|
|||
"This property has been added in version 0.26.5.\n"
|
||||
) +
|
||||
gsi::method ("separate_groups=", &db::LEFDEFReaderOptions::set_separate_groups, gsi::arg ("flag"),
|
||||
"@brief Gets a value indicating whether to create separate parent cells for individual groups.\n"
|
||||
"@brief Sets a value indicating whether to create separate parent cells for individual groups.\n"
|
||||
"See \\seperate_groups for details about this property.\n"
|
||||
"\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"
|
||||
"\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"
|
||||
"\n"
|
||||
"This property has been added in version 0.26.5.\n"
|
||||
) +
|
||||
gsi::method ("lef_files", &db::LEFDEFReaderOptions::lef_files,
|
||||
"@brief Gets the list technology LEF files to additionally import\n"
|
||||
"Returns a list of path names for technology LEF files to read in addition to the primary file. "
|
||||
|
|
|
|||
|
|
@ -207,17 +207,13 @@
|
|||
<property name="bottomMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Layout database unit</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<widget class="QLabel" name="label_21">
|
||||
<property name="text">
|
||||
<string>Via cell name prefix</string>
|
||||
<item row="0" column="4">
|
||||
<widget class="QLineEdit" name="prefix_via_cellname">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
@ -234,6 +230,34 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1" colspan="4">
|
||||
<widget class="QCheckBox" name="separate_groups">
|
||||
<property name="text">
|
||||
<string>Produce a parent cell for each group</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<widget class="QLabel" name="label_21">
|
||||
<property name="text">
|
||||
<string>Via cell name prefix</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Layout database unit</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_22">
|
||||
<property name="text">
|
||||
<string>Separate groups</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="dbu">
|
||||
<property name="sizePolicy">
|
||||
|
|
@ -244,27 +268,20 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="4">
|
||||
<widget class="QLineEdit" name="prefix_via_cellname">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_25">
|
||||
<property name="text">
|
||||
<string>Consider map files</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="4">
|
||||
<widget class="QCheckBox" name="separate_groups">
|
||||
<item row="2" column="1" colspan="4">
|
||||
<widget class="QCheckBox" name="consider_map_file">
|
||||
<property name="text">
|
||||
<string>Produce a parent cell for each group</string>
|
||||
<string>Look for .map files next to DEF files and use them to map layers</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="3">
|
||||
<widget class="QLabel" name="label_22">
|
||||
<property name="text">
|
||||
<string>Separate groups</string>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
@ -517,13 +534,6 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="5" colspan="2">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Produce ...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="5">
|
||||
<widget class="QCheckBox" name="produce_pins">
|
||||
<property name="text">
|
||||
|
|
@ -764,6 +774,56 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="5" colspan="2">
|
||||
<widget class="QFrame" name="frame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="warn1">
|
||||
<property name="toolTip">
|
||||
<string>Layer assignment is not used if a .map file is present for DEF layer mapping</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="pixmap">
|
||||
<pixmap resource="../../../../lay/lay/layResources.qrc">:/warn_16.png</pixmap>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_26">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Produce ...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
@ -781,10 +841,7 @@
|
|||
<property name="flat">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<property name="leftMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
|
|
@ -797,21 +854,14 @@
|
|||
<property name="bottomMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QCheckBox" name="read_all_cbx">
|
||||
<property name="text">
|
||||
<string>Read all layers (additionally to the ones in the mapping table)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<item row="2" column="1">
|
||||
<widget class="lay::LayerMappingWidget" name="layer_map">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
||||
|
|
@ -833,6 +883,32 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="warn2">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>This table is not used if a .map file is present for DEF layer mapping</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="pixmap">
|
||||
<pixmap resource="../../../../lay/lay/layResources.qrc">:/warn_16.png</pixmap>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="Line" name="line_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
@ -881,12 +957,12 @@
|
|||
<slot>setChecked(bool)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>186</x>
|
||||
<y>598</y>
|
||||
<x>229</x>
|
||||
<y>838</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>155</x>
|
||||
<y>553</y>
|
||||
<x>198</x>
|
||||
<y>701</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
|
|
|
|||
|
|
@ -363,6 +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 ()));
|
||||
|
||||
lay::activate_help_links (help_label);
|
||||
}
|
||||
|
|
@ -450,6 +451,7 @@ 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->clear_lef_files ();
|
||||
for (int i = 0; i < lef_files->count (); ++i) {
|
||||
|
|
@ -510,6 +512,7 @@ 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 ());
|
||||
|
||||
checkbox_changed ();
|
||||
|
||||
|
|
@ -526,6 +529,13 @@ 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 ()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -98,6 +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 ();
|
||||
|
||||
private:
|
||||
tl::weak_ptr<db::Technology> mp_tech;
|
||||
|
|
|
|||
|
|
@ -69,7 +69,15 @@ static void run_test (tl::TestBase *_this, const char *lef_dir, const char *file
|
|||
|
||||
while (! ex.at_end ()) {
|
||||
|
||||
if (ex.test ("def:")) {
|
||||
if (ex.test ("map:")) {
|
||||
|
||||
std::string fn = fn_path, f;
|
||||
ex.read_word_or_quoted (f);
|
||||
fn += f;
|
||||
|
||||
ld.read_map_file (fn, layout);
|
||||
|
||||
} else if (ex.test ("def:")) {
|
||||
|
||||
std::string fn = fn_path, f;
|
||||
ex.read_word_or_quoted (f);
|
||||
|
|
@ -230,6 +238,7 @@ TEST(15)
|
|||
TEST(16)
|
||||
{
|
||||
run_test (_this, "def7", "lef:cells.lef+lef:tech.lef+def:in.def.gz", "au.oas.gz", default_options ());
|
||||
run_test (_this, "def7", "map:in.map+lef:cells.lef+lef:tech.lef+def:in.def.gz", "au_with_map_file.oas.gz", default_options ());
|
||||
}
|
||||
|
||||
TEST(17)
|
||||
|
|
|
|||
|
|
@ -345,6 +345,10 @@ class DBReaders_TestClass < TestBase
|
|||
conf.separate_groups = true
|
||||
assert_equal(conf.separate_groups, true)
|
||||
|
||||
assert_equal(conf.consider_map_file, true)
|
||||
conf.consider_map_file = false
|
||||
assert_equal(conf.consider_map_file, false)
|
||||
|
||||
assert_equal(conf.lef_files.join(","), "")
|
||||
conf.lef_files = [ "u.lef", "v.lef" ]
|
||||
assert_equal(conf.lef_files.join(","), "u.lef,v.lef")
|
||||
|
|
|
|||
Loading…
Reference in New Issue