WIP: starting MAG writer.

This commit is contained in:
Matthias Koefferlein 2019-11-27 22:33:50 +01:00
parent a980332c76
commit 5c217b90b5
12 changed files with 73 additions and 171 deletions

View File

@ -107,7 +107,7 @@ CIFWriter::write (db::Layout &layout, tl::OutputStream &stream, const db::SaveLa
strftime(timestr, sizeof (timestr), "%F %T", &tt); strftime(timestr, sizeof (timestr), "%F %T", &tt);
// Write header // Write header
*this << "(CIF file written " << (const char *)timestr << " by KLayout);" << endl; *this << "(CIF file written " << (const char *)timestr << " by KLayout);" << m_endl;
// TODO: this can be done more intelligently .. // TODO: this can be done more intelligently ..
int tl_scale_divider; int tl_scale_divider;
@ -136,8 +136,8 @@ CIFWriter::write (db::Layout &layout, tl::OutputStream &stream, const db::SaveLa
double sf = 1.0; double sf = 1.0;
*this << "DS " << cell_index << " " << tl_scale_denom << " " << tl_scale_divider << ";" << endl; *this << "DS " << cell_index << " " << tl_scale_denom << " " << tl_scale_divider << ";" << m_endl;
*this << "9 " << tl::to_word_or_quoted_string (layout.cell_name (*cell)) << ";" << endl; *this << "9 " << tl::to_word_or_quoted_string (layout.cell_name (*cell)) << ";" << m_endl;
// instances // instances
for (db::Cell::const_iterator inst = cref.begin (); ! inst.at_end (); ++inst) { for (db::Cell::const_iterator inst = cref.begin (); ! inst.at_end (); ++inst) {
@ -195,7 +195,7 @@ CIFWriter::write (db::Layout &layout, tl::OutputStream &stream, const db::SaveLa
*this << " T" << d.x() << xy_sep () << d.y(); *this << " T" << d.x() << xy_sep () << d.y();
*this << ";" << endl; *this << ";" << m_endl;
} }
@ -219,7 +219,7 @@ CIFWriter::write (db::Layout &layout, tl::OutputStream &stream, const db::SaveLa
} }
// end of cell // end of cell
*this << "DF;" << endl; *this << "DF;" << m_endl;
} }
@ -232,7 +232,7 @@ CIFWriter::write (db::Layout &layout, tl::OutputStream &stream, const db::SaveLa
std::map<db::cell_index_type, int>::const_iterator cif_index = db_to_cif_index_map.find (*cell); std::map<db::cell_index_type, int>::const_iterator cif_index = db_to_cif_index_map.find (*cell);
tl_assert(cif_index != db_to_cif_index_map.end ()); tl_assert(cif_index != db_to_cif_index_map.end ());
*this << "C" << cif_index->second << ";" << endl; *this << "C" << cif_index->second << ";" << m_endl;
} }
@ -241,7 +241,7 @@ CIFWriter::write (db::Layout &layout, tl::OutputStream &stream, const db::SaveLa
} }
// end of file // end of file
*this << "E" << endl; *this << "E" << m_endl;
m_progress.set (mp_stream->pos ()); m_progress.set (mp_stream->pos ());
@ -252,7 +252,7 @@ CIFWriter::emit_layer()
{ {
if (m_needs_emit) { if (m_needs_emit) {
m_needs_emit = false; m_needs_emit = false;
*this << "L " << tl::to_word_or_quoted_string(m_layer.name, "0123456789_.$") << ";" << endl; *this << "L " << tl::to_word_or_quoted_string(m_layer.name, "0123456789_.$") << ";" << m_endl;
} }
} }
@ -271,7 +271,7 @@ CIFWriter::write_texts (const db::Layout &layout, const db::Cell &cell, unsigned
double h = shape->text_size () * layout.dbu (); double h = shape->text_size () * layout.dbu ();
db::Vector p (shape->text_trans ().disp () * sf); db::Vector p (shape->text_trans ().disp () * sf);
*this << " " << p.x() << xy_sep () << p.y () << " " << h << ";" << endl; *this << " " << p.x() << xy_sep () << p.y () << " " << h << ";" << m_endl;
++shape; ++shape;
@ -324,7 +324,7 @@ CIFWriter::write_polygon (const db::Polygon &polygon, double sf)
db::Point pp (*p * sf); db::Point pp (*p * sf);
*this << " " << pp.x () << xy_sep () << pp.y (); *this << " " << pp.x () << xy_sep () << pp.y ();
} }
*this << ";" << endl; *this << ";" << m_endl;
} }
void void
@ -338,7 +338,7 @@ CIFWriter::write_boxes (const db::Layout & /*layout*/, const db::Cell &cell, uns
emit_layer (); emit_layer ();
db::Box b (shape->bbox () * sf); db::Box b (shape->bbox () * sf);
*this << "B " << b.width () << " " << b.height () << " " << b.center ().x () << xy_sep () << b.center ().y () << ";" << endl; *this << "B " << b.width () << " " << b.height () << " " << b.center ().x () << xy_sep () << b.center ().y () << ";" << m_endl;
++shape; ++shape;
@ -411,13 +411,13 @@ CIFWriter::write_paths (const db::Layout & /*layout*/, const db::Cell &cell, uns
db::Point pp (*shape->begin_point () * sf); db::Point pp (*shape->begin_point () * sf);
*this << " " << pp.x () << xy_sep () << pp.y (); *this << " " << pp.x () << xy_sep () << pp.y ();
*this << ";" << endl; *this << ";" << m_endl;
} else if (path_type >= 0 && npts > 1) { } else if (path_type >= 0 && npts > 1) {
emit_layer (); emit_layer ();
*this << "98 " << path_type << ";" << endl; *this << "98 " << path_type << ";" << m_endl;
*this << "W " << long (floor (0.5 + sf * shape->path_width ())); *this << "W " << long (floor (0.5 + sf * shape->path_width ()));
@ -426,7 +426,7 @@ CIFWriter::write_paths (const db::Layout & /*layout*/, const db::Cell &cell, uns
*this << " " << pp.x () << xy_sep () << pp.y (); *this << " " << pp.x () << xy_sep () << pp.y ();
} }
*this << ";" << endl; *this << ";" << m_endl;
} else { } else {
db::Polygon poly; db::Polygon poly;

View File

@ -66,7 +66,7 @@ private:
tl::OutputStream *mp_stream; tl::OutputStream *mp_stream;
CIFWriterOptions m_options; CIFWriterOptions m_options;
tl::AbsoluteProgress m_progress; tl::AbsoluteProgress m_progress;
endl_tag endl; endl_tag m_endl;
db::LayerProperties m_layer; db::LayerProperties m_layer;
bool m_needs_emit; bool m_needs_emit;

View File

@ -212,7 +212,7 @@ static bool get_cif_blank_separator (const db::SaveLayoutOptions *options)
return options->get_options<db::CIFWriterOptions> ().blank_separator; return options->get_options<db::CIFWriterOptions> ().blank_separator;
} }
// extend lay::SaveLayoutOptions with the GDS2 options // extend lay::SaveLayoutOptions with the CIF options
static static
gsi::ClassExt<db::SaveLayoutOptions> cif_writer_options ( gsi::ClassExt<db::SaveLayoutOptions> cif_writer_options (
gsi::method_ext ("cif_dummy_calls=", &set_cif_dummy_calls, gsi::method_ext ("cif_dummy_calls=", &set_cif_dummy_calls,

View File

@ -83,7 +83,7 @@ public:
virtual tl::XMLElementBase *xml_reader_options_element () const virtual tl::XMLElementBase *xml_reader_options_element () const
{ {
return new db::ReaderOptionsXMLElement<db::MAGReaderOptions> ("cif", return new db::ReaderOptionsXMLElement<db::MAGReaderOptions> ("mag",
tl::make_member (&db::MAGReaderOptions::lambda, "lambda") + tl::make_member (&db::MAGReaderOptions::lambda, "lambda") +
tl::make_member (&db::MAGReaderOptions::dbu, "dbu") + tl::make_member (&db::MAGReaderOptions::dbu, "dbu") +
tl::make_member (&db::MAGReaderOptions::layer_map, "layer-map") + tl::make_member (&db::MAGReaderOptions::layer_map, "layer-map") +
@ -98,12 +98,9 @@ public:
virtual tl::XMLElementBase *xml_writer_options_element () const virtual tl::XMLElementBase *xml_writer_options_element () const
{ {
// @@@ return new db::WriterOptionsXMLElement<db::MAGWriterOptions> ("mag",
return new db::WriterOptionsXMLElement<db::MAGWriterOptions> ("cif", tl::make_member (&db::MAGWriterOptions::lambda, "lambda")
tl::make_member (&db::MAGWriterOptions::dummy_calls, "dummy-calls") +
tl::make_member (&db::MAGWriterOptions::blank_separator, "blank-separator")
); );
// @@@
} }
}; };

View File

@ -146,24 +146,19 @@ public:
* @brief The constructor * @brief The constructor
*/ */
MAGWriterOptions () MAGWriterOptions ()
: dummy_calls (false), blank_separator (false) : lambda (0.0)
{ {
// .. nothing yet .. // .. nothing yet ..
} }
/** /**
* @brief A flag indicating whether dummy calls shall be written * @brief Specifies the lambda value for writing
* If this flag is true, the writer will produce dummy cell calls on global *
* level for all top cells. * The lambda value is the basic scaling parameter.
* If this value is set to 0 or negative, the lambda value stored in the layout
* is used (meta data "lambda").
*/ */
bool dummy_calls; double lambda;
/**
* @brief A flag indicating whether to use blanks as x/y separators
* If this flag is true, blank characters will be used to separate x and y values.
* Otherwise comma characters will be used.
*/
bool blank_separator;
/** /**
* @brief Implementation of FormatSpecificWriterOptions * @brief Implementation of FormatSpecificWriterOptions

View File

@ -283,7 +283,7 @@ MAGReader::do_read_part (db::Layout &layout, db::cell_index_type cell_index, tl:
error (tl::to_string (tr ("Could not find 'magic' header line - is this a MAGIC file?"))); error (tl::to_string (tr ("Could not find 'magic' header line - is this a MAGIC file?")));
} }
layout.add_meta_info (db::MetaInfo ("magic_lambda", "MAGIC lambda value", tl::to_string (m_lambda))); layout.add_meta_info (db::MetaInfo ("lambda", "lambda value (tech scaling)", tl::to_string (m_lambda)));
bool valid_layer = false; bool valid_layer = false;
unsigned int current_layer = 0; unsigned int current_layer = 0;

View File

@ -37,50 +37,19 @@ namespace db
MAGWriter::MAGWriter () MAGWriter::MAGWriter ()
: mp_stream (0), : mp_stream (0),
m_progress (tl::to_string (tr ("Writing MAG file")), 10000), m_progress (tl::to_string (tr ("Writing Magic file")), 10000)
m_needs_emit (false)
{ {
m_progress.set_format (tl::to_string (tr ("%.0f MB"))); m_progress.set_format (tl::to_string (tr ("%.0f MB")));
m_progress.set_unit (1024 * 1024); m_progress.set_unit (1024 * 1024);
} }
MAGWriter &
MAGWriter::operator<<(const char *s)
{
mp_stream->put(s, strlen(s));
return *this;
}
MAGWriter &
MAGWriter::operator<<(const std::string &s)
{
mp_stream->put(s.c_str(), s.size());
return *this;
}
MAGWriter &
MAGWriter::operator<<(endl_tag)
{
#ifdef _WIN32
*this << "\r\n";
#else
*this << "\n";
#endif
return *this;
}
const char *
MAGWriter::xy_sep () const
{
return m_options.blank_separator ? " " : ",";
}
void void
MAGWriter::write (db::Layout &layout, tl::OutputStream &stream, const db::SaveLayoutOptions &options) MAGWriter::write (db::Layout &layout, tl::OutputStream &stream, const db::SaveLayoutOptions &options)
{ {
m_options = options.get_options<MAGWriterOptions> (); m_options = options.get_options<MAGWriterOptions> ();
mp_stream = &stream; mp_stream = &stream;
#if 0 // @@@
// compute the scale factor to get to the 10 nm basic database unit of MAG // compute the scale factor to get to the 10 nm basic database unit of MAG
double tl_scale = options.scale_factor () * layout.dbu () / 0.01; double tl_scale = options.scale_factor () * layout.dbu () / 0.01;
@ -242,11 +211,12 @@ MAGWriter::write (db::Layout &layout, tl::OutputStream &stream, const db::SaveLa
// end of file // end of file
*this << "E" << endl; *this << "E" << endl;
#endif
m_progress.set (mp_stream->pos ()); m_progress.set (mp_stream->pos ());
} }
#if 0 // @@@
void void
MAGWriter::emit_layer() MAGWriter::emit_layer()
{ {
@ -440,6 +410,7 @@ MAGWriter::write_paths (const db::Layout & /*layout*/, const db::Cell &cell, uns
} }
} }
#endif
} }

View File

@ -66,28 +66,6 @@ private:
tl::OutputStream *mp_stream; tl::OutputStream *mp_stream;
MAGWriterOptions m_options; MAGWriterOptions m_options;
tl::AbsoluteProgress m_progress; tl::AbsoluteProgress m_progress;
endl_tag endl;
db::LayerProperties m_layer;
bool m_needs_emit;
MAGWriter &operator<<(const char *s);
MAGWriter &operator<<(const std::string &s);
MAGWriter &operator<<(endl_tag);
template<class X> MAGWriter &operator<<(const X &x)
{
return (*this << tl::to_string(x));
}
void write_texts (const db::Layout &layout, const db::Cell &cell, unsigned int layer, double tl_scale);
void write_polygons (const db::Layout &layout, const db::Cell &cell, unsigned int layer, double tl_scale);
void write_polygon (const db::Polygon &polygon, double tl_scale);
void write_boxes (const db::Layout &layout, const db::Cell &cell, unsigned int layer, double tl_scale);
void write_paths (const db::Layout &layout, const db::Cell &cell, unsigned int layer, double tl_scale);
void write_edges (const db::Layout &layout, const db::Cell &cell, unsigned int layer, double tl_scale);
const char *xy_sep () const;
void emit_layer();
}; };
} // namespace db } // namespace db

View File

@ -236,53 +236,32 @@ gsi::ClassExt<db::LoadLayoutOptions> mag_reader_options (
// --------------------------------------------------------------- // ---------------------------------------------------------------
// gsi Implementation of specific methods // gsi Implementation of specific methods
static void set_mag_dummy_calls (db::SaveLayoutOptions *options, bool f) static void set_mag_lambda_w (db::SaveLayoutOptions *options, double f)
{ {
options->get_options<db::MAGWriterOptions> ().dummy_calls = f; options->get_options<db::MAGWriterOptions> ().lambda = f;
} }
static bool get_mag_dummy_calls (const db::SaveLayoutOptions *options) static double get_mag_lambda_w (const db::SaveLayoutOptions *options)
{ {
return options->get_options<db::MAGWriterOptions> ().dummy_calls; return options->get_options<db::MAGWriterOptions> ().lambda;
} }
static void set_mag_blank_separator (db::SaveLayoutOptions *options, bool f) // extend lay::SaveLayoutOptions with the MAG options
{
options->get_options<db::MAGWriterOptions> ().blank_separator = f;
}
static bool get_mag_blank_separator (const db::SaveLayoutOptions *options)
{
return options->get_options<db::MAGWriterOptions> ().blank_separator;
}
// extend lay::SaveLayoutOptions with the GDS2 options
static static
gsi::ClassExt<db::SaveLayoutOptions> mag_writer_options ( gsi::ClassExt<db::SaveLayoutOptions> mag_writer_options (
gsi::method_ext ("mag_dummy_calls=", &set_mag_dummy_calls, gsi::method_ext ("mag_lambda=", &set_mag_lambda_w, gsi::arg ("lambda"),
"@brief Sets a flag indicating whether dummy calls shall be written\n" "@brief Specifies the lambda value to used for writing\n"
"If this property is set to true, dummy calls will be written in the top level entity " "\n"
"of the MAG file calling every top cell.\n" "The lamdba value is the basic unit of the layout.\n"
"This option is useful for enhanced compatibility with other tools.\n" "The layout is brought to units of this value. If the layout is not on-grid on this unit, snapping will happen. "
"\nThis property has been added in version 0.23.10.\n" "If the value is less or equal to zero, KLayout will use the lambda value stored inside the layout (set by a previous read operation "
"of a MAGIC file).\n"
"\nThis property has been added in version 0.26.2.\n"
) + ) +
gsi::method_ext ("mag_dummy_calls?|#mag_dummy_calls", &get_mag_dummy_calls, gsi::method_ext ("mag_lambda", &get_mag_lambda_w,
"@brief Gets a flag indicating whether dummy calls shall be written\n" "@brief Get the lambda value\n"
"See \\mag_dummy_calls= method for a description of that property." "See \\mag_lambda= method for a description of this attribute."
"\nThis property has been added in version 0.23.10.\n" "\nThis property has been added in version 0.26.2.\n"
"\nThe predicate version (mag_blank_separator?) has been added in version 0.25.1.\n"
) +
gsi::method_ext ("mag_blank_separator=", &set_mag_blank_separator,
"@brief Sets a flag indicating whether blanks shall be used as x/y separator characters\n"
"If this property is set to true, the x and y coordinates are separated with blank characters "
"rather than comma characters."
"\nThis property has been added in version 0.23.10.\n"
) +
gsi::method_ext ("mag_blank_separator?|#mag_blank_separator", &get_mag_blank_separator,
"@brief Gets a flag indicating whether blanks shall be used as x/y separator characters\n"
"See \\mag_blank_separator= method for a description of that property."
"\nThis property has been added in version 0.23.10.\n"
"\nThe predicate version (mag_blank_separator?) has been added in version 0.25.1.\n"
), ),
"" ""
); );

View File

@ -35,50 +35,27 @@
<string>CIF Writer Options</string> <string>CIF Writer Options</string>
</property> </property>
<layout class="QGridLayout" name="gridLayout"> <layout class="QGridLayout" name="gridLayout">
<property name="leftMargin">
<number>9</number>
</property>
<property name="topMargin">
<number>9</number>
</property>
<property name="rightMargin">
<number>9</number>
</property>
<property name="bottomMargin">
<number>9</number>
</property>
<item row="0" column="1"> <item row="0" column="1">
<widget class="QCheckBox" name="blank_separator_cbx"> <widget class="QLineEdit" name="lambda_le"/>
<property name="sizePolicy"> </item>
<sizepolicy hsizetype="Expanding" vsizetype="Fixed"> <item row="0" column="2">
<horstretch>0</horstretch> <widget class="QLabel" name="label">
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text"> <property name="text">
<string>If checked, a blank character is used as x/y coordinate <string>Micron</string>
separator. Otherweise a comma is used.</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="0"> <item row="0" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Lambda value</string>
</property>
</widget>
</item>
<item row="1" column="1" colspan="2">
<widget class="QLabel" name="label_2"> <widget class="QLabel" name="label_2">
<property name="text"> <property name="text">
<string>Blank as x/y separator</string> <string>Leave this value empty to take the lambda value stored in the layout</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Dummy cell calls</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="dummy_calls_cbx">
<property name="text">
<string>If checked, dummy cell calls are added on global level</string>
</property> </property>
</widget> </widget>
</item> </item>

View File

@ -55,8 +55,11 @@ MAGWriterOptionPage::setup (const db::FormatSpecificWriterOptions *o, const db::
{ {
const db::MAGWriterOptions *options = dynamic_cast<const db::MAGWriterOptions *> (o); const db::MAGWriterOptions *options = dynamic_cast<const db::MAGWriterOptions *> (o);
if (options) { if (options) {
mp_ui->dummy_calls_cbx->setChecked (options->dummy_calls); if (options->lambda <= 0.0) {
mp_ui->blank_separator_cbx->setChecked (options->blank_separator); mp_ui->lambda_le->setText (QString ());
} else {
mp_ui->lambda_le->setText (tl::to_qstring (tl::to_string (options->lambda)));
}
} }
} }
@ -65,8 +68,11 @@ MAGWriterOptionPage::commit (db::FormatSpecificWriterOptions *o, const db::Techn
{ {
db::MAGWriterOptions *options = dynamic_cast<db::MAGWriterOptions *> (o); db::MAGWriterOptions *options = dynamic_cast<db::MAGWriterOptions *> (o);
if (options) { if (options) {
options->dummy_calls = mp_ui->dummy_calls_cbx->isChecked (); QString l = mp_ui->lambda_le->text ().trimmed ();
options->blank_separator = mp_ui->blank_separator_cbx->isChecked (); options->lambda = 0.0;
if (! l.isEmpty ()) {
tl::from_string (tl::to_string (l), options->lambda);
}
} }
} }

View File

@ -97,8 +97,7 @@ static void run_test (tl::TestBase *_this, const std::string &base, const char *
tl::OutputStream stream (tmp_cif_file); tl::OutputStream stream (tmp_cif_file);
db::MAGWriterOptions *opt = new db::MAGWriterOptions(); db::MAGWriterOptions *opt = new db::MAGWriterOptions();
opt->dummy_calls = dummy_calls; opt->lambda = 0.5;
opt->blank_separator = blank_sep;
db::MAGWriter writer; db::MAGWriter writer;
db::SaveLayoutOptions options; db::SaveLayoutOptions options;