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);
// 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 ..
int tl_scale_divider;
@ -136,8 +136,8 @@ CIFWriter::write (db::Layout &layout, tl::OutputStream &stream, const db::SaveLa
double sf = 1.0;
*this << "DS " << cell_index << " " << tl_scale_denom << " " << tl_scale_divider << ";" << endl;
*this << "9 " << tl::to_word_or_quoted_string (layout.cell_name (*cell)) << ";" << 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)) << ";" << m_endl;
// instances
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 << ";" << endl;
*this << ";" << m_endl;
}
@ -219,7 +219,7 @@ CIFWriter::write (db::Layout &layout, tl::OutputStream &stream, const db::SaveLa
}
// 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);
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
*this << "E" << endl;
*this << "E" << m_endl;
m_progress.set (mp_stream->pos ());
@ -252,7 +252,7 @@ CIFWriter::emit_layer()
{
if (m_needs_emit) {
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 ();
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;
@ -324,7 +324,7 @@ CIFWriter::write_polygon (const db::Polygon &polygon, double sf)
db::Point pp (*p * sf);
*this << " " << pp.x () << xy_sep () << pp.y ();
}
*this << ";" << endl;
*this << ";" << m_endl;
}
void
@ -338,7 +338,7 @@ CIFWriter::write_boxes (const db::Layout & /*layout*/, const db::Cell &cell, uns
emit_layer ();
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;
@ -411,13 +411,13 @@ CIFWriter::write_paths (const db::Layout & /*layout*/, const db::Cell &cell, uns
db::Point pp (*shape->begin_point () * sf);
*this << " " << pp.x () << xy_sep () << pp.y ();
*this << ";" << endl;
*this << ";" << m_endl;
} else if (path_type >= 0 && npts > 1) {
emit_layer ();
*this << "98 " << path_type << ";" << endl;
*this << "98 " << path_type << ";" << m_endl;
*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 << ";" << endl;
*this << ";" << m_endl;
} else {
db::Polygon poly;

View File

@ -66,7 +66,7 @@ private:
tl::OutputStream *mp_stream;
CIFWriterOptions m_options;
tl::AbsoluteProgress m_progress;
endl_tag endl;
endl_tag m_endl;
db::LayerProperties m_layer;
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;
}
// extend lay::SaveLayoutOptions with the GDS2 options
// extend lay::SaveLayoutOptions with the CIF options
static
gsi::ClassExt<db::SaveLayoutOptions> cif_writer_options (
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
{
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::dbu, "dbu") +
tl::make_member (&db::MAGReaderOptions::layer_map, "layer-map") +
@ -98,12 +98,9 @@ public:
virtual tl::XMLElementBase *xml_writer_options_element () const
{
// @@@
return new db::WriterOptionsXMLElement<db::MAGWriterOptions> ("cif",
tl::make_member (&db::MAGWriterOptions::dummy_calls, "dummy-calls") +
tl::make_member (&db::MAGWriterOptions::blank_separator, "blank-separator")
return new db::WriterOptionsXMLElement<db::MAGWriterOptions> ("mag",
tl::make_member (&db::MAGWriterOptions::lambda, "lambda")
);
// @@@
}
};

View File

@ -146,24 +146,19 @@ public:
* @brief The constructor
*/
MAGWriterOptions ()
: dummy_calls (false), blank_separator (false)
: lambda (0.0)
{
// .. nothing yet ..
}
/**
* @brief A flag indicating whether dummy calls shall be written
* If this flag is true, the writer will produce dummy cell calls on global
* level for all top cells.
* @brief Specifies the lambda value for writing
*
* 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;
/**
* @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;
double lambda;
/**
* @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?")));
}
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;
unsigned int current_layer = 0;

View File

@ -37,50 +37,19 @@ namespace db
MAGWriter::MAGWriter ()
: mp_stream (0),
m_progress (tl::to_string (tr ("Writing MAG file")), 10000),
m_needs_emit (false)
m_progress (tl::to_string (tr ("Writing Magic file")), 10000)
{
m_progress.set_format (tl::to_string (tr ("%.0f MB")));
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
MAGWriter::write (db::Layout &layout, tl::OutputStream &stream, const db::SaveLayoutOptions &options)
{
m_options = options.get_options<MAGWriterOptions> ();
mp_stream = &stream;
#if 0 // @@@
// 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;
@ -242,11 +211,12 @@ MAGWriter::write (db::Layout &layout, tl::OutputStream &stream, const db::SaveLa
// end of file
*this << "E" << endl;
#endif
m_progress.set (mp_stream->pos ());
}
#if 0 // @@@
void
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;
MAGWriterOptions m_options;
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

View File

@ -236,53 +236,32 @@ gsi::ClassExt<db::LoadLayoutOptions> mag_reader_options (
// ---------------------------------------------------------------
// 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)
{
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
// extend lay::SaveLayoutOptions with the MAG options
static
gsi::ClassExt<db::SaveLayoutOptions> mag_writer_options (
gsi::method_ext ("mag_dummy_calls=", &set_mag_dummy_calls,
"@brief Sets a flag indicating whether dummy calls shall be written\n"
"If this property is set to true, dummy calls will be written in the top level entity "
"of the MAG file calling every top cell.\n"
"This option is useful for enhanced compatibility with other tools.\n"
"\nThis property has been added in version 0.23.10.\n"
gsi::method_ext ("mag_lambda=", &set_mag_lambda_w, gsi::arg ("lambda"),
"@brief Specifies the lambda value to used for writing\n"
"\n"
"The lamdba value is the basic unit of the layout.\n"
"The layout is brought to units of this value. If the layout is not on-grid on this unit, snapping will happen. "
"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,
"@brief Gets a flag indicating whether dummy calls shall be written\n"
"See \\mag_dummy_calls= 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"
) +
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"
gsi::method_ext ("mag_lambda", &get_mag_lambda_w,
"@brief Get the lambda value\n"
"See \\mag_lambda= method for a description of this attribute."
"\nThis property has been added in version 0.26.2.\n"
),
""
);

View File

@ -35,50 +35,27 @@
<string>CIF Writer Options</string>
</property>
<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">
<widget class="QCheckBox" name="blank_separator_cbx">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<widget class="QLineEdit" name="lambda_le"/>
</item>
<item row="0" column="2">
<widget class="QLabel" name="label">
<property name="text">
<string>If checked, a blank character is used as x/y coordinate
separator. Otherweise a comma is used.</string>
<string>Micron</string>
</property>
</widget>
</item>
<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">
<property name="text">
<string>Blank as x/y separator</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>
<string>Leave this value empty to take the lambda value stored in the layout</string>
</property>
</widget>
</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);
if (options) {
mp_ui->dummy_calls_cbx->setChecked (options->dummy_calls);
mp_ui->blank_separator_cbx->setChecked (options->blank_separator);
if (options->lambda <= 0.0) {
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);
if (options) {
options->dummy_calls = mp_ui->dummy_calls_cbx->isChecked ();
options->blank_separator = mp_ui->blank_separator_cbx->isChecked ();
QString l = mp_ui->lambda_le->text ().trimmed ();
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);
db::MAGWriterOptions *opt = new db::MAGWriterOptions();
opt->dummy_calls = dummy_calls;
opt->blank_separator = blank_sep;
opt->lambda = 0.5;
db::MAGWriter writer;
db::SaveLayoutOptions options;