mirror of https://github.com/KLayout/klayout.git
Fixed DEF layer mapping for compatibility with 0.26
Problem was: general layers (e.g. OUTLINE) were not routed through the layer map.
This commit is contained in:
parent
6eac98907f
commit
b0f25dd61e
|
|
@ -1060,14 +1060,85 @@ LEFDEFReaderState::open_layer (db::Layout &layout, const std::string &n, LayerPu
|
|||
}
|
||||
}
|
||||
|
||||
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::pair <bool, 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;
|
||||
|
||||
|
|
@ -1095,6 +1166,42 @@ LEFDEFReaderState::open_layer_uncached (db::Layout &layout, const std::string &n
|
|||
lp.datatype = 0;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
// employ the layer map to find the target layer
|
||||
std::pair<bool, unsigned int> ll = m_layer_map.logical (lp, layout);
|
||||
|
||||
if (ll.first) {
|
||||
|
||||
// If the layer map provides a target, use that one for the layer
|
||||
const db::LayerProperties *lpp = m_layer_map.target (ll.second);
|
||||
if (lpp) {
|
||||
if (! lpp->name.empty ()) {
|
||||
lp.name = lpp->name;
|
||||
}
|
||||
if (lpp->datatype >= 0) {
|
||||
lp.datatype = lpp->datatype;
|
||||
}
|
||||
if (lpp->layer >= 0) {
|
||||
lp.layer = lpp->layer;
|
||||
}
|
||||
}
|
||||
|
||||
} else if (! m_create_layers) {
|
||||
return std::make_pair (false, 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);
|
||||
|
|
@ -1139,8 +1246,6 @@ LEFDEFReaderState::open_layer_uncached (db::Layout &layout, const std::string &n
|
|||
}
|
||||
}
|
||||
|
||||
// Note: "name" is the decorated name as provided by the tech component's
|
||||
// x_suffix specifications.
|
||||
std::string name_suffix;
|
||||
int dt = 0;
|
||||
|
||||
|
|
@ -1182,8 +1287,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);
|
||||
|
|
@ -1191,21 +1298,31 @@ LEFDEFReaderState::open_layer_uncached (db::Layout &layout, const std::string &n
|
|||
lp.layer = ldef->second;
|
||||
}
|
||||
|
||||
// Route the layer through the layer map, first the decorated name and if there is no mapping, the
|
||||
// undecorated one.
|
||||
std::pair<bool, unsigned int> ll = m_layer_map.logical (name, layout);
|
||||
bool generic_match = false;
|
||||
if (! ll.first) {
|
||||
ll = m_layer_map.logical (n, layout);
|
||||
generic_match = true;
|
||||
}
|
||||
|
||||
if (ll.first) {
|
||||
|
||||
// If the layer map provides a target, use that one for the layer
|
||||
// Datatypes from the target and the tech component's x_datatype specification are additive
|
||||
const db::LayerProperties *lpp = m_layer_map.target (ll.second);
|
||||
if (lpp) {
|
||||
lp = *lpp;
|
||||
if (lp.datatype >= 0) {
|
||||
if (lp.datatype < 0) {
|
||||
lp.datatype = dt;
|
||||
} else if (generic_match) {
|
||||
lp.datatype += dt;
|
||||
}
|
||||
if (lp.name.empty ()) {
|
||||
lp.name = name;
|
||||
} else if (generic_match) {
|
||||
lp.name += name_suffix;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1254,44 +1371,7 @@ LEFDEFReaderState::finish (db::Layout &layout)
|
|||
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;
|
||||
}
|
||||
std::string ps = purpose_to_name (l->first.second.first);
|
||||
|
||||
unsigned int layer_index = l->second.second;
|
||||
db::LayerProperties lp = layout.get_properties (layer_index);
|
||||
|
|
@ -1336,7 +1416,7 @@ LEFDEFReaderState::finish (db::Layout &layout)
|
|||
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,16 +556,151 @@ 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_name_to_ld_target_mapping)
|
||||
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::LayerMap lm_read = run_test (_this, "via_properties", "lef:in.lef+def:in.def", "au.oas.gz", 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)')"
|
||||
)
|
||||
{
|
||||
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(200_lefdef_plugin)
|
||||
|
|
|
|||
Loading…
Reference in New Issue