Merge pull request #1298 from KLayout/lefdef-wip

Lefdef wip
This commit is contained in:
Matthias Köfferlein 2023-02-19 20:29:03 +01:00 committed by GitHub
commit a04f2940ac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 393 additions and 125 deletions

View File

@ -2143,6 +2143,10 @@ ms_extraction (db::EdgeProcessor &ep, bool resolve_holes)
static db::Polygon
do_minkowski_sum (const db::Polygon &a, const db::Edge &b, bool resolve_holes)
{
if (a.begin_hull () == a.end_hull ()) {
return db::Polygon ();
}
db::EdgeProcessor ep;
db::ms_production (a, b.p1 (), b.p2 (), ep);
return db::ms_extraction (ep, resolve_holes);
@ -2161,7 +2165,9 @@ minkowski_sum (const db::Polygon &a, const db::Edge &b, bool rh)
static db::Polygon
do_minkowski_sum (const db::Polygon &a, const db::Polygon &b, bool resolve_holes)
{
tl_assert (a.begin_hull () != a.end_hull ());
if (a.begin_hull () == a.end_hull () || b.begin_hull () == b.end_hull ()) {
return db::Polygon ();
}
db::Vector p0 = *a.begin_hull () - db::Point ();

View File

@ -782,7 +782,7 @@ DEFImporter::read_nets (db::Layout &layout, db::Cell &design, double scale, bool
}
}
while (test ("+")) {
while ((in_subnet && ! at_end ()) || test ("+")) {
bool was_shield = false;
unsigned int mask = 0;
@ -820,6 +820,8 @@ DEFImporter::read_nets (db::Layout &layout, db::Cell &design, double scale, bool
} else {
bool any = false;
bool prefixed = false;
bool can_have_rect_polygon_or_via = true;
@ -831,8 +833,6 @@ DEFImporter::read_nets (db::Layout &layout, db::Cell &design, double scale, bool
can_have_rect_polygon_or_via = test ("+");
}
bool any = false;
if (can_have_rect_polygon_or_via) {
if (test ("SHAPE")) {
take ();
@ -882,22 +882,29 @@ DEFImporter::read_nets (db::Layout &layout, db::Cell &design, double scale, bool
} else if (can_have_rect_polygon_or_via && test ("VIA")) {
// For the via, the masks are encoded in a three-digit number (<mask-top> <mask-cut> <mask_bottom>)
unsigned int mask_top = (mask / 100) % 10;
unsigned int mask_cut = (mask / 10) % 10;
unsigned int mask_bottom = mask % 10;
std::string vn = get ();
db::FTrans ft = get_orient (true /*optional*/);
test ("(");
db::Vector pt = get_vector (scale);
test (")");
while (test ("(")) {
std::map<std::string, ViaDesc>::const_iterator vd = m_via_desc.find (vn);
if (vd != m_via_desc.end ()) {
// TODO: no mask specification here?
db::Cell *cell = reader_state ()->via_cell (vn, nondefaultrule, layout, 0, 0, 0, &m_lef_importer);
if (cell) {
design.insert (db::CellInstArray (db::CellInst (cell->cell_index ()), db::Trans (ft.rot (), pt)));
db::Vector pt = get_vector (scale);
test (")");
std::map<std::string, ViaDesc>::const_iterator vd = m_via_desc.find (vn);
if (vd != m_via_desc.end ()) {
db::Cell *cell = reader_state ()->via_cell (vn, nondefaultrule, layout, mask_bottom, mask_cut, mask_top, &m_lef_importer);
if (cell) {
design.insert (db::CellInstArray (db::CellInst (cell->cell_index ()), db::Trans (ft.rot (), pt)));
}
} else {
warn (tl::to_string (tr ("Invalid via name: ")) + vn);
}
} else {
error (tl::to_string (tr ("Invalid via name: ")) + vn);
}
any = true;
@ -1120,9 +1127,9 @@ DEFImporter::read_vias (db::Layout &layout, db::Cell & /*design*/, double scale)
if (vd.m1.empty () && vd.m2.empty ()) {
// analyze the layers to find the metals
if (routing_layers.size () == 2) {
vd.m1 = routing_layers[0];
vd.m2 = routing_layers[1];
if (routing_layers.size () == 2 || routing_layers.size () == 1) {
vd.m1 = routing_layers.front ();
vd.m2 = routing_layers.back ();
} else {
warn (tl::to_string (tr ("Cannot determine routing layers for via: ")) + n);
}
@ -1204,7 +1211,7 @@ DEFImporter::read_pins (db::Layout &layout, db::Cell &design, double scale)
double x = 0.0, y = 0.0;
while (! at_end () && ! test ("+") && ! test (";")) {
while (! at_end () && ! peek ("+") && ! peek (";")) {
test ("(");
if (! test ("*")) {
@ -1237,8 +1244,36 @@ DEFImporter::read_pins (db::Layout &layout, db::Cell &design, double scale)
} else if (test ("VIA")) {
// TODO: implement
error (tl::to_string (tr ("VIA not supported on pins currently")));
// TODO: clarify - VIA on pins is regarded VIA purpose, not PIN and gives a separate cell
std::string vn = get ();
unsigned int mask = 0;
if (test ("MASK")) {
mask = get_mask (get_long ());
}
while (test ("(")) {
db::Vector pt = get_vector (scale);
test (")");
unsigned int mask_top = (mask / 100) % 10;
unsigned int mask_cut = (mask / 10) % 10;
unsigned int mask_bottom = mask % 10;
std::map<std::string, ViaDesc>::const_iterator vd = m_via_desc.find (vn);
if (vd != m_via_desc.end ()) {
std::string nondefaultrule;
db::Cell *cell = reader_state ()->via_cell (vn, nondefaultrule, layout, mask_bottom, mask_cut, mask_top, &m_lef_importer);
if (cell) {
design.insert (db::CellInstArray (db::CellInst (cell->cell_index ()), db::Trans (pt)));
}
} else {
warn (tl::to_string (tr ("Invalid via name: ")) + vn);
}
}
} else {
while (! peek ("+") && ! peek ("-") && ! peek (";")) {
@ -1391,13 +1426,49 @@ DEFImporter::read_fills (db::Layout &layout, db::Cell &design, double scale)
} else if (test ("VIA")) {
// TODO: implement
warn (tl::to_string (tr ("VIA not supported on fills currently")));
// TODO: clarify - VIA on fill is regarded VIA purpose, not PIN and gives a separate cell
while (! at_end () && ! test (";")) {
take ();
std::string vn = get ();
unsigned int mask = 0;
while (test ("+")) {
if (test ("MASK")) {
mask = get_mask (get_long ());
} else if (test ("OPC")) {
// ignore
} else {
error (tl::to_string (tr ("Expected 'MASK' or 'OPC' inside fill/VIA definition")));
}
}
if (peek ("+") && test ("MASK")) {
mask = get_mask (get_long ());
}
unsigned int mask_top = (mask / 100) % 10;
unsigned int mask_cut = (mask / 10) % 10;
unsigned int mask_bottom = mask % 10;
while (test ("(")) {
db::Vector pt = get_vector (scale);
test (")");
std::map<std::string, ViaDesc>::const_iterator vd = m_via_desc.find (vn);
if (vd != m_via_desc.end ()) {
std::string nondefaultrule;
db::Cell *cell = reader_state ()->via_cell (vn, nondefaultrule, layout, mask_bottom, mask_cut, mask_top, &m_lef_importer);
if (cell) {
design.insert (db::CellInstArray (db::CellInst (cell->cell_index ()), db::Trans (pt)));
}
} else {
warn (tl::to_string (tr ("Invalid via name: ")) + vn);
}
}
test (";");
} else {
error (tl::to_string (tr ("'LAYER' or 'VIA' keyword expected")));
}
@ -1432,7 +1503,7 @@ DEFImporter::read_styles (double scale)
}
m_styles.insert (std::make_pair (sn, db::Polygon ())).first->second.assign_hull (points.begin (), points.end ());
m_styles.insert (std::make_pair (sn, db::Polygon ())).first->second.assign_hull (points.begin (), points.end (), false /*don't compress*/);
}
}

View File

@ -1990,7 +1990,11 @@ LEFDEFImporter::read (tl::InputStream &stream, db::Layout &layout, LEFDEFReaderS
void
LEFDEFImporter::error (const std::string &msg)
{
throw LEFDEFReaderException (msg, int (mp_stream->line_number ()), m_cellname, m_fn);
if (m_sections.empty ()) {
throw LEFDEFReaderException (msg, int (mp_stream->line_number ()), m_cellname, m_fn);
} else {
throw LEFDEFReaderException (msg + tl::sprintf (tl::to_string (tr (" (inside %s)")), tl::join (m_sections, "/")), int (mp_stream->line_number ()), m_cellname, m_fn);
}
}
void
@ -2140,6 +2144,18 @@ LEFDEFImporter::get ()
return r;
}
void
LEFDEFImporter::enter_section (const std::string &name)
{
m_sections.push_back (name);
}
void
LEFDEFImporter::leave_section ()
{
m_sections.pop_back ();
}
const std::string &
LEFDEFImporter::next ()
{

View File

@ -1706,8 +1706,31 @@ private:
db::property_names_id_type m_pin_prop_name_id;
db::LEFDEFReaderOptions m_options;
int m_warn_level;
std::vector<std::string> m_sections;
friend class LEFDEFSection;
const std::string &next ();
void enter_section (const std::string &name);
void leave_section ();
};
class DB_PLUGIN_PUBLIC LEFDEFSection
{
public:
LEFDEFSection (LEFDEFImporter *importer, const std::string &name)
: mp_importer (importer)
{
mp_importer->enter_section (name);
}
~LEFDEFSection ()
{
mp_importer->leave_section ();
}
private:
LEFDEFImporter *mp_importer;
};
class DB_PLUGIN_PUBLIC LEFDEFReader

View File

@ -388,9 +388,7 @@ LEFImporter::read_geometries (GeometryBasedLayoutGenerator *lg, double dbu, Laye
} else if (test ("PROPERTY")) {
// skip properties
while (! at_end () && ! test (";")) {
take ();
}
skip_entry ();
} else {
// stop at unknown token
@ -406,22 +404,20 @@ LEFImporter::read_nondefaultrule (db::Layout &layout)
// read NONDEFAULTRULE sections
std::string n = get ();
while (! test ("END") || ! test (n)) {
while (! at_end () && ! test ("END")) {
if (test ("LAYER")) {
std::string l = get ();
// read the width for the layer
while (! test ("END")) {
while (! at_end () && ! test ("END")) {
if (test ("WIDTH")) {
double w = get_double ();
test (";");
m_nondefault_widths[n][l] = std::make_pair (w, w);
} else {
while (! at_end () && ! test (";")) {
take ();
}
skip_entry ();
}
}
@ -432,18 +428,31 @@ LEFImporter::read_nondefaultrule (db::Layout &layout)
read_viadef (layout, n);
} else {
while (! at_end () && ! test (";")) {
take ();
std::string token = get ();
if (token == "SPACING") {
// read over sections we do not need
while (! at_end () && ! test ("END")) {
skip_entry ();
}
test (token);
} else if (token != ";") {
// read over lines we do not need
skip_entry ();
}
}
}
test (n);
}
void
LEFImporter::read_viadef_by_rule (RuleBasedViaGenerator *vg, ViaDesc &via_desc, const std::string & /*n*/, double dbu)
{
while (! test ("END")) {
while (! at_end () && ! test ("END")) {
double x, y;
@ -557,6 +566,13 @@ LEFImporter::read_viadef_by_geometry (GeometryBasedLayoutGenerator *lg, ViaDesc
get_double ();
test (";");
} else if (test ("FOREIGN")) {
// undocumented
while (! at_end () && ! test (";")) {
take ();
}
} else if (test ("LAYER")) {
layer_name = get ();
@ -631,9 +647,7 @@ LEFImporter::read_viadef_by_geometry (GeometryBasedLayoutGenerator *lg, ViaDesc
} else if (test ("PROPERTY")) {
// skip properties
while (! at_end () && ! test (";")) {
take ();
}
skip_entry ();
} else {
// stop at unknown token
@ -663,7 +677,7 @@ LEFImporter::read_viadef (Layout &layout, const std::string &nondefaultrule)
ViaDesc &via_desc = m_vias[n];
while (test ("DEFAULT") || test ("TOPOFSTACKONLY"))
while (test ("DEFAULT") || test ("TOPOFSTACKONLY") || test("GENERATED"))
;
test (";");
@ -746,55 +760,51 @@ LEFImporter::read_layer (Layout & /*layout*/)
// blocks following a semicolon
take ();
if (test ("FREQUENCY")) {
while (! test ("TABLEENTRIES")) {
while (! at_end () && ! test ("TABLEENTRIES")) {
take ();
}
}
while (! at_end () && ! test (";")) {
take ();
}
skip_entry ();
} else if (test ("PROPERTY")) {
std::string name = get ();
tl::Variant value = get ();
while (! test (";") && ! at_end ()) {
if (name == "LEF58_MINWIDTH") {
std::string name = get ();
tl::Variant value = get ();
// Cadence extension
tl::Extractor ex (value.to_string ());
double v = 0.0;
if (ex.test ("MINWIDTH") && ex.try_read (v)) {
if (ex.test ("WRONGDIRECTION")) {
wmin_wrongdir = v;
} else {
wmin = v;
if (name == "LEF58_MINWIDTH") {
// Cadence extension
tl::Extractor ex (value.to_string ());
double v = 0.0;
if (ex.test ("MINWIDTH") && ex.try_read (v)) {
if (ex.test ("WRONGDIRECTION")) {
wmin_wrongdir = v;
} else {
wmin = v;
}
}
}
} else if (name == "LEF58_WIDTH") {
} else if (name == "LEF58_WIDTH") {
// Cadence extension
tl::Extractor ex (value.to_string ());
double v = 0.0;
if (ex.test ("WIDTH") && ex.try_read (v)) {
if (ex.test ("WRONGDIRECTION")) {
w_wrongdir = v;
} else {
w = v;
// Cadence extension
tl::Extractor ex (value.to_string ());
double v = 0.0;
if (ex.test ("WIDTH") && ex.try_read (v)) {
if (ex.test ("WRONGDIRECTION")) {
w_wrongdir = v;
} else {
w = v;
}
}
}
}
expect (";");
} else {
while (! at_end () && ! test (";")) {
take ();
}
skip_entry ();
}
}
@ -865,6 +875,8 @@ LEFImporter::read_macro (Layout &layout)
} else if (test ("PIN")) {
LEFDEFSection section (this, "PIN");
std::string pn = get ();
std::string dir;
@ -881,6 +893,8 @@ LEFImporter::read_macro (Layout &layout)
} else if (test ("PORT")) {
LEFDEFSection section (this, "PORT");
// produce pin labels
// TODO: put a label on every single object?
std::string label = pn;
@ -916,9 +930,7 @@ LEFImporter::read_macro (Layout &layout)
expect ("END");
} else {
while (! at_end () && ! test (";")) {
take ();
}
skip_entry ();
}
}
@ -926,12 +938,19 @@ LEFImporter::read_macro (Layout &layout)
} else if (test ("FOREIGN")) {
LEFDEFSection section (this, "FOREIGN");
std::string cn = get ();
db::Point vec;
db::FTrans ft;
if (! peek (";")) {
vec = get_point (1.0 / layout.dbu ());
if (test ("(")) {
vec = get_point (1.0 / layout.dbu ());
expect (")");
} else {
vec = get_point (1.0 / layout.dbu ());
}
ft = get_orient (true);
}
@ -940,7 +959,7 @@ LEFImporter::read_macro (Layout &layout)
if (options ().macro_resolution_mode () != 1) {
if (! foreign_name.empty ()) {
error (tl::to_string (tr ("Duplicate FOREIGN definition")));
warn (tl::to_string (tr ("Duplicate FOREIGN definition")));
}
// What is the definition of the FOREIGN transformation?
@ -956,6 +975,8 @@ LEFImporter::read_macro (Layout &layout)
} else if (test ("OBS")) {
LEFDEFSection section (this, "OBS");
if (reader_state ()->tech_comp ()->produce_obstructions ()) {
read_geometries (mg, layout.dbu (), Obstructions);
} else {
@ -966,8 +987,10 @@ LEFImporter::read_macro (Layout &layout)
} else if (test ("DENSITY")) {
LEFDEFSection section (this, "DENSITY");
// read over DENSITY statements
while (! test ("END")) {
while (! at_end () && ! test ("END")) {
if (test ("LAYER")) {
get ();
expect (";");
@ -980,17 +1003,27 @@ LEFImporter::read_macro (Layout &layout)
}
}
expect ("END");
} else if (test ("FIXEDMASK")) {
mg->set_fixedmask (true);
expect (";");
} else {
while (! at_end () && ! test (";")) {
take ();
std::string token = get ();
LEFDEFSection section (this, token);
if (token == "TIMING") {
// read over sections we do not need
while (! at_end () && ! test ("END")) {
skip_entry ();
}
test (token);
} else if (token != ";") {
// read over lines we do not need
skip_entry ();
}
}
}
@ -1031,17 +1064,16 @@ LEFImporter::do_read (db::Layout &layout)
} else if (test ("UNITS")) {
// read over SPACING sections
while (! test ("END")) {
LEFDEFSection section (this, "UNITS");
while (! at_end () && ! test ("END")) {
if (test ("DATABASE")) {
expect ("MICRONS");
// TODO: what to do with that value
/* dbu_mic = */ get_double ();
expect (";");
} else {
while (! at_end () && ! test (";")) {
take ();
}
skip_entry ();
}
}
@ -1049,66 +1081,138 @@ LEFImporter::do_read (db::Layout &layout)
} else if (test ("SPACING")) {
LEFDEFSection section (this, "SPACING");
// read over SPACING sections
while (! test ("END") || ! test ("SPACING")) {
take ();
while (! at_end () && ! test ("END")) {
skip_entry ();
}
test ("SPACING");
} else if (test ("PROPERTYDEFINITIONS")) {
LEFDEFSection section (this, "PROPERTYDEFINITIONS");
// read over PROPERTYDEFINITIONS sections
while (! test ("END") || ! test ("PROPERTYDEFINITIONS")) {
take ();
while (! at_end () && ! test ("END")) {
skip_entry ();
}
test ("PROPERTYDEFINITIONS");
} else if (test ("NONDEFAULTRULE")) {
LEFDEFSection section (this, "NONDEFAULTRULE");
read_nondefaultrule (layout);
} else if (test ("SITE")) {
// read over SITE sections
LEFDEFSection section (this, "NONDEFAULTRULE");
// read over SITE or VIARULE sections
std::string n = get ();
while (! test ("END") || ! test (n)) {
take ();
while (! at_end () && ! test ("END")) {
skip_entry ();
}
test (n);
} else if (test ("VIARULE")) {
// read over VIARULE sections
LEFDEFSection section (this, "VIARULE");
// read over SITE or VIARULE sections
std::string n = get ();
while (! test ("END") || ! test (n)) {
take ();
while (! at_end () && ! test ("END")) {
skip_entry ();
}
test (n);
} else if (test ("NOISETABLE")) {
LEFDEFSection section (this, "NOISETABLE");
// read over NOISETABLE sections
while (! at_end () && ! test ("END")) {
skip_entry ();
}
test ("NOISETABLE");
} else if (test ("IRDROP")) {
LEFDEFSection section (this, "IRDROP");
// read over IRDROP sections
while (! at_end () && ! test ("END")) {
skip_entry ();
}
test ("IRDROP");
} else if (test ("ARRAY")) {
LEFDEFSection section (this, "ARRAY");
// read over ARRAY sections
std::string n = get ();
while (! at_end () && ! test ("END")) {
if (test ("FLOORPLAN")) {
while (! at_end () && ! test ("END")) {
skip_entry ();
}
} else {
skip_entry ();
}
}
test (n);
} else if (test ("VIA")) {
LEFDEFSection section (this, "VIA");
read_viadef (layout, std::string ());
} else if (test ("BEGINEXT")) {
LEFDEFSection section (this, "BEGINEXT");
// read over BEGINEXT sections
while (! test ("ENDEXT")) {
while (! at_end () && ! test ("ENDEXT")) {
take ();
}
} else if (test ("LAYER")) {
LEFDEFSection section (this, "LAYER");
read_layer (layout);
} else if (test ("MACRO")) {
LEFDEFSection section (this, "MACRO");
read_macro (layout);
} else {
while (! at_end () && ! test (";")) {
take ();
}
// read over entries we do not need
skip_entry ();
}
}
}
void
LEFImporter::skip_entry ()
{
while (! at_end () && ! test (";")) {
take ();
}
}
void
LEFImporter::finish_lef (db::Layout &layout)
{

View File

@ -152,6 +152,7 @@ private:
void read_viadef_by_geometry (GeometryBasedLayoutGenerator *lg, ViaDesc &desc, const std::string &n, double dbu);
void read_layer (Layout &layout);
void read_macro (Layout &layout);
void skip_entry ();
};
}

View File

@ -277,81 +277,88 @@ static void run_test2 (tl::TestBase *_this, const char *lef_dir, const char *fil
}
}
TEST(1)
TEST(lef1)
{
run_test (_this, "lef1", "lef:in.lef", 0, default_options ());
}
TEST(2)
TEST(lef2)
{
// Also tests ability of plugin to properly read LEF
run_test (_this, "lef2", "read:in.lef", "au.oas.gz", default_options ());
}
TEST(3)
TEST(lef3)
{
db::LEFDEFReaderOptions options = default_options ();
options.set_cell_outline_layer ("OUTLINE (2/0)");
run_test (_this, "lef3", "lef:in.lef", "au.oas.gz", options);
}
TEST(4)
TEST(lef4)
{
run_test (_this, "lef4", "lef:in.lef", 0, default_options ());
}
TEST(5)
TEST(lef5)
{
run_test (_this, "lef5", "lef:in.lef", 0, default_options ());
}
TEST(6)
TEST(lef6)
{
run_test (_this, "lef6", "lef:in.lef", 0, default_options ());
}
TEST(7)
TEST(lef7)
{
db::LEFDEFReaderOptions options = default_options ();
options.set_cell_outline_layer ("OUTLINE (8/0)");
run_test (_this, "lef7", "lef:in_tech.lef+lef:in.lef", "au.oas.gz", options);
}
TEST(10)
TEST(lef8)
{
// this is rather a smoke test and throws a number of warnings
// (complete example)
run_test (_this, "lef8", "lef:tech.lef+lef:a.lef", "au.oas.gz", default_options ());
}
TEST(def1)
{
run_test (_this, "def1", "lef:in.lef+def:in.def", "au2.oas.gz", default_options ());
}
TEST(11)
TEST(def2)
{
db::LEFDEFReaderOptions options = default_options ();
options.set_cell_outline_layer ("OUTLINE (10/0)");
run_test (_this, "def2", "lef:0.lef+lef:1.lef+def:in.def.gz", "au.oas.gz", options);
}
TEST(12)
TEST(def3)
{
db::LEFDEFReaderOptions options = default_options ();
options.set_cell_outline_layer ("OUTLINE (13/0)");
run_test (_this, "def3", "lef:in.lef+def:in.def", "au.oas.gz", options);
}
TEST(13)
TEST(def4)
{
run_test (_this, "def4", "lef:in.lef+def:in.def", "au2.oas.gz", default_options ());
}
TEST(14)
TEST(def5)
{
run_test (_this, "def5", "lef:in.lef+def:in.def", "au.oas.gz", default_options ());
}
TEST(15)
TEST(def6)
{
run_test (_this, "def6", "lef:cells.lef+lef:tech.lef+def:in.def.gz", "au-new.oas.gz", default_options ());
}
TEST(16)
TEST(def7)
{
db::LEFDEFReaderOptions options = default_options ();
options.set_placement_blockage_layer ("PLACEMENT_BLK (11/0)");
@ -361,12 +368,12 @@ TEST(16)
run_test (_this, "def7", "map:in.map+lef:cells.lef+lef:tech.lef+def:in.def.gz", "au2_with_map_file-new.oas.gz", options);
}
TEST(17)
TEST(def8)
{
run_test (_this, "def8", "lef:tech.lef+def:in.def", "au.oas.gz", default_options ());
}
TEST(18)
TEST(def9)
{
db::LEFDEFReaderOptions options = default_options ();
options.set_separate_groups (true);
@ -375,47 +382,56 @@ TEST(18)
run_test (_this, "def9", "lef:tech.lef+lef:cells_modified.lef+def:in.def", "au_nogroups-new.oas.gz", default_options ());
}
TEST(19)
TEST(def10)
{
db::LEFDEFReaderOptions opt = default_options ();
opt.set_cell_outline_layer ("OUTLINE (2/0)");
run_test (_this, "def10", "def:in.def", "au.oas.gz", opt);
}
TEST(20)
TEST(def11)
{
db::LEFDEFReaderOptions opt = default_options ();
opt.set_cell_outline_layer ("OUTLINE (12/0)");
run_test (_this, "def11", "lef:test.lef+def:test.def", "au.oas.gz", opt);
}
TEST(21)
TEST(def12)
{
db::LEFDEFReaderOptions opt = default_options ();
opt.set_cell_outline_layer ("OUTLINE (20/0)");
run_test (_this, "def12", "lef:test.lef+def:test.def", "au-new.oas.gz", opt);
}
TEST(22)
TEST(def13)
{
db::LEFDEFReaderOptions opt = default_options ();
run_test (_this, "def13", "map:test.map+lef:test.lef_5.8+def:top.def.gz", "au2.oas.gz", opt);
}
TEST(23)
TEST(def14)
{
db::LEFDEFReaderOptions opt = default_options ();
opt.set_macro_resolution_mode (1);
run_test (_this, "def14", "map:test.map+lef:tech.lef+lef:stdlib.lef+def:test.def", "au.oas.gz", opt);
}
TEST(24)
TEST(def15)
{
db::LEFDEFReaderOptions opt = default_options ();
opt.set_macro_resolution_mode (1);
run_test (_this, "def15", "map:test.map+lef:tech.lef+def:test.def", "au2.oas.gz", opt);
}
TEST(def16)
{
// this is rather a smoke test
// (complete example)
db::LEFDEFReaderOptions opt = default_options ();
opt.set_macro_resolution_mode (1);
run_test (_this, "def16", "lef:a.lef+lef:tech.lef+def:a.def", "au.oas.gz", opt);
}
TEST(100)
{
run_test (_this, "issue-172", "lef:in.lef+def:in.def", "au.oas.gz", default_options (), false);
@ -954,3 +970,9 @@ TEST(205_lef_resistance)
run_test (_this, "issue-1214", "read:merged.nom.lef", "au.oas.gz", lefdef_opt, false);
}
// issue 1282
TEST(206_lef_spacing)
{
run_test (_this, "issue-1282", "read:a.lef", 0, default_options (), false);
}

25
testdata/lefdef/issue-1282/a.lef vendored Normal file
View File

@ -0,0 +1,25 @@
VERSION 5.4 ;
NAMESCASESENSITIVE ON ;
BUSBITCHARS "[]" ;
DIVIDERCHAR "/" ;
NOWIREEXTENSIONATPIN OFF ;
UNITS
DATABASE MICRONS 1000 ;
END UNITS
NONDEFAULTRULE DOUBLESPACE
LAYER M1
WIDTH 0.16 ;
SPACING 0.36 ;
END M1
# klayout 0.28.5 lef reader get's confused by the SPACING in NONDEFAULTRULE
SPACING
SAMENET M1 M1 0.36 ;
END SPACING
END DOUBLESPACE
END LIBRARY

Binary file not shown.

Binary file not shown.

Binary file not shown.