mirror of https://github.com/KLayout/klayout.git
WIP: substantial changes
- force lower-case layer names to allow CIF/MAG loop (CIF needs upper-case layer names, MAG doesn't) - reverted CIF reader to standard - new options for writer: tech, "zero timestamp". - file name MUST be consistent with one cell name. Reason: it's not possible to derive the initial cell from the given options, so without the file name being consistent, we can't know what to write there. Basically the file name rather supplies the path.
This commit is contained in:
parent
9fb73a3928
commit
c6ede46fd0
|
|
@ -84,7 +84,7 @@ extract_ld (const char *s, int &l, int &d, std::string &n)
|
|||
{
|
||||
l = d = 0;
|
||||
|
||||
if (*s == 'L') {
|
||||
if (*s == 'L' || *s == 'l') {
|
||||
++s;
|
||||
}
|
||||
|
||||
|
|
@ -97,7 +97,7 @@ extract_ld (const char *s, int &l, int &d, std::string &n)
|
|||
++s;
|
||||
}
|
||||
|
||||
if (*s == 'D' || *s == '.') {
|
||||
if (*s == 'D' || *s == 'd' || *s == '.') {
|
||||
++s;
|
||||
if (! safe_isdigit (*s)) {
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -339,6 +339,14 @@ LayoutHandle::load (const db::LoadLayoutOptions &options, const std::string &tec
|
|||
db::Reader reader (stream);
|
||||
db::LayerMap new_lmap = reader.read (layout (), m_load_options);
|
||||
|
||||
// If there is no technology given and the reader reports one, use this one
|
||||
if (technology.empty ()) {
|
||||
std::string tech_from_reader = layout ().meta_info_value ("technology");
|
||||
if (! tech_from_reader.empty ()) {
|
||||
set_tech_name (tech_from_reader);
|
||||
}
|
||||
}
|
||||
|
||||
// Update the file's data:
|
||||
file_watcher ().remove_file (filename ());
|
||||
file_watcher ().add_file (filename ());
|
||||
|
|
@ -358,6 +366,12 @@ LayoutHandle::load ()
|
|||
db::Reader reader (stream);
|
||||
db::LayerMap new_lmap = reader.read (layout (), m_load_options);
|
||||
|
||||
// Attach the technology from the reader if it reports one
|
||||
std::string tech_from_reader = layout ().meta_info_value ("technology");
|
||||
if (! tech_from_reader.empty ()) {
|
||||
set_tech_name (tech_from_reader);
|
||||
}
|
||||
|
||||
// Update the file's data:
|
||||
file_watcher ().remove_file (filename ());
|
||||
file_watcher ().add_file (filename ());
|
||||
|
|
|
|||
|
|
@ -106,17 +106,10 @@ CIFReader::warn (const std::string &msg)
|
|||
void
|
||||
CIFReader::skip_blanks()
|
||||
{
|
||||
bool had_space = false;
|
||||
while (! m_stream.at_end ()) {
|
||||
char c = m_stream.peek_char ();
|
||||
if (isupper (c) || isdigit (c) || c == '-' || c == '(' || c == ')' || c == ';') {
|
||||
return;
|
||||
} else if (isspace (c)) {
|
||||
had_space = true;
|
||||
} else if (had_space) {
|
||||
// an extension to allow lower-case cell and layer names and some more flexibility
|
||||
// in general: after space (blank, tab ...) any character will end the sequence.
|
||||
return;
|
||||
}
|
||||
m_stream.get_char ();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -135,7 +135,7 @@ 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 << ";" << m_endl;
|
||||
*this << "9 " << tl::to_word_or_quoted_string (layout.cell_name (*cell)) << ";" << m_endl;
|
||||
*this << "9 " << tl::to_word_or_quoted_string (tl::to_upper_case (layout.cell_name (*cell))) << ";" << m_endl;
|
||||
|
||||
// instances
|
||||
for (db::Cell::const_iterator inst = cref.begin (); ! inst.at_end (); ++inst) {
|
||||
|
|
@ -250,7 +250,7 @@ CIFWriter::emit_layer()
|
|||
{
|
||||
if (m_needs_emit) {
|
||||
m_needs_emit = false;
|
||||
*this << "L " << tl::to_word_or_quoted_string(m_layer.name, "0123456789_.$") << ";" << m_endl;
|
||||
*this << "L " << tl::to_word_or_quoted_string (tl::to_upper_case (m_layer.name), "0123456789_.$") << ";" << m_endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -264,7 +264,7 @@ CIFWriter::write_texts (const db::Layout &layout, const db::Cell &cell, unsigned
|
|||
|
||||
emit_layer ();
|
||||
|
||||
*this << "94 " << tl::to_word_or_quoted_string(shape->text_string(), "0123456789:<>/&%$!.-_#+*?\\[]{}");
|
||||
*this << "94 " << tl::to_word_or_quoted_string (shape->text_string(), "0123456789:<>/&%$!.-_#+*?\\[]{}");
|
||||
|
||||
double h = shape->text_size () * layout.dbu ();
|
||||
|
||||
|
|
|
|||
|
|
@ -99,7 +99,9 @@ public:
|
|||
virtual tl::XMLElementBase *xml_writer_options_element () const
|
||||
{
|
||||
return new db::WriterOptionsXMLElement<db::MAGWriterOptions> ("mag",
|
||||
tl::make_member (&db::MAGWriterOptions::lambda, "lambda")
|
||||
tl::make_member (&db::MAGWriterOptions::lambda, "lambda") +
|
||||
tl::make_member (&db::MAGWriterOptions::tech, "tech") +
|
||||
tl::make_member (&db::MAGWriterOptions::write_timestamp, "write-timestamp")
|
||||
);
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -146,7 +146,7 @@ public:
|
|||
* @brief The constructor
|
||||
*/
|
||||
MAGWriterOptions ()
|
||||
: lambda (0.0)
|
||||
: lambda (0.0), write_timestamp (true)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
@ -160,6 +160,21 @@ public:
|
|||
*/
|
||||
double lambda;
|
||||
|
||||
/**
|
||||
* @brief Specifies the technology value for writing Magic files
|
||||
*
|
||||
* If this value is set an empty string, the technology store in the layout's
|
||||
* "technology" meta data is used.
|
||||
*/
|
||||
std::string tech;
|
||||
|
||||
/**
|
||||
* @brief A value indicating whether the real (true) or fake (false) timestamp is written
|
||||
*
|
||||
* A fake, static timestamp is useful for comparing files.
|
||||
*/
|
||||
bool write_timestamp;
|
||||
|
||||
/**
|
||||
* @brief Implementation of FormatSpecificWriterOptions
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -142,7 +142,7 @@ MAGReader::cell_from_path (const std::string &path, db::Layout &layout)
|
|||
return c->second;
|
||||
}
|
||||
|
||||
// @@@ this can lead to cell variants if a cell is present with different library paths ... (L500_CHAR_p)
|
||||
// NOTE: this can lead to cell variants if a cell is present with different library paths ... (L500_CHAR_p)
|
||||
db::cell_index_type ci = layout.add_cell (cell_name_from_path (path).c_str ());
|
||||
m_cells_read.insert (std::make_pair (path, ci));
|
||||
|
||||
|
|
@ -219,11 +219,7 @@ bool
|
|||
MAGReader::resolve_path (const std::string &path, std::string &real_path)
|
||||
{
|
||||
tl::Eval expr;
|
||||
/* @@@
|
||||
expr.set_var ("tech_dir", m_default_base_path);
|
||||
expr.set_var ("tech_file", m_lyt_file);
|
||||
expr.set_var ("tech_name", m_lyt_file);
|
||||
*/
|
||||
// TODO: more variables?
|
||||
expr.set_var ("tech_info", m_tech);
|
||||
|
||||
tl::URI path_uri (path);
|
||||
|
|
@ -305,7 +301,7 @@ MAGReader::do_read_part (db::Layout &layout, db::cell_index_type cell_index, tl:
|
|||
|
||||
if (&m_stream == &stream) {
|
||||
// initial file - store technology
|
||||
layout.add_meta_info (db::MetaInfo ("magic_tech", "MAGIC technology string", m_tech));
|
||||
layout.add_meta_info (db::MetaInfo ("technology", "MAGIC technology string", m_tech));
|
||||
}
|
||||
|
||||
ex.expect_end ();
|
||||
|
|
@ -316,7 +312,7 @@ MAGReader::do_read_part (db::Layout &layout, db::cell_index_type cell_index, tl:
|
|||
ex.read (ts);
|
||||
|
||||
if (&m_stream == &stream) {
|
||||
// initial file - store technology
|
||||
// initial file - store timestamp
|
||||
layout.add_meta_info (db::MetaInfo ("magic_timestamp", "MAGIC main file timestamp", tl::to_string (ts)));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
#include "tlUri.h"
|
||||
#include "tlLog.h"
|
||||
#include "tlUniqueName.h"
|
||||
#include "tlTimer.h"
|
||||
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
|
|
@ -52,6 +53,23 @@ MAGWriter::MAGWriter ()
|
|||
void
|
||||
MAGWriter::write (db::Layout &layout, tl::OutputStream &stream, const db::SaveLayoutOptions &options)
|
||||
{
|
||||
std::vector <std::pair <unsigned int, db::LayerProperties> > layers;
|
||||
options.get_valid_layers (layout, layers, db::SaveLayoutOptions::LP_AssignName);
|
||||
|
||||
std::set <db::cell_index_type> cell_set;
|
||||
options.get_cells (layout, cell_set, layers);
|
||||
|
||||
tl::URI src (stream.path ());
|
||||
std::string basename = tl::basename (src.path ());
|
||||
std::pair<bool, db::cell_index_type> ci = layout.cell_by_name (basename.c_str ());
|
||||
if (! ci.first) {
|
||||
throw tl::Exception (tl::to_string (tr ("Magic file names must be valid cell names. This is not a valid name: ")) + basename);
|
||||
}
|
||||
|
||||
if (cell_set.find (ci.second) == cell_set.end ()) {
|
||||
throw tl::Exception (tl::to_string (tr ("Cell name derived from file name isn't a selected cell: ")) + basename);
|
||||
}
|
||||
|
||||
m_options = options.get_options<MAGWriterOptions> ();
|
||||
mp_stream = &stream;
|
||||
|
||||
|
|
@ -59,10 +77,12 @@ MAGWriter::write (db::Layout &layout, tl::OutputStream &stream, const db::SaveLa
|
|||
m_ext = tl::extension (m_base_uri.path ());
|
||||
m_base_uri.set_path (tl::dirname (m_base_uri.path ()));
|
||||
|
||||
m_cells_written.clear ();
|
||||
m_cells_to_write.clear ();
|
||||
m_layer_names.clear ();
|
||||
m_timestamp = 0; // @@@ set timestamp?
|
||||
m_timestamp = 0;
|
||||
if (m_options.write_timestamp) {
|
||||
timespec ts;
|
||||
tl::current_utc_time (&ts);
|
||||
m_timestamp = ts.tv_sec;
|
||||
}
|
||||
|
||||
double lambda = m_options.lambda;
|
||||
if (lambda <= 0.0) {
|
||||
|
|
@ -75,87 +95,10 @@ MAGWriter::write (db::Layout &layout, tl::OutputStream &stream, const db::SaveLa
|
|||
|
||||
m_sf = layout.dbu () / lambda;
|
||||
|
||||
if (layout.end_top_cells () - layout.begin_top_down () == 1) {
|
||||
|
||||
// write the one top cell to the given stream. Otherwise
|
||||
write_cell (*layout.begin_top_down (), layout, stream);
|
||||
|
||||
} else {
|
||||
|
||||
stream << "# KLayout is not writing this file as there are multiple top cells - see those files for the individual cells.";
|
||||
|
||||
for (db::Layout::top_down_const_iterator c = layout.begin_top_down (); c != layout.end_top_cells (); ++c) {
|
||||
m_cells_to_write.insert (std::make_pair (*c, filename_for_cell (*c, layout)));
|
||||
}
|
||||
|
||||
for (std::set<db::cell_index_type>::const_iterator c = cell_set.begin (); c != cell_set.end (); ++c) {
|
||||
tl::OutputStream os (filename_for_cell (*c, layout), tl::OutputStream::OM_Auto, true);
|
||||
write_cell (*c, layers, layout, os);
|
||||
}
|
||||
|
||||
while (! m_cells_to_write.empty ()) {
|
||||
|
||||
std::map<db::cell_index_type, std::string> cells_to_write;
|
||||
cells_to_write.swap (m_cells_to_write);
|
||||
|
||||
for (std::map<db::cell_index_type, std::string>::const_iterator cw = cells_to_write.begin (); cw != cells_to_write.end (); ++cw) {
|
||||
tl::OutputStream os (cw->second, tl::OutputStream::OM_Auto, true);
|
||||
write_cell (cw->first, layout, os);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
std::string
|
||||
MAGWriter::layer_name (unsigned int li, const Layout &layout)
|
||||
{
|
||||
std::map<unsigned int, std::string>::const_iterator i = m_layer_names.find (li);
|
||||
if (i != m_layer_names.end ()) {
|
||||
return i->second;
|
||||
}
|
||||
|
||||
// Avoid built-in names, like "end", "space", "labels" and "checkpaint"
|
||||
std::set<std::string> used_names;
|
||||
used_names.insert ("end");
|
||||
used_names.insert ("space");
|
||||
used_names.insert ("labels");
|
||||
used_names.insert ("checkpaint");
|
||||
|
||||
if (m_layer_names.empty ()) {
|
||||
|
||||
for (db::Layout::layer_iterator i = layout.begin_layers (); i != layout.end_layers (); ++i) {
|
||||
|
||||
db::LayerProperties lp = layout.get_properties ((*i).first);
|
||||
if (! lp.name.empty ()) {
|
||||
|
||||
std::string lp_name = lp.name;
|
||||
lp_name = tl::unique_name (lp_name, used_names, "_");
|
||||
used_names.insert (lp_name);
|
||||
|
||||
m_layer_names.insert (std::make_pair ((*i).first, lp_name));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (db::Layout::layer_iterator i = layout.begin_layers (); i != layout.end_layers (); ++i) {
|
||||
|
||||
db::LayerProperties lp = layout.get_properties ((*i).first);
|
||||
if (lp.name.empty ()) {
|
||||
|
||||
std::string ld_name = std::string ("L") + tl::to_string (lp.layer);
|
||||
if (lp.datatype) {
|
||||
ld_name += "D";
|
||||
ld_name += tl::to_string (lp.datatype);
|
||||
}
|
||||
|
||||
ld_name = tl::unique_name (ld_name, used_names, "_");
|
||||
used_names.insert (ld_name);
|
||||
m_layer_names.insert (std::make_pair ((*i).first, ld_name));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return m_layer_names [li];
|
||||
}
|
||||
|
||||
std::string
|
||||
|
|
@ -171,24 +114,29 @@ MAGWriter::filename_for_cell (db::cell_index_type ci, db::Layout &layout)
|
|||
}
|
||||
|
||||
void
|
||||
MAGWriter::write_cell (db::cell_index_type ci, db::Layout &layout, tl::OutputStream &os)
|
||||
MAGWriter::write_cell (db::cell_index_type ci, const std::vector <std::pair <unsigned int, db::LayerProperties> > &layers, db::Layout &layout, tl::OutputStream &os)
|
||||
{
|
||||
m_cellname = layout.cell_name (ci);
|
||||
try {
|
||||
do_write_cell (ci, layout, os);
|
||||
do_write_cell (ci, layers, layout, os);
|
||||
} catch (tl::Exception &ex) {
|
||||
throw tl::Exception (ex.msg () + tl::to_string (tr (" when writing cell ")) + m_cellname);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MAGWriter::do_write_cell (db::cell_index_type ci, db::Layout &layout, tl::OutputStream &os)
|
||||
MAGWriter::do_write_cell (db::cell_index_type ci, const std::vector <std::pair <unsigned int, db::LayerProperties> > &layers, db::Layout &layout, tl::OutputStream &os)
|
||||
{
|
||||
os.set_as_text (true);
|
||||
os << "magic\n";
|
||||
|
||||
// @@@ write tech
|
||||
os << "tech scmos\n";
|
||||
std::string tech = m_options.tech;
|
||||
if (tech.empty ()) {
|
||||
tech = layout.meta_info_value ("technology");
|
||||
}
|
||||
if (! tech.empty ()) {
|
||||
os << "tech " << tl::to_word_or_quoted_string (tl::to_lower_case (tech)) << "\n";
|
||||
}
|
||||
|
||||
os << "timestamp " << m_timestamp << "\n";
|
||||
|
||||
|
|
@ -197,39 +145,36 @@ MAGWriter::do_write_cell (db::cell_index_type ci, db::Layout &layout, tl::Output
|
|||
os << "<< checkpaint >>\n";
|
||||
write_polygon (db::Polygon (cell.bbox ()), layout, os);
|
||||
|
||||
for (db::Layout::layer_iterator i = layout.begin_layers (); i != layout.end_layers (); ++i) {
|
||||
bool any;
|
||||
|
||||
unsigned int li = (*i).first;
|
||||
if (! cell.shapes (li).empty ()) {
|
||||
os << "<< " << tl::to_word_or_quoted_string (layer_name (li, layout)) << " >>\n";
|
||||
for (db::Shapes::shape_iterator s = cell.shapes (li).begin (db::ShapeIterator::Boxes | db::ShapeIterator::Polygons | db::ShapeIterator::Paths); ! s.at_end (); ++s) {
|
||||
db::Polygon poly;
|
||||
s->polygon (poly);
|
||||
write_polygon (poly, layout, os);
|
||||
for (std::vector <std::pair <unsigned int, db::LayerProperties> >::const_iterator ll = layers.begin (); ll != layers.end (); ++ll) {
|
||||
any = false;
|
||||
for (db::Shapes::shape_iterator s = cell.shapes (ll->first).begin (db::ShapeIterator::Boxes | db::ShapeIterator::Polygons | db::ShapeIterator::Paths); ! s.at_end (); ++s) {
|
||||
if (! any) {
|
||||
os << "<< " << tl::to_word_or_quoted_string (tl::to_lower_case (ll->second.name)) << " >>\n";
|
||||
any = true;
|
||||
}
|
||||
db::Polygon poly;
|
||||
s->polygon (poly);
|
||||
write_polygon (poly, layout, os);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool any = false;
|
||||
|
||||
for (db::Layout::layer_iterator i = layout.begin_layers (); i != layout.end_layers (); ++i) {
|
||||
for (db::Shapes::shape_iterator s = cell.shapes ((*i).first).begin (db::ShapeIterator::Texts); ! s.at_end (); ++s) {
|
||||
any = false;
|
||||
for (std::vector <std::pair <unsigned int, db::LayerProperties> >::const_iterator ll = layers.begin (); ll != layers.end (); ++ll) {
|
||||
for (db::Shapes::shape_iterator s = cell.shapes (ll->first).begin (db::ShapeIterator::Texts); ! s.at_end (); ++s) {
|
||||
if (! any) {
|
||||
os << "<< labels >>\n";
|
||||
any = true;
|
||||
}
|
||||
db::Text text;
|
||||
s->text (text);
|
||||
write_label (layer_name ((*i).first, layout), text, layout, os);
|
||||
write_label (tl::to_lower_case (ll->second.name), text, layout, os);
|
||||
}
|
||||
}
|
||||
|
||||
m_cell_id.clear ();
|
||||
for (db::Cell::const_iterator i = cell.begin (); ! i.at_end (); ++i) {
|
||||
if (m_cells_written.find (i->cell_index ()) == m_cells_written.end ()) {
|
||||
m_cells_written.insert (i->cell_index ());
|
||||
m_cells_to_write.insert (std::make_pair (i->cell_index (), filename_for_cell (i->cell_index (), layout)));
|
||||
}
|
||||
write_instance (i->cell_inst (), layout, os);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -90,20 +90,16 @@ private:
|
|||
tl::OutputStream *mp_stream;
|
||||
MAGWriterOptions m_options;
|
||||
tl::AbsoluteProgress m_progress;
|
||||
std::set<db::cell_index_type> m_cells_written;
|
||||
std::map<db::cell_index_type, std::string> m_cells_to_write;
|
||||
tl::URI m_base_uri;
|
||||
std::string m_ext;
|
||||
std::map<unsigned int, std::string> m_layer_names;
|
||||
size_t m_timestamp;
|
||||
std::map<db::cell_index_type, size_t> m_cell_id;
|
||||
double m_sf;
|
||||
std::string m_cellname;
|
||||
|
||||
std::string filename_for_cell (db::cell_index_type ci, db::Layout &layout);
|
||||
void write_cell (db::cell_index_type ci, db::Layout &layout, tl::OutputStream &os);
|
||||
void do_write_cell (db::cell_index_type ci, db::Layout &layout, tl::OutputStream &os);
|
||||
std::string layer_name (unsigned int li, const db::Layout &layout);
|
||||
void write_cell (db::cell_index_type ci, const std::vector <std::pair <unsigned int, db::LayerProperties> > &layers, db::Layout &layout, tl::OutputStream &os);
|
||||
void do_write_cell (db::cell_index_type ci, const std::vector <std::pair <unsigned int, db::LayerProperties> > &layers, db::Layout &layout, tl::OutputStream &os);
|
||||
void write_polygon (const db::Polygon &poly, const db::Layout &layout, tl::OutputStream &os);
|
||||
void write_label (const std::string &layer, const db::Text &text, const Layout &layout, tl::OutputStream &os);
|
||||
void write_instance (const db::CellInstArray &inst, const db::Layout &layout, tl::OutputStream &os);
|
||||
|
|
|
|||
|
|
@ -246,6 +246,26 @@ static double get_mag_lambda_w (const db::SaveLayoutOptions *options)
|
|||
return options->get_options<db::MAGWriterOptions> ().lambda;
|
||||
}
|
||||
|
||||
static void set_mag_write_timestamp (db::SaveLayoutOptions *options, bool f)
|
||||
{
|
||||
options->get_options<db::MAGWriterOptions> ().write_timestamp = f;
|
||||
}
|
||||
|
||||
static bool get_mag_write_timestamp (const db::SaveLayoutOptions *options)
|
||||
{
|
||||
return options->get_options<db::MAGWriterOptions> ().write_timestamp;
|
||||
}
|
||||
|
||||
static void set_mag_tech_w (db::SaveLayoutOptions *options, const std::string &t)
|
||||
{
|
||||
options->get_options<db::MAGWriterOptions> ().tech = t;
|
||||
}
|
||||
|
||||
static const std::string &get_mag_tech_w (const db::SaveLayoutOptions *options)
|
||||
{
|
||||
return options->get_options<db::MAGWriterOptions> ().tech;
|
||||
}
|
||||
|
||||
// extend lay::SaveLayoutOptions with the MAG options
|
||||
static
|
||||
gsi::ClassExt<db::SaveLayoutOptions> mag_writer_options (
|
||||
|
|
@ -259,9 +279,31 @@ gsi::ClassExt<db::SaveLayoutOptions> mag_writer_options (
|
|||
"\nThis property has been added in version 0.26.2.\n"
|
||||
) +
|
||||
gsi::method_ext ("mag_lambda", &get_mag_lambda_w,
|
||||
"@brief Get the lambda value\n"
|
||||
"@brief Gets 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"
|
||||
) +
|
||||
gsi::method_ext ("write_timestamp=", &set_mag_write_timestamp, gsi::arg ("f"),
|
||||
"@brief Specifies whether to write a timestamp\n"
|
||||
"\n"
|
||||
"If this attribute is set to false, the timestamp written is 0. This isn't correct in the strict sense but simplifies comparison of Magic files.\n"
|
||||
"\nThis property has been added in version 0.26.2.\n"
|
||||
) +
|
||||
gsi::method_ext ("write_timestamp", &get_mag_write_timestamp,
|
||||
"@brief Gets a value indicating whether to write a timestamp\n"
|
||||
"See \\write_timestamp= method for a description of this attribute.\n"
|
||||
"\nThis property has been added in version 0.26.2.\n"
|
||||
) +
|
||||
gsi::method_ext ("mag_tech=", &set_mag_tech_w, gsi::arg ("tech"),
|
||||
"@brief Specifies the technology string used for writing\n"
|
||||
"\n"
|
||||
"If this string is empty, the writer will try to obtain the technology from the \"technology\" metadata attribute of the layout.\n"
|
||||
"\nThis property has been added in version 0.26.2.\n"
|
||||
) +
|
||||
gsi::method_ext ("mag_tech", &get_mag_tech_w,
|
||||
"@brief Gets the technology string used for writing\n"
|
||||
"See \\mag_tech= method for a description of this attribute."
|
||||
"\nThis property has been added in version 0.26.2.\n"
|
||||
),
|
||||
""
|
||||
);
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>619</width>
|
||||
<height>209</height>
|
||||
<height>250</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
|
|
@ -35,9 +35,40 @@
|
|||
<string>Magic Writer Options</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="3" column="1">
|
||||
<widget class="QLineEdit" name="tech_le"/>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="lambda_le"/>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Zero timestamp</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QCheckBox" name="zero_ts_cbx">
|
||||
<property name="text">
|
||||
<string>If checked, a zero timestamp is written (good for comparing files)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1" colspan="2">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Leave this value empty to take the lambda value stored in the layout</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Technology</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
|
|
@ -52,13 +83,6 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1" colspan="2">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Leave this value empty to take the lambda value stored in the layout</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
|
|||
|
|
@ -60,6 +60,8 @@ MAGWriterOptionPage::setup (const db::FormatSpecificWriterOptions *o, const db::
|
|||
} else {
|
||||
mp_ui->lambda_le->setText (tl::to_qstring (tl::to_string (options->lambda)));
|
||||
}
|
||||
mp_ui->tech_le->setText (tl::to_qstring (options->tech));
|
||||
mp_ui->zero_ts_cbx->setChecked (! options->write_timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -73,6 +75,8 @@ MAGWriterOptionPage::commit (db::FormatSpecificWriterOptions *o, const db::Techn
|
|||
if (! l.isEmpty ()) {
|
||||
tl::from_string (tl::to_string (l), options->lambda);
|
||||
}
|
||||
options->tech = tl::to_string (mp_ui->tech_le->text ().trimmed ());
|
||||
options->write_timestamp = ! mp_ui->zero_ts_cbx->isChecked ();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -66,16 +66,12 @@ static void run_test (tl::TestBase *_this, const std::string &base, const char *
|
|||
reader.read (layout, options);
|
||||
}
|
||||
|
||||
// generate a "unique" name ...
|
||||
unsigned int hash = 0;
|
||||
for (const char *cp = file_au; *cp; ++cp) {
|
||||
hash = (hash << 4) ^ (hash >> 4) ^ ((unsigned int) *cp);
|
||||
}
|
||||
std::string tc_name = layout.cell_name (*layout.begin_top_down ());
|
||||
|
||||
// normalize the layout by writing to GDS and reading from ..
|
||||
|
||||
std::string tmp_cif_file = _this->tmp_file (tl::sprintf ("tmp_%x.cif", hash));
|
||||
std::string tmp_mag_file = _this->tmp_file (tl::sprintf ("tmp_%x.mag", hash));
|
||||
std::string tmp_cif_file = _this->tmp_file (tl::sprintf ("%s.cif", tc_name));
|
||||
std::string tmp_mag_file = _this->tmp_file (tl::sprintf ("%s.mag", tc_name));
|
||||
|
||||
{
|
||||
tl::OutputStream stream (tmp_cif_file);
|
||||
|
|
@ -142,6 +138,6 @@ static void run_test (tl::TestBase *_this, const std::string &base, const char *
|
|||
|
||||
TEST(1)
|
||||
{
|
||||
run_test (_this, tl::testsrc (), "mag_test.mag.gz", "mag_test_au.cif.gz");
|
||||
run_test (_this, tl::testsrc (), "MAG_TEST.mag.gz", "mag_test_au.cif.gz");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ namespace tl
|
|||
* @brief clock_gettime is not implemented in Mac OS X 10.11 and lower
|
||||
* From: https://gist.githubusercontent.com/jbenet/1087739/raw/638b37f76cdd9dc46d617443cab27eac297e2ee3/current_utc_time.c
|
||||
*/
|
||||
void current_utc_time (struct timespec *ts);
|
||||
TL_PUBLIC void current_utc_time (struct timespec *ts);
|
||||
|
||||
/**
|
||||
* @brief A basic timer class
|
||||
|
|
|
|||
Binary file not shown.
Loading…
Reference in New Issue