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:
Matthias Koefferlein 2020-11-21 20:39:31 +01:00
parent 6eac98907f
commit b0f25dd61e
2 changed files with 277 additions and 55 deletions

View File

@ -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;
}

View File

@ -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)