mirror of https://github.com/KLayout/klayout.git
Some LEF reader fixes based on the complete sample
This commit is contained in:
parent
66a6832594
commit
33c858924f
|
|
@ -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 ()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,7 +404,7 @@ LEFImporter::read_nondefaultrule (db::Layout &layout)
|
|||
// read NONDEFAULTRULE sections
|
||||
std::string n = get ();
|
||||
|
||||
while (! test ("END") || ! test (n)) {
|
||||
while (! test ("END")) {
|
||||
|
||||
if (test ("LAYER")) {
|
||||
|
||||
|
|
@ -419,9 +417,7 @@ LEFImporter::read_nondefaultrule (db::Layout &layout)
|
|||
test (";");
|
||||
m_nondefault_widths[n][l] = std::make_pair (w, w);
|
||||
} else {
|
||||
while (! at_end () && ! test (";")) {
|
||||
take ();
|
||||
}
|
||||
skip_entry ();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -432,12 +428,25 @@ 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
|
||||
|
|
@ -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,44 +1081,105 @@ 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")) {
|
||||
take ();
|
||||
|
|
@ -1094,21 +1187,32 @@ LEFImporter::do_read (db::Layout &layout)
|
|||
|
||||
} 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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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 ();
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -317,6 +317,12 @@ TEST(lef7)
|
|||
run_test (_this, "lef7", "lef:in_tech.lef+lef:in.lef", "au.oas.gz", options);
|
||||
}
|
||||
|
||||
TEST(lef8)
|
||||
{
|
||||
// this is rather a smoke test and throws a number of warnings
|
||||
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 ());
|
||||
|
|
@ -418,6 +424,7 @@ TEST(def15)
|
|||
|
||||
TEST(def16)
|
||||
{
|
||||
// this is rather a smoke test
|
||||
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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue