mirror of https://github.com/KLayout/klayout.git
Merge branch 'master' of github.com:KLayout/klayout
This commit is contained in:
commit
63a948a77b
|
|
@ -48,7 +48,7 @@ jobs:
|
|||
large-packages: true
|
||||
- uses: hmarr/debug-action@v3
|
||||
- name: Cancel Workflow Action
|
||||
uses: styfle/cancel-workflow-action@0.13.0
|
||||
uses: styfle/cancel-workflow-action@0.13.1
|
||||
- uses: actions/checkout@v6
|
||||
- name: ccache
|
||||
if: matrix.os != 'ubuntu-24.04-arm'
|
||||
|
|
@ -66,7 +66,7 @@ jobs:
|
|||
mkdir -p $HOST_CCACHE_DIR
|
||||
- name: Build wheels (ARM)
|
||||
if: matrix.os == 'ubuntu-24.04-arm'
|
||||
uses: pypa/cibuildwheel@v3.3.1
|
||||
uses: pypa/cibuildwheel@v3.4.0
|
||||
env:
|
||||
# override the default CentOS “yum install … ccache” and drop ccache
|
||||
CIBW_BEFORE_ALL_LINUX: |
|
||||
|
|
@ -81,7 +81,7 @@ jobs:
|
|||
|
||||
- name: Build wheels (all other platforms)
|
||||
if: matrix.os != 'ubuntu-24.04-arm'
|
||||
uses: pypa/cibuildwheel@v3.3.1
|
||||
uses: pypa/cibuildwheel@v3.4.0
|
||||
env:
|
||||
CIBW_BUILD: ${{ matrix.cibuild }}
|
||||
CIBW_ARCHS_MACOS: ${{ matrix.macos-arch }}
|
||||
|
|
|
|||
|
|
@ -41,7 +41,9 @@ INCLUDEPATH += $$RBA_INC
|
|||
DEPENDPATH += $$RBA_INC
|
||||
|
||||
equals(HAVE_RUBY, "1") {
|
||||
LIBS += -lklayout_rba
|
||||
INCLUDEPATH += $$DRC_INC $$LVS_INC
|
||||
DEPENDPATH += $$DRC_INC $$LVS_INC
|
||||
LIBS += -lklayout_rba -lklayout_drc -lklayout_lvs
|
||||
} else {
|
||||
LIBS += -lklayout_rbastub
|
||||
}
|
||||
|
|
|
|||
|
|
@ -153,10 +153,10 @@ void clip (ClipData &data)
|
|||
// write the layout
|
||||
|
||||
db::SaveLayoutOptions save_options;
|
||||
save_options.set_format_from_filename (data.file_out);
|
||||
std::string of = save_options.set_format_from_filename (data.file_out).second;
|
||||
data.writer_options.configure (save_options, target_layout);
|
||||
|
||||
tl::OutputStream stream (data.file_out);
|
||||
tl::OutputStream stream (of);
|
||||
db::Writer writer (save_options);
|
||||
writer.write (target_layout, stream);
|
||||
}
|
||||
|
|
@ -176,7 +176,9 @@ BD_PUBLIC int strmclip (int argc, char *argv[])
|
|||
<< tl::arg ("output", &data.file_out, "The output file",
|
||||
"The output format is determined from the suffix of the file. If the suffix indicates "
|
||||
"gzip compression, the file will be compressed on output. Examples for recognized suffixes are "
|
||||
"\".oas\", \".gds.gz\", \".dxf\" or \".gds2\"."
|
||||
"\".oas\", \".gds.gz\", \".dxf\" or \".gds2\". You can also use any name, and specify the "
|
||||
"desired suffix in square brackets after the file name. For example, 'file.clip[oas]' will "
|
||||
"create an OASIS file called 'file.clip'."
|
||||
)
|
||||
<< tl::arg ("-l|--clip-layer=spec", &data, &ClipData::set_clip_layer, "Specifies a layer to take the clip regions from",
|
||||
"If this option is given, the clip rectangles are taken from the given layer."
|
||||
|
|
|
|||
|
|
@ -36,6 +36,8 @@
|
|||
#include "libForceLink.h"
|
||||
#include "rdbForceLink.h"
|
||||
#include "pexForceLink.h"
|
||||
#include "drcForceLink.h"
|
||||
#include "lvsForceLink.h"
|
||||
#include "lymMacro.h"
|
||||
#include "lymMacroCollection.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -408,7 +408,9 @@ BD_PUBLIC int strmxor (int argc, char *argv[])
|
|||
<< tl::arg ("?output", &output, "The output file to which the XOR differences are written",
|
||||
"This argument is optional. If not given, the exit status alone will indicate whether the layouts "
|
||||
"are identical or not. The output is a layout file. The format of the file is derived "
|
||||
"from the file name's suffix (.oas[.gz] for (gzipped) OASIS, .gds[.gz] for (gzipped) GDS2 etc.)."
|
||||
"from the file name's suffix (.oas for OASIS, .gds[.gz] for (gzipped) GDS2 etc.). "
|
||||
"You can also use any name, and specify the desired suffix in square brackets after the file name. "
|
||||
"For example, 'file.xor[oas]' will create an OASIS file called 'file.xor'."
|
||||
)
|
||||
<< tl::arg ("-ta|--top-a=name", &top_a, "Specifies the top cell for the first layout",
|
||||
"Use this option to take a specific cell as the top cell from the first layout. All "
|
||||
|
|
@ -587,10 +589,10 @@ BD_PUBLIC int strmxor (int argc, char *argv[])
|
|||
if (output_layout.get ()) {
|
||||
|
||||
db::SaveLayoutOptions save_options;
|
||||
save_options.set_format_from_filename (output);
|
||||
std::string of = save_options.set_format_from_filename (output).second;
|
||||
writer_options.configure (save_options, *output_layout);
|
||||
|
||||
tl::OutputStream stream (output);
|
||||
tl::OutputStream stream (of);
|
||||
db::Writer writer (save_options);
|
||||
writer.write (*output_layout, stream);
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ INCLUDEPATH += $$RBA_INC
|
|||
DEPENDPATH += $$RBA_INC
|
||||
|
||||
equals(HAVE_RUBY, "1") {
|
||||
LIBS += -lklayout_rba
|
||||
LIBS += -lklayout_rba -lklayout_drc -lklayout_lvs
|
||||
} else {
|
||||
LIBS += -lklayout_rbastub
|
||||
}
|
||||
|
|
|
|||
|
|
@ -212,6 +212,34 @@ TEST(7)
|
|||
db::compare_layouts (this, layout, input, db::NoNormalization);
|
||||
}
|
||||
|
||||
// Small DEF example with explicit format
|
||||
TEST(8)
|
||||
{
|
||||
std::string input = tl::testdata ();
|
||||
input += "/lefdef/strm2oas_small/in.defok[def]";
|
||||
|
||||
std::string input_au = tl::testdata ();
|
||||
input_au += "/lefdef/strm2oas_small/au.gds";
|
||||
|
||||
std::string output = this->tmp_file ("small_def");
|
||||
|
||||
const char *argv[] = { "x", input.c_str (), output.c_str () };
|
||||
|
||||
EXPECT_EQ (bd::converter_main (sizeof (argv) / sizeof (argv[0]), (char **) argv, bd::GenericWriterOptions::oasis_format_name), 0);
|
||||
|
||||
db::Layout layout;
|
||||
|
||||
{
|
||||
tl::InputStream stream (output);
|
||||
db::LoadLayoutOptions options;
|
||||
db::Reader reader (stream);
|
||||
reader.read (layout, options);
|
||||
EXPECT_EQ (reader.format (), "OASIS");
|
||||
}
|
||||
|
||||
db::compare_layouts (this, layout, input_au, db::WriteGDS2);
|
||||
}
|
||||
|
||||
// Large LEF/DEF to OAS converter test
|
||||
TEST(10)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -97,6 +97,34 @@ TEST(2)
|
|||
tl::InputStream stream (output);
|
||||
db::Reader reader (stream);
|
||||
reader.read (layout);
|
||||
EXPECT_EQ (reader.format (), "GDS2");
|
||||
}
|
||||
|
||||
db::compare_layouts (this, layout, au, db::NoNormalization);
|
||||
}
|
||||
|
||||
// with explicit output format
|
||||
TEST(3)
|
||||
{
|
||||
std::string input = tl::testdata ();
|
||||
input += "/bd/strm2clip_in.gds";
|
||||
|
||||
std::string au = tl::testdata ();
|
||||
au += "/bd/strm2clip_au2.gds";
|
||||
|
||||
std::string output = this->tmp_file () + "[oas]";
|
||||
|
||||
const char *argv[] = { "x", input.c_str (), output.c_str (), "-r=0,-2,9,5", "-t", "INV2", "-x=CLIP_OUT" };
|
||||
|
||||
EXPECT_EQ (strmclip (sizeof (argv) / sizeof (argv[0]), (char **) argv), 0);
|
||||
|
||||
db::Layout layout;
|
||||
|
||||
{
|
||||
tl::InputStream stream (output);
|
||||
db::Reader reader (stream);
|
||||
reader.read (layout);
|
||||
EXPECT_EQ (reader.format (), "OASIS");
|
||||
}
|
||||
|
||||
db::compare_layouts (this, layout, au, db::NoNormalization);
|
||||
|
|
|
|||
|
|
@ -28,10 +28,7 @@
|
|||
TEST(1)
|
||||
{
|
||||
#if defined(HAVE_PYTHON)
|
||||
std::string fp (tl::testsrc ());
|
||||
fp += "/testdata/bd/strmrun.py";
|
||||
|
||||
std::string cmd;
|
||||
std::string cmd_call;
|
||||
|
||||
#if defined(__APPLE__)
|
||||
// NOTE: because of system integrity, MacOS does not inherit DYLD_LIBRARY_PATH to child
|
||||
|
|
@ -39,19 +36,42 @@ TEST(1)
|
|||
const char *ldpath_name = "DYLD_LIBRARY_PATH";
|
||||
const char *ldpath = getenv (ldpath_name);
|
||||
if (ldpath) {
|
||||
cmd += std::string (ldpath_name) + "=\"" + ldpath + "\"; export " + ldpath_name + "; ";
|
||||
cmd_call += std::string (ldpath_name) + "=\"" + ldpath + "\"; export " + ldpath_name + "; ";
|
||||
}
|
||||
#endif
|
||||
|
||||
cmd += tl::combine_path (tl::get_inst_path (), "strmrun ") + fp;
|
||||
tl::info << cmd;
|
||||
cmd_call += tl::combine_path (tl::get_inst_path (), "strmrun");
|
||||
|
||||
tl::InputPipe pipe (cmd);
|
||||
tl::InputStream is (pipe);
|
||||
std::string data = is.read_all ();
|
||||
tl::info << data;
|
||||
{
|
||||
std::string fp (tl::testsrc ());
|
||||
fp += "/testdata/bd/strmrun.py";
|
||||
|
||||
std::string cmd = cmd_call + " " + fp;
|
||||
tl::info << cmd;
|
||||
|
||||
tl::InputPipe pipe (cmd);
|
||||
tl::InputStream is (pipe);
|
||||
std::string data = is.read_all ();
|
||||
tl::info << data;
|
||||
|
||||
EXPECT_EQ (data, "Hello, world (0,-42;42,0)!\n");
|
||||
}
|
||||
|
||||
{
|
||||
std::string fp (tl::testsrc ());
|
||||
fp += "/testdata/bd/strmrun.drc";
|
||||
|
||||
std::string cmd = cmd_call + " " + fp;
|
||||
tl::info << cmd;
|
||||
|
||||
tl::InputPipe pipe (cmd);
|
||||
tl::InputStream is (pipe);
|
||||
std::string data = is.read_all ();
|
||||
tl::info << data;
|
||||
|
||||
EXPECT_EQ (data, "This is DRC.\n");
|
||||
}
|
||||
|
||||
EXPECT_EQ (data, "Hello, world (0,-42;42,0)!\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -97,6 +97,52 @@ TEST(1A_Flat)
|
|||
tl::InputStream stream (output);
|
||||
db::Reader reader (stream);
|
||||
reader.read (layout);
|
||||
|
||||
EXPECT_EQ (std::string (reader.format ()), "OASIS");
|
||||
}
|
||||
|
||||
db::compare_layouts (this, layout, au, db::NormalizationMode (db::NoNormalization | db::AsPolygons));
|
||||
EXPECT_EQ (cap.captured_text (),
|
||||
"Layer 10/0 is not present in first layout, but in second\n"
|
||||
"Result summary (layers without differences are not shown):\n"
|
||||
"\n"
|
||||
" Layer Output Differences (shape count)\n"
|
||||
" ----------------------------------------------------------------\n"
|
||||
" 3/0 3/0 30\n"
|
||||
" 6/0 6/0 41\n"
|
||||
" 8/1 8/1 1\n"
|
||||
" 10/0 - (no such layer in first layout)\n"
|
||||
"\n"
|
||||
);
|
||||
}
|
||||
|
||||
TEST(1A_FlatWithExplicitOutputFormat)
|
||||
{
|
||||
tl::CaptureChannel cap;
|
||||
|
||||
std::string input_a = tl::testdata ();
|
||||
input_a += "/bd/strmxor_in1.gds";
|
||||
|
||||
std::string input_b = tl::testdata ();
|
||||
input_b += "/bd/strmxor_in2.gds";
|
||||
|
||||
std::string au = tl::testdata ();
|
||||
au += "/bd/strmxor_au1.oas";
|
||||
|
||||
std::string output = this->tmp_file ("tmp.xxx[oas]");
|
||||
|
||||
const char *argv[] = { "x", input_a.c_str (), input_b.c_str (), output.c_str () };
|
||||
|
||||
EXPECT_EQ (strmxor (sizeof (argv) / sizeof (argv[0]), (char **) argv), 1);
|
||||
|
||||
db::Layout layout;
|
||||
|
||||
{
|
||||
tl::InputStream stream (output);
|
||||
db::Reader reader (stream);
|
||||
reader.read (layout);
|
||||
|
||||
EXPECT_EQ (std::string (reader.format ()), "OASIS");
|
||||
}
|
||||
|
||||
db::compare_layouts (this, layout, au, db::NormalizationMode (db::NoNormalization | db::AsPolygons));
|
||||
|
|
|
|||
|
|
@ -152,6 +152,7 @@ SOURCES = \
|
|||
gsiDeclDbRecursiveInstanceIterator.cc \
|
||||
gsiDeclDbRecursiveShapeIterator.cc \
|
||||
gsiDeclDbRegion.cc \
|
||||
gsiDeclDbSaveLayoutOptions.cc \
|
||||
gsiDeclDbShape.cc \
|
||||
gsiDeclDbShapeProcessor.cc \
|
||||
gsiDeclDbShapes.cc \
|
||||
|
|
|
|||
|
|
@ -113,9 +113,8 @@ EdgePairs::write (const std::string &fn) const
|
|||
unsigned int li = layout.insert_layer (db::LayerProperties (0, 0));
|
||||
insert_into (&layout, top.cell_index (), li);
|
||||
|
||||
tl::OutputStream os (fn);
|
||||
db::SaveLayoutOptions opt;
|
||||
opt.set_format_from_filename (fn);
|
||||
tl::OutputStream os (opt.set_format_from_filename (fn).second);
|
||||
db::Writer writer (opt);
|
||||
writer.write (layout, os);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -145,9 +145,8 @@ Edges::write (const std::string &fn) const
|
|||
unsigned int li = layout.insert_layer (db::LayerProperties (0, 0));
|
||||
insert_into (&layout, top.cell_index (), li);
|
||||
|
||||
tl::OutputStream os (fn);
|
||||
db::SaveLayoutOptions opt;
|
||||
opt.set_format_from_filename (fn);
|
||||
tl::OutputStream os (opt.set_format_from_filename (fn).second);
|
||||
db::Writer writer (opt);
|
||||
writer.write (layout, os);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -134,13 +134,26 @@ ReaderBase::check_dbu (double dbu) const
|
|||
Reader::Reader (tl::InputStream &stream)
|
||||
: mp_actual_reader (0), m_stream (stream)
|
||||
{
|
||||
// Detect the format by asking all reader declarations
|
||||
for (tl::Registrar<db::StreamFormatDeclaration>::iterator rdr = tl::Registrar<db::StreamFormatDeclaration>::begin (); rdr != tl::Registrar<db::StreamFormatDeclaration>::end () && ! mp_actual_reader; ++rdr) {
|
||||
m_stream.reset ();
|
||||
if (rdr->detect (m_stream)) {
|
||||
m_stream.reset ();
|
||||
mp_actual_reader = rdr->create_reader (m_stream);
|
||||
if (stream.is_explicit_suffix ()) {
|
||||
|
||||
// If an explicit suffix is given for the stream, use it to find the reader
|
||||
for (tl::Registrar<db::StreamFormatDeclaration>::iterator rdr = tl::Registrar<db::StreamFormatDeclaration>::begin (); rdr != tl::Registrar<db::StreamFormatDeclaration>::end () && ! mp_actual_reader; ++rdr) {
|
||||
if (tl::match_filename_to_format ("." + stream.suffix (), rdr->file_format ())) {
|
||||
mp_actual_reader = rdr->create_reader (m_stream);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// Detect the format by asking all reader declarations
|
||||
for (tl::Registrar<db::StreamFormatDeclaration>::iterator rdr = tl::Registrar<db::StreamFormatDeclaration>::begin (); rdr != tl::Registrar<db::StreamFormatDeclaration>::end () && ! mp_actual_reader; ++rdr) {
|
||||
m_stream.reset ();
|
||||
if (rdr->detect (m_stream)) {
|
||||
m_stream.reset ();
|
||||
mp_actual_reader = rdr->create_reader (m_stream);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (! mp_actual_reader) {
|
||||
|
|
|
|||
|
|
@ -142,9 +142,8 @@ Region::write (const std::string &fn) const
|
|||
unsigned int li = layout.insert_layer (db::LayerProperties (0, 0));
|
||||
insert_into (&layout, top.cell_index (), li);
|
||||
|
||||
tl::OutputStream os (fn);
|
||||
db::SaveLayoutOptions opt;
|
||||
opt.set_format_from_filename (fn);
|
||||
tl::OutputStream os (opt.set_format_from_filename (fn).second);
|
||||
db::Writer writer (opt);
|
||||
writer.write (layout, os);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include "tlStream.h"
|
||||
#include "tlExpression.h"
|
||||
#include "tlInternational.h"
|
||||
#include "tlGlobPattern.h"
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
|
@ -444,16 +445,33 @@ SaveLayoutOptions::get_cells (const db::Layout &layout, std::set <db::cell_index
|
|||
}
|
||||
}
|
||||
|
||||
bool
|
||||
std::pair<bool, std::string>
|
||||
SaveLayoutOptions::set_format_from_filename (const std::string &fn)
|
||||
{
|
||||
for (tl::Registrar<db::StreamFormatDeclaration>::iterator fmt = tl::Registrar<db::StreamFormatDeclaration>::begin (); fmt != tl::Registrar<db::StreamFormatDeclaration>::end (); ++fmt) {
|
||||
if (tl::match_filename_to_format (fn, fmt->file_format ())) {
|
||||
m_format = fmt->format_name ();
|
||||
return true;
|
||||
tl::GlobPattern pat ("(*)\\[(*)\\]");
|
||||
|
||||
std::vector<std::string> pat_parts;
|
||||
if (pat.match (fn, pat_parts) && pat_parts.size () == 2) {
|
||||
|
||||
for (tl::Registrar<db::StreamFormatDeclaration>::iterator fmt = tl::Registrar<db::StreamFormatDeclaration>::begin (); fmt != tl::Registrar<db::StreamFormatDeclaration>::end (); ++fmt) {
|
||||
if (tl::match_filename_to_format ("." + pat_parts[1], fmt->file_format ())) {
|
||||
m_format = fmt->format_name ();
|
||||
return std::make_pair (true, pat_parts[0]);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
for (tl::Registrar<db::StreamFormatDeclaration>::iterator fmt = tl::Registrar<db::StreamFormatDeclaration>::begin (); fmt != tl::Registrar<db::StreamFormatDeclaration>::end (); ++fmt) {
|
||||
if (tl::match_filename_to_format (fn, fmt->file_format ())) {
|
||||
m_format = fmt->format_name ();
|
||||
return std::make_pair (true, fn);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return false;
|
||||
|
||||
return std::make_pair (false, fn);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -268,7 +268,7 @@ public:
|
|||
*
|
||||
* Returns true, if the suffix indicates a known format.
|
||||
*/
|
||||
bool set_format_from_filename (const std::string &fn);
|
||||
std::pair<bool, std::string> set_format_from_filename(const std::string &fn);
|
||||
|
||||
/**
|
||||
* @brief Sets specific options for the given format
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ void compare_layouts (tl::TestBase *_this, const db::Layout &layout, const std::
|
|||
} else {
|
||||
// write the temp file in the same format than the au file
|
||||
tmp_file = _this->tmp_file (tl::sprintf ("tmp_%x." + tl::extension (au_file), hash));
|
||||
options.set_format_from_filename (tmp_file);
|
||||
tmp_file = options.set_format_from_filename (tmp_file).second;
|
||||
}
|
||||
|
||||
if ((norm & NoContext) != 0) {
|
||||
|
|
|
|||
|
|
@ -109,9 +109,8 @@ Texts::write (const std::string &fn) const
|
|||
unsigned int li = layout.insert_layer (db::LayerProperties (0, 0));
|
||||
insert_into (&layout, top.cell_index (), li);
|
||||
|
||||
tl::OutputStream os (fn);
|
||||
db::SaveLayoutOptions opt;
|
||||
opt.set_format_from_filename (fn);
|
||||
tl::OutputStream os (opt.set_format_from_filename (fn).second);
|
||||
db::Writer writer (opt);
|
||||
writer.write (layout, os);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1310,10 +1310,10 @@ write_simple (const db::Cell *cell, const std::string &filename)
|
|||
db::SaveLayoutOptions options;
|
||||
options.clear_cells ();
|
||||
options.add_cell (cell->cell_index ());
|
||||
options.set_format_from_filename (filename);
|
||||
std::string fn = options.set_format_from_filename (filename).second;
|
||||
|
||||
db::Writer writer (options);
|
||||
tl::OutputStream stream (filename);
|
||||
tl::OutputStream stream (fn);
|
||||
writer.write (*layout, stream);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -690,12 +690,13 @@ static void
|
|||
write_simple (db::Layout *layout, const std::string &filename)
|
||||
{
|
||||
db::SaveLayoutOptions options;
|
||||
if (! options.set_format_from_filename (filename)) {
|
||||
auto ff = options.set_format_from_filename (filename);
|
||||
if (! ff.first) {
|
||||
throw tl::Exception (tl::to_string (tr ("Cannot determine format from filename")));
|
||||
}
|
||||
|
||||
db::Writer writer (options);
|
||||
tl::OutputStream stream (filename);
|
||||
tl::OutputStream stream (ff.second);
|
||||
writer.write (*layout, stream);
|
||||
}
|
||||
|
||||
|
|
@ -2863,231 +2864,4 @@ Class<db::Layout> decl_Layout ("db", "Layout",
|
|||
"@/code\n"
|
||||
);
|
||||
|
||||
static db::SaveLayoutOptions *new_v ()
|
||||
{
|
||||
return new db::SaveLayoutOptions ();
|
||||
}
|
||||
|
||||
static bool set_format_from_filename (db::SaveLayoutOptions *opt, const std::string &fn)
|
||||
{
|
||||
if (! opt->set_format_from_filename (fn)) {
|
||||
throw tl::Exception (tl::to_string (tr ("Cannot determine format from filename")));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Class<db::SaveLayoutOptions> decl_SaveLayoutOptions ("db", "SaveLayoutOptions",
|
||||
gsi::constructor ("new", &new_v,
|
||||
"@brief Default constructor\n"
|
||||
"\n"
|
||||
"This will initialize the scale factor to 1.0, the database unit is set to\n"
|
||||
"\"same as original\" and all layers are selected as well as all cells.\n"
|
||||
"The default format is GDS2."
|
||||
) +
|
||||
gsi::method_ext ("set_format_from_filename", &set_format_from_filename, gsi::arg ("filename"),
|
||||
"@brief Select a format from the given file name\n"
|
||||
"\n"
|
||||
"This method will set the format according to the file's extension.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.22. "
|
||||
"Beginning with version 0.23, this method always returns true, since the "
|
||||
"only consumer for the return value, Layout#write, now ignores that "
|
||||
"parameter and automatically determines the compression mode from the file name.\n"
|
||||
) +
|
||||
gsi::method ("format=", &db::SaveLayoutOptions::set_format, gsi::arg ("format"),
|
||||
"@brief Select a format\n"
|
||||
"The format string can be either \"GDS2\", \"OASIS\", \"CIF\" or \"DXF\". Other formats may be available if\n"
|
||||
"a suitable plugin is installed."
|
||||
) +
|
||||
gsi::method ("format", &db::SaveLayoutOptions::format,
|
||||
"@brief Gets the format name\n"
|
||||
"\n"
|
||||
"See \\format= for a description of that method.\n"
|
||||
) +
|
||||
gsi::method ("add_layer", &db::SaveLayoutOptions::add_layer, gsi::arg ("layer_index"), gsi::arg ("properties"),
|
||||
"@brief Add a layer to be saved \n"
|
||||
"\n"
|
||||
"\n"
|
||||
"Adds the layer with the given index to the layer list that will be written.\n"
|
||||
"If all layers have been selected previously, all layers will \n"
|
||||
"be unselected first and only the new layer remains.\n"
|
||||
"\n"
|
||||
"The 'properties' argument can be used to assign different layer properties than the ones\n"
|
||||
"present in the layout. Pass a default \\LayerInfo object to this argument to use the\n"
|
||||
"properties from the layout object. Construct a valid \\LayerInfo object with explicit layer,\n"
|
||||
"datatype and possibly a name to override the properties stored in the layout.\n"
|
||||
) +
|
||||
gsi::method ("select_all_layers", &db::SaveLayoutOptions::select_all_layers,
|
||||
"@brief Select all layers to be saved\n"
|
||||
"\n"
|
||||
"This method will clear all layers selected with \\add_layer so far and set the 'select all layers' flag.\n"
|
||||
"This is the default.\n"
|
||||
) +
|
||||
gsi::method ("deselect_all_layers", &db::SaveLayoutOptions::deselect_all_layers,
|
||||
"@brief Unselect all layers: no layer will be saved\n"
|
||||
"\n"
|
||||
"This method will clear all layers selected with \\add_layer so far and clear the 'select all layers' flag.\n"
|
||||
"Using this method is the only way to save a layout without any layers."
|
||||
) +
|
||||
gsi::method ("select_cell", &db::SaveLayoutOptions::select_cell, gsi::arg ("cell_index"),
|
||||
"@brief Selects a cell to be saved (plus hierarchy below)\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"This method is basically a convenience method that combines \\clear_cells and \\add_cell.\n"
|
||||
"This method clears the 'select all cells' flag.\n"
|
||||
"\n"
|
||||
"This method has been added in version 0.22.\n"
|
||||
) +
|
||||
gsi::method ("select_this_cell", &db::SaveLayoutOptions::select_this_cell, gsi::arg ("cell_index"),
|
||||
"@brief Selects a cell to be saved\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"This method is basically a convenience method that combines \\clear_cells and \\add_this_cell.\n"
|
||||
"This method clears the 'select all cells' flag.\n"
|
||||
"\n"
|
||||
"This method has been added in version 0.23.\n"
|
||||
) +
|
||||
gsi::method ("clear_cells", &db::SaveLayoutOptions::clear_cells,
|
||||
"@brief Clears all cells to be saved\n"
|
||||
"\n"
|
||||
"This method can be used to ensure that no cell is selected before \\add_cell is called to specify a cell.\n"
|
||||
"This method clears the 'select all cells' flag.\n"
|
||||
"\n"
|
||||
"This method has been added in version 0.22.\n"
|
||||
) +
|
||||
gsi::method ("add_this_cell", &db::SaveLayoutOptions::add_this_cell, gsi::arg ("cell_index"),
|
||||
"@brief Adds a cell to be saved\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"The index of the cell must be a valid index in the context of the layout that will be saved.\n"
|
||||
"This method clears the 'select all cells' flag.\n"
|
||||
"Unlike \\add_cell, this method does not implicitly add all children of that cell.\n"
|
||||
"\n"
|
||||
"This method has been added in version 0.23.\n"
|
||||
) +
|
||||
gsi::method ("add_cell", &db::SaveLayoutOptions::add_cell, gsi::arg ("cell_index"),
|
||||
"@brief Add a cell (plus hierarchy) to be saved\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"The index of the cell must be a valid index in the context of the layout that will be saved.\n"
|
||||
"This method clears the 'select all cells' flag.\n"
|
||||
"\n"
|
||||
"This method also implicitly adds the children of that cell. A method that does not add the "
|
||||
"children in \\add_this_cell.\n"
|
||||
) +
|
||||
gsi::method ("select_all_cells", &db::SaveLayoutOptions::select_all_cells,
|
||||
"@brief Select all cells to save\n"
|
||||
"\n"
|
||||
"This method will clear all cells specified with \\add_cells so far and set the 'select all cells' flag.\n"
|
||||
"This is the default.\n"
|
||||
) +
|
||||
gsi::method ("write_context_info=", &db::SaveLayoutOptions::set_write_context_info, gsi::arg ("flag"),
|
||||
"@brief Enables or disables context information\n"
|
||||
"\n"
|
||||
"If this flag is set to false, no context information for PCell or library cell instances is written. "
|
||||
"Those cells will be converted to plain cells and KLayout will not be able to restore the identity of "
|
||||
"those cells. Use this option to enforce compatibility with other tools that don't understand the "
|
||||
"context information of KLayout.\n"
|
||||
"\n"
|
||||
"The default value is true (context information is stored). Not all formats support context information, hence "
|
||||
"that flag has no effect for formats like CIF or DXF.\n"
|
||||
"\n"
|
||||
"This method was introduced in version 0.23.\n"
|
||||
) +
|
||||
gsi::method ("write_context_info?", &db::SaveLayoutOptions::write_context_info,
|
||||
"@brief Gets a flag indicating whether context information will be stored\n"
|
||||
"\n"
|
||||
"See \\write_context_info= for details about this flag.\n"
|
||||
"\n"
|
||||
"This method was introduced in version 0.23.\n"
|
||||
) +
|
||||
gsi::method ("keep_instances=", &db::SaveLayoutOptions::set_keep_instances, gsi::arg ("flag"),
|
||||
"@brief Enables or disables instances for dropped cells\n"
|
||||
"\n"
|
||||
"If this flag is set to true, instances for cells will be written, even if the cell is dropped. "
|
||||
"That may happen, if cells are selected with \\select_this_cell or \\add_this_cell or \\no_empty_cells is used. "
|
||||
"Even if cells called by such cells are not selected, instances will be written for that "
|
||||
"cell if \"keep_instances\" is true. That feature is supported by the GDS format currently and "
|
||||
"results in \"ghost cells\" which have instances but no cell definition.\n"
|
||||
"\n"
|
||||
"The default value is false (instances of dropped cells are not written).\n"
|
||||
"\n"
|
||||
"This method was introduced in version 0.23.\n"
|
||||
) +
|
||||
gsi::method ("keep_instances?", &db::SaveLayoutOptions::keep_instances,
|
||||
"@brief Gets a flag indicating whether instances will be kept even if the target cell is dropped\n"
|
||||
"\n"
|
||||
"See \\keep_instances= for details about this flag.\n"
|
||||
"\n"
|
||||
"This method was introduced in version 0.23.\n"
|
||||
) +
|
||||
gsi::method ("dbu=", &db::SaveLayoutOptions::set_dbu, gsi::arg ("dbu"),
|
||||
"@brief Sets the database unit to be used in the stream file\n"
|
||||
"\n"
|
||||
"By default, the database unit of the layout is used. This method allows one to explicitly use a different\n"
|
||||
"database unit. A scale factor is introduced automatically which scales all layout objects accordingly so their physical dimensions remain the same. "
|
||||
"When scaling to a larger database unit or one that is not an integer fraction of the original one, rounding errors may occur and the "
|
||||
"layout may become slightly distorted."
|
||||
) +
|
||||
gsi::method ("dbu", &db::SaveLayoutOptions::dbu,
|
||||
"@brief Gets the explicit database unit if one is set\n"
|
||||
"\n"
|
||||
"See \\dbu= for a description of that attribute.\n"
|
||||
) +
|
||||
gsi::method ("no_empty_cells=", &db::SaveLayoutOptions::set_dont_write_empty_cells, gsi::arg ("flag"),
|
||||
"@brief Don't write empty cells if this flag is set\n"
|
||||
"\n"
|
||||
"By default, all cells are written (no_empty_cells is false).\n"
|
||||
"This applies to empty cells which do not contain shapes for the specified layers "
|
||||
"as well as cells which are empty because they reference empty cells only.\n"
|
||||
) +
|
||||
gsi::method ("no_empty_cells?", &db::SaveLayoutOptions::dont_write_empty_cells,
|
||||
"@brief Returns a flag indicating whether empty cells are not written.\n"
|
||||
) +
|
||||
gsi::method ("libname=|#gds2_libname=", &db::SaveLayoutOptions::set_libname, gsi::arg ("libname"),
|
||||
"@brief Sets the library name\n"
|
||||
"\n"
|
||||
"The library name is an attribute and specifies a formal name for a library, if the layout files is to be used as one.\n"
|
||||
"Currently, this attribute is only supported by the GDS2 format. Hence the alias.\n"
|
||||
"\n"
|
||||
"By default or if the libname is an empty string, the current library name of the layout or 'LIB' is used.\n"
|
||||
"\n"
|
||||
"The 'libname' alias has been introduced in version 0.30.5. The original name \\gds2_libname= is still available."
|
||||
) +
|
||||
gsi::method ("libname|#gds2_libname", &db::SaveLayoutOptions::libname,
|
||||
"@brief Gets the library name\n"
|
||||
"\n"
|
||||
"See \\libname= for details.\n"
|
||||
"The 'libname' alias has been introduced in version 0.30.5. The original name \\gds2_libname is still available."
|
||||
) +
|
||||
gsi::method ("scale_factor=", &db::SaveLayoutOptions::set_scale_factor, gsi::arg ("scale_factor"),
|
||||
"@brief Sets the scaling factor for the saving \n"
|
||||
"\n"
|
||||
"Using a scaling factor will scale all objects accordingly. "
|
||||
"This scale factor adds to a potential scaling implied by using an explicit database unit.\n"
|
||||
"\n"
|
||||
"Be aware that rounding effects may occur if fractional scaling factors are used.\n"
|
||||
"\n"
|
||||
"By default, no scaling is applied."
|
||||
) +
|
||||
gsi::method ("scale_factor", &db::SaveLayoutOptions::scale_factor,
|
||||
"@brief Gets the scaling factor currently set\n"
|
||||
),
|
||||
"@brief Options for saving layouts\n"
|
||||
"\n"
|
||||
"This class describes the various options for saving a layout to a stream file (GDS2, OASIS and others).\n"
|
||||
"There are: layers to be saved, cell or cells to be saved, scale factor, format, database unit\n"
|
||||
"and format specific options.\n"
|
||||
"\n"
|
||||
"Usually the default constructor provides a suitable object. Please note, that the format written is \"GDS2\" by default. Either explicitly set a "
|
||||
"format using \\format= or derive the format from the file name using \\set_format_from_filename.\n"
|
||||
"\n"
|
||||
"The layers are specified by either selecting all layers or by defining layer by layer using the\n"
|
||||
"\\add_layer method. \\select_all_layers will explicitly select all layers for saving, \\deselect_all_layers will explicitly clear the list of layers.\n"
|
||||
"\n"
|
||||
"Cells are selected in a similar fashion: by default, all cells are selected. Using \\add_cell, specific\n"
|
||||
"cells can be selected for saving. All these cells plus their hierarchy will then be written to the stream file.\n"
|
||||
"\n"
|
||||
);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,262 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2026 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#include "gsiDecl.h"
|
||||
#include "dbSaveLayoutOptions.h"
|
||||
|
||||
namespace gsi
|
||||
{
|
||||
|
||||
static db::SaveLayoutOptions *new_v ()
|
||||
{
|
||||
return new db::SaveLayoutOptions ();
|
||||
}
|
||||
|
||||
static std::string set_format_from_filename (db::SaveLayoutOptions *opt, const std::string &fn)
|
||||
{
|
||||
auto ff = opt->set_format_from_filename (fn);
|
||||
if (! ff.first) {
|
||||
throw tl::Exception (tl::to_string (tr ("Cannot determine format from filename")));
|
||||
}
|
||||
return ff.second;
|
||||
}
|
||||
|
||||
Class<db::SaveLayoutOptions> decl_SaveLayoutOptions ("db", "SaveLayoutOptions",
|
||||
gsi::constructor ("new", &new_v,
|
||||
"@brief Default constructor\n"
|
||||
"\n"
|
||||
"This will initialize the scale factor to 1.0, the database unit is set to\n"
|
||||
"\"same as original\" and all layers are selected as well as all cells.\n"
|
||||
"The default format is GDS2."
|
||||
) +
|
||||
gsi::method_ext ("set_format_from_filename", &set_format_from_filename, gsi::arg ("filename"),
|
||||
"@brief Select a format from the given file name\n"
|
||||
"\n"
|
||||
"This method will set the format according to the file's extension.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.22. "
|
||||
"Beginning with version 0.23, this method always returns true, since the "
|
||||
"only consumer for the return value, Layout#write, now ignores that "
|
||||
"parameter and automatically determines the compression mode from the file name.\n"
|
||||
"\n"
|
||||
"Starting with version 0.30.8, this method allows specifying the desired format's extension in square brackets "
|
||||
"after the file name (e.g. 'file.txt[def]'). This allows writing files with non-standard extensions. "
|
||||
"The return value of this function now is the actual file name used without the square brackets ('file.txt' in the example case)."
|
||||
) +
|
||||
gsi::method ("format=", &db::SaveLayoutOptions::set_format, gsi::arg ("format"),
|
||||
"@brief Select a format\n"
|
||||
"The format string can be either \"GDS2\", \"OASIS\", \"CIF\" or \"DXF\". Other formats may be available if\n"
|
||||
"a suitable plugin is installed."
|
||||
) +
|
||||
gsi::method ("format", &db::SaveLayoutOptions::format,
|
||||
"@brief Gets the format name\n"
|
||||
"\n"
|
||||
"See \\format= for a description of that method.\n"
|
||||
) +
|
||||
gsi::method ("add_layer", &db::SaveLayoutOptions::add_layer, gsi::arg ("layer_index"), gsi::arg ("properties"),
|
||||
"@brief Add a layer to be saved \n"
|
||||
"\n"
|
||||
"\n"
|
||||
"Adds the layer with the given index to the layer list that will be written.\n"
|
||||
"If all layers have been selected previously, all layers will \n"
|
||||
"be unselected first and only the new layer remains.\n"
|
||||
"\n"
|
||||
"The 'properties' argument can be used to assign different layer properties than the ones\n"
|
||||
"present in the layout. Pass a default \\LayerInfo object to this argument to use the\n"
|
||||
"properties from the layout object. Construct a valid \\LayerInfo object with explicit layer,\n"
|
||||
"datatype and possibly a name to override the properties stored in the layout.\n"
|
||||
) +
|
||||
gsi::method ("select_all_layers", &db::SaveLayoutOptions::select_all_layers,
|
||||
"@brief Select all layers to be saved\n"
|
||||
"\n"
|
||||
"This method will clear all layers selected with \\add_layer so far and set the 'select all layers' flag.\n"
|
||||
"This is the default.\n"
|
||||
) +
|
||||
gsi::method ("deselect_all_layers", &db::SaveLayoutOptions::deselect_all_layers,
|
||||
"@brief Unselect all layers: no layer will be saved\n"
|
||||
"\n"
|
||||
"This method will clear all layers selected with \\add_layer so far and clear the 'select all layers' flag.\n"
|
||||
"Using this method is the only way to save a layout without any layers."
|
||||
) +
|
||||
gsi::method ("select_cell", &db::SaveLayoutOptions::select_cell, gsi::arg ("cell_index"),
|
||||
"@brief Selects a cell to be saved (plus hierarchy below)\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"This method is basically a convenience method that combines \\clear_cells and \\add_cell.\n"
|
||||
"This method clears the 'select all cells' flag.\n"
|
||||
"\n"
|
||||
"This method has been added in version 0.22.\n"
|
||||
) +
|
||||
gsi::method ("select_this_cell", &db::SaveLayoutOptions::select_this_cell, gsi::arg ("cell_index"),
|
||||
"@brief Selects a cell to be saved\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"This method is basically a convenience method that combines \\clear_cells and \\add_this_cell.\n"
|
||||
"This method clears the 'select all cells' flag.\n"
|
||||
"\n"
|
||||
"This method has been added in version 0.23.\n"
|
||||
) +
|
||||
gsi::method ("clear_cells", &db::SaveLayoutOptions::clear_cells,
|
||||
"@brief Clears all cells to be saved\n"
|
||||
"\n"
|
||||
"This method can be used to ensure that no cell is selected before \\add_cell is called to specify a cell.\n"
|
||||
"This method clears the 'select all cells' flag.\n"
|
||||
"\n"
|
||||
"This method has been added in version 0.22.\n"
|
||||
) +
|
||||
gsi::method ("add_this_cell", &db::SaveLayoutOptions::add_this_cell, gsi::arg ("cell_index"),
|
||||
"@brief Adds a cell to be saved\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"The index of the cell must be a valid index in the context of the layout that will be saved.\n"
|
||||
"This method clears the 'select all cells' flag.\n"
|
||||
"Unlike \\add_cell, this method does not implicitly add all children of that cell.\n"
|
||||
"\n"
|
||||
"This method has been added in version 0.23.\n"
|
||||
) +
|
||||
gsi::method ("add_cell", &db::SaveLayoutOptions::add_cell, gsi::arg ("cell_index"),
|
||||
"@brief Add a cell (plus hierarchy) to be saved\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"The index of the cell must be a valid index in the context of the layout that will be saved.\n"
|
||||
"This method clears the 'select all cells' flag.\n"
|
||||
"\n"
|
||||
"This method also implicitly adds the children of that cell. A method that does not add the "
|
||||
"children in \\add_this_cell.\n"
|
||||
) +
|
||||
gsi::method ("select_all_cells", &db::SaveLayoutOptions::select_all_cells,
|
||||
"@brief Select all cells to save\n"
|
||||
"\n"
|
||||
"This method will clear all cells specified with \\add_cells so far and set the 'select all cells' flag.\n"
|
||||
"This is the default.\n"
|
||||
) +
|
||||
gsi::method ("write_context_info=", &db::SaveLayoutOptions::set_write_context_info, gsi::arg ("flag"),
|
||||
"@brief Enables or disables context information\n"
|
||||
"\n"
|
||||
"If this flag is set to false, no context information for PCell or library cell instances is written. "
|
||||
"Those cells will be converted to plain cells and KLayout will not be able to restore the identity of "
|
||||
"those cells. Use this option to enforce compatibility with other tools that don't understand the "
|
||||
"context information of KLayout.\n"
|
||||
"\n"
|
||||
"The default value is true (context information is stored). Not all formats support context information, hence "
|
||||
"that flag has no effect for formats like CIF or DXF.\n"
|
||||
"\n"
|
||||
"This method was introduced in version 0.23.\n"
|
||||
) +
|
||||
gsi::method ("write_context_info?", &db::SaveLayoutOptions::write_context_info,
|
||||
"@brief Gets a flag indicating whether context information will be stored\n"
|
||||
"\n"
|
||||
"See \\write_context_info= for details about this flag.\n"
|
||||
"\n"
|
||||
"This method was introduced in version 0.23.\n"
|
||||
) +
|
||||
gsi::method ("keep_instances=", &db::SaveLayoutOptions::set_keep_instances, gsi::arg ("flag"),
|
||||
"@brief Enables or disables instances for dropped cells\n"
|
||||
"\n"
|
||||
"If this flag is set to true, instances for cells will be written, even if the cell is dropped. "
|
||||
"That may happen, if cells are selected with \\select_this_cell or \\add_this_cell or \\no_empty_cells is used. "
|
||||
"Even if cells called by such cells are not selected, instances will be written for that "
|
||||
"cell if \"keep_instances\" is true. That feature is supported by the GDS format currently and "
|
||||
"results in \"ghost cells\" which have instances but no cell definition.\n"
|
||||
"\n"
|
||||
"The default value is false (instances of dropped cells are not written).\n"
|
||||
"\n"
|
||||
"This method was introduced in version 0.23.\n"
|
||||
) +
|
||||
gsi::method ("keep_instances?", &db::SaveLayoutOptions::keep_instances,
|
||||
"@brief Gets a flag indicating whether instances will be kept even if the target cell is dropped\n"
|
||||
"\n"
|
||||
"See \\keep_instances= for details about this flag.\n"
|
||||
"\n"
|
||||
"This method was introduced in version 0.23.\n"
|
||||
) +
|
||||
gsi::method ("dbu=", &db::SaveLayoutOptions::set_dbu, gsi::arg ("dbu"),
|
||||
"@brief Sets the database unit to be used in the stream file\n"
|
||||
"\n"
|
||||
"By default, the database unit of the layout is used. This method allows one to explicitly use a different\n"
|
||||
"database unit. A scale factor is introduced automatically which scales all layout objects accordingly so their physical dimensions remain the same. "
|
||||
"When scaling to a larger database unit or one that is not an integer fraction of the original one, rounding errors may occur and the "
|
||||
"layout may become slightly distorted."
|
||||
) +
|
||||
gsi::method ("dbu", &db::SaveLayoutOptions::dbu,
|
||||
"@brief Gets the explicit database unit if one is set\n"
|
||||
"\n"
|
||||
"See \\dbu= for a description of that attribute.\n"
|
||||
) +
|
||||
gsi::method ("no_empty_cells=", &db::SaveLayoutOptions::set_dont_write_empty_cells, gsi::arg ("flag"),
|
||||
"@brief Don't write empty cells if this flag is set\n"
|
||||
"\n"
|
||||
"By default, all cells are written (no_empty_cells is false).\n"
|
||||
"This applies to empty cells which do not contain shapes for the specified layers "
|
||||
"as well as cells which are empty because they reference empty cells only.\n"
|
||||
) +
|
||||
gsi::method ("no_empty_cells?", &db::SaveLayoutOptions::dont_write_empty_cells,
|
||||
"@brief Returns a flag indicating whether empty cells are not written.\n"
|
||||
) +
|
||||
gsi::method ("libname=|#gds2_libname=", &db::SaveLayoutOptions::set_libname, gsi::arg ("libname"),
|
||||
"@brief Sets the library name\n"
|
||||
"\n"
|
||||
"The library name is an attribute and specifies a formal name for a library, if the layout files is to be used as one.\n"
|
||||
"Currently, this attribute is only supported by the GDS2 format. Hence the alias.\n"
|
||||
"\n"
|
||||
"By default or if the libname is an empty string, the current library name of the layout or 'LIB' is used.\n"
|
||||
"\n"
|
||||
"The 'libname' alias has been introduced in version 0.30.5. The original name \\gds2_libname= is still available."
|
||||
) +
|
||||
gsi::method ("libname|#gds2_libname", &db::SaveLayoutOptions::libname,
|
||||
"@brief Gets the library name\n"
|
||||
"\n"
|
||||
"See \\libname= for details.\n"
|
||||
"The 'libname' alias has been introduced in version 0.30.5. The original name \\gds2_libname is still available."
|
||||
) +
|
||||
gsi::method ("scale_factor=", &db::SaveLayoutOptions::set_scale_factor, gsi::arg ("scale_factor"),
|
||||
"@brief Sets the scaling factor for the saving \n"
|
||||
"\n"
|
||||
"Using a scaling factor will scale all objects accordingly. "
|
||||
"This scale factor adds to a potential scaling implied by using an explicit database unit.\n"
|
||||
"\n"
|
||||
"Be aware that rounding effects may occur if fractional scaling factors are used.\n"
|
||||
"\n"
|
||||
"By default, no scaling is applied."
|
||||
) +
|
||||
gsi::method ("scale_factor", &db::SaveLayoutOptions::scale_factor,
|
||||
"@brief Gets the scaling factor currently set\n"
|
||||
),
|
||||
"@brief Options for saving layouts\n"
|
||||
"\n"
|
||||
"This class describes the various options for saving a layout to a stream file (GDS2, OASIS and others).\n"
|
||||
"There are: layers to be saved, cell or cells to be saved, scale factor, format, database unit\n"
|
||||
"and format specific options.\n"
|
||||
"\n"
|
||||
"Usually the default constructor provides a suitable object. Please note, that the format written is \"GDS2\" by default. Either explicitly set a "
|
||||
"format using \\format= or derive the format from the file name using \\set_format_from_filename.\n"
|
||||
"\n"
|
||||
"The layers are specified by either selecting all layers or by defining layer by layer using the\n"
|
||||
"\\add_layer method. \\select_all_layers will explicitly select all layers for saving, \\deselect_all_layers will explicitly clear the list of layers.\n"
|
||||
"\n"
|
||||
"Cells are selected in a similar fashion: by default, all cells are selected. Using \\add_cell, specific\n"
|
||||
"cells can be selected for saving. All these cells plus their hierarchy will then be written to the stream file.\n"
|
||||
"\n"
|
||||
);
|
||||
|
||||
}
|
||||
|
|
@ -102,3 +102,17 @@ TEST(1)
|
|||
EXPECT_EQ (opt.get_option_by_name ("mywriter_value").to_string (), "17");
|
||||
}
|
||||
|
||||
TEST(2)
|
||||
{
|
||||
db::SaveLayoutOptions opt;
|
||||
auto ff = opt.set_format_from_filename ("/home/xyz/test.def");
|
||||
EXPECT_EQ (ff.first, true);
|
||||
EXPECT_EQ (ff.second, "/home/xyz/test.def");
|
||||
EXPECT_EQ (opt.format (), "LEFDEF");
|
||||
|
||||
opt = db::SaveLayoutOptions ();
|
||||
ff = opt.set_format_from_filename ("/home/xyz/test.txt[def]");
|
||||
EXPECT_EQ (ff.first, true);
|
||||
EXPECT_EQ (ff.second, "/home/xyz/test.txt");
|
||||
EXPECT_EQ (opt.format (), "LEFDEF");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -164,7 +164,7 @@ module DRC
|
|||
|
||||
def initialize
|
||||
|
||||
cv = RBA::CellView::active
|
||||
cv = RBA.const_defined?(:CellView) && RBA::CellView::active
|
||||
|
||||
@time = Time::now
|
||||
@force_gc = ($drc_force_gc == true) # for testing, $drc_force_gc can be set to true
|
||||
|
|
@ -1444,7 +1444,7 @@ module DRC
|
|||
|
||||
if arg =~ /^@(\d+)/
|
||||
n = $1.to_i - 1
|
||||
view = RBA::LayoutView::current
|
||||
view = RBA.const_defined?(:LayoutView) && RBA::LayoutView::current
|
||||
view || raise("No view open")
|
||||
(n >= 0 && view.cellviews > n) || raise("Invalid layout index @#{n + 1}")
|
||||
cv = view.cellview(n)
|
||||
|
|
@ -1543,7 +1543,7 @@ module DRC
|
|||
|
||||
if arg =~ /^@(\d+)/
|
||||
n = $1.to_i - 1
|
||||
view = RBA::LayoutView::current
|
||||
view = RBA.const_defined?(:LayoutView) && RBA::LayoutView::current
|
||||
view || raise("No view open")
|
||||
(n >= 0 && view.cellviews > n) || raise("Invalid layout index @#{n + 1}")
|
||||
cv = view.cellview(n)
|
||||
|
|
@ -1608,7 +1608,7 @@ module DRC
|
|||
self._context("report") do
|
||||
|
||||
# finish what we got so far
|
||||
view = RBA::LayoutView::current
|
||||
view = RBA.const_defined?(:LayoutView) && RBA::LayoutView::current
|
||||
@def_output && @def_output.finish(false, view)
|
||||
|
||||
@def_output = nil
|
||||
|
|
@ -2925,7 +2925,7 @@ CODE
|
|||
def _start(job_description)
|
||||
|
||||
# clearing the selection avoids some nasty problems
|
||||
view = RBA::LayoutView::current
|
||||
view = RBA.const_defined?(:LayoutView) && RBA::LayoutView::current
|
||||
view && view.cancel
|
||||
|
||||
@total_timer = RBA::Timer::new
|
||||
|
|
@ -2950,7 +2950,7 @@ CODE
|
|||
|
||||
_flush
|
||||
|
||||
view = RBA::LayoutView::current
|
||||
view = RBA.const_defined?(:LayoutView) && RBA::LayoutView::current
|
||||
|
||||
@def_output && @def_output.finish(final, view)
|
||||
|
||||
|
|
@ -3484,7 +3484,7 @@ CODE
|
|||
|
||||
output_rdb_index = nil
|
||||
|
||||
view = RBA::LayoutView::current
|
||||
view = RBA.const_defined?(:LayoutView) && RBA::LayoutView::current
|
||||
if view
|
||||
if self._rdb_index
|
||||
output_rdb = RBA::ReportDatabase::new("") # reuse existing name
|
||||
|
|
@ -3518,7 +3518,7 @@ CODE
|
|||
|
||||
if arg =~ /^@(\d+|\+)/
|
||||
|
||||
view = RBA::LayoutView::current
|
||||
view = RBA.const_defined?(:LayoutView) && RBA::LayoutView::current
|
||||
view || raise("No view open")
|
||||
if $1 == "+"
|
||||
prev_cv = view.active_cellview_index
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>561</width>
|
||||
<height>323</height>
|
||||
<width>586</width>
|
||||
<height>431</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
|
|
@ -20,32 +20,6 @@
|
|||
<property name="margin" stdset="0">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>The selection will be copied row * columns times. Each copy will be displaced by a vector given by the row vector times the row index and the column vector times the column index.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>10</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="array_grp">
|
||||
<property name="sizePolicy">
|
||||
|
|
@ -61,144 +35,248 @@
|
|||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QGridLayout">
|
||||
<property name="margin" stdset="0">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="3" column="3">
|
||||
<widget class="QLineEdit" name="row_x_le">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
<item row="3" column="0" colspan="5">
|
||||
<widget class="QTabWidget" name="mode_tab">
|
||||
<property name="currentIndex">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="tab">
|
||||
<attribute name="title">
|
||||
<string>Array with pitch vectors</string>
|
||||
</attribute>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0" colspan="5">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string> Each copy will be displaced by a vector given by the row vector times the row index and the column vector times the column index.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="3">
|
||||
<widget class="QLabel" name="label_15">
|
||||
<property name="text">
|
||||
<string>y =</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QLineEdit" name="column_x_le">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_16">
|
||||
<property name="text">
|
||||
<string> Column vector (x,y)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="label_14">
|
||||
<property name="text">
|
||||
<string>x =</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="4">
|
||||
<widget class="QLineEdit" name="column_y_le">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QLineEdit" name="row_x_le">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLabel" name="label_11">
|
||||
<property name="text">
|
||||
<string>x =</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="3">
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="text">
|
||||
<string>y =</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="4">
|
||||
<widget class="QLineEdit" name="row_y_le">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="text">
|
||||
<string> Row vector (x,y)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="5">
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_2">
|
||||
<attribute name="title">
|
||||
<string>Array with space</string>
|
||||
</attribute>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_17">
|
||||
<property name="text">
|
||||
<string>Space</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QLineEdit" name="space_x_le">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="4">
|
||||
<widget class="QLineEdit" name="space_y_le">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>30</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="1" column="5">
|
||||
<spacer name="horizontalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="label_18">
|
||||
<property name="text">
|
||||
<string>horizonal =</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="3">
|
||||
<widget class="QLabel" name="label_13">
|
||||
<property name="text">
|
||||
<string>vertical =</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="6">
|
||||
<widget class="QCheckBox" name="vis_only_cbx">
|
||||
<property name="text">
|
||||
<string>Use visible layers only for bounding boxes of instances</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="6">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>The selection is placed in a rectangular array, with the bounding box defining the pitch. Additional space can be added between columns and rows.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<widget class="QLabel" name="label_11">
|
||||
<item row="0" column="0" colspan="5">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>x =</string>
|
||||
<string>The selection will be copied row * columns times.</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="5">
|
||||
<widget class="QLineEdit" name="column_y_le">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="3">
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="text">
|
||||
<string>Columns =</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="4">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>Rows =</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<widget class="QLineEdit" name="columns_le">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0" colspan="2">
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="text">
|
||||
<string> Row vector (x,y)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="2">
|
||||
<widget class="QLabel" name="label_16">
|
||||
<property name="text">
|
||||
<string> Column vector (x,y)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="5">
|
||||
<widget class="QLineEdit" name="row_y_le">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QLabel" name="label_14">
|
||||
<property name="text">
|
||||
<string>x =</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="3">
|
||||
<widget class="QLineEdit" name="column_x_le">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="5">
|
||||
<widget class="QLineEdit" name="rows_le">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="4">
|
||||
<widget class="QLabel" name="label_15">
|
||||
<property name="text">
|
||||
<string>y =</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="4">
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="text">
|
||||
<string>y =</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="6">
|
||||
<item row="2" column="0" colspan="5">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
|
|
@ -214,6 +292,59 @@
|
|||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="text">
|
||||
<string>Columns =</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="columns_le">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>Rows =</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="3">
|
||||
<widget class="QLineEdit" name="rows_le">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="4">
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
@ -271,10 +402,14 @@
|
|||
<tabstops>
|
||||
<tabstop>columns_le</tabstop>
|
||||
<tabstop>rows_le</tabstop>
|
||||
<tabstop>mode_tab</tabstop>
|
||||
<tabstop>column_x_le</tabstop>
|
||||
<tabstop>column_y_le</tabstop>
|
||||
<tabstop>row_x_le</tabstop>
|
||||
<tabstop>row_y_le</tabstop>
|
||||
<tabstop>space_x_le</tabstop>
|
||||
<tabstop>space_y_le</tabstop>
|
||||
<tabstop>vis_only_cbx</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections>
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
#include "dbLayout.h"
|
||||
|
||||
#include "edtDialogs.h"
|
||||
#include "edtMainService.h"
|
||||
#include "layEditorUtils.h"
|
||||
#include "layObjectInstPath.h"
|
||||
#include "layCellView.h"
|
||||
|
|
@ -646,29 +647,41 @@ MakeArrayOptionsDialog::MakeArrayOptionsDialog (QWidget *parent)
|
|||
}
|
||||
|
||||
bool
|
||||
MakeArrayOptionsDialog::exec_dialog (db::DVector &a, unsigned int &na, db::DVector &b, unsigned int &nb)
|
||||
MakeArrayOptionsDialog::exec_dialog (ArrayOptions &options)
|
||||
{
|
||||
rows_le->setText (tl::to_qstring (tl::to_string (na)));
|
||||
columns_le->setText (tl::to_qstring (tl::to_string (nb)));
|
||||
row_x_le->setText (tl::to_qstring (tl::micron_to_string (a.x ())));
|
||||
row_y_le->setText (tl::to_qstring (tl::micron_to_string (a.y ())));
|
||||
column_x_le->setText (tl::to_qstring (tl::micron_to_string (b.x ())));
|
||||
column_y_le->setText (tl::to_qstring (tl::micron_to_string (b.y ())));
|
||||
rows_le->setText (tl::to_qstring (tl::to_string (options.na)));
|
||||
columns_le->setText (tl::to_qstring (tl::to_string (options.nb)));
|
||||
row_x_le->setText (tl::to_qstring (tl::micron_to_string (options.a.x ())));
|
||||
row_y_le->setText (tl::to_qstring (tl::micron_to_string (options.a.y ())));
|
||||
column_x_le->setText (tl::to_qstring (tl::micron_to_string (options.b.x ())));
|
||||
column_y_le->setText (tl::to_qstring (tl::micron_to_string (options.b.y ())));
|
||||
space_x_le->setText (tl::to_qstring (tl::micron_to_string (options.space.x ())));
|
||||
space_y_le->setText (tl::to_qstring (tl::micron_to_string (options.space.y ())));
|
||||
|
||||
mode_tab->setCurrentIndex (options.mode == ArrayOptions::PitchVectors ? 0 : 1);
|
||||
vis_only_cbx->setChecked (options.use_visible_layers);
|
||||
|
||||
if (QDialog::exec ()) {
|
||||
|
||||
options.mode = mode_tab->currentIndex () == 0 ? ArrayOptions::PitchVectors : ArrayOptions::Spaced;
|
||||
options.use_visible_layers = vis_only_cbx->isChecked ();
|
||||
|
||||
double bx = 0.0, by = 0.0;
|
||||
double ax = 0.0, ay = 0.0;
|
||||
double sx = 0.0, sy = 0.0;
|
||||
|
||||
tl::from_string_ext (tl::to_string (column_x_le->text ()), bx);
|
||||
tl::from_string_ext (tl::to_string (column_y_le->text ()), by);
|
||||
tl::from_string_ext (tl::to_string (columns_le->text ()), nb);
|
||||
tl::from_string_ext (tl::to_string (columns_le->text ()), options.nb);
|
||||
tl::from_string_ext (tl::to_string (row_x_le->text ()), ax);
|
||||
tl::from_string_ext (tl::to_string (row_y_le->text ()), ay);
|
||||
tl::from_string_ext (tl::to_string (rows_le->text ()), na);
|
||||
tl::from_string_ext (tl::to_string (rows_le->text ()), options.na);
|
||||
tl::from_string_ext (tl::to_string (space_x_le->text ()), sx);
|
||||
tl::from_string_ext (tl::to_string (space_y_le->text ()), sy);
|
||||
|
||||
a = db::DVector (ax, ay);
|
||||
b = db::DVector (bx, by);
|
||||
options.a = db::DVector (ax, ay);
|
||||
options.b = db::DVector (bx, by);
|
||||
options.space = db::DVector (sx, sy);
|
||||
|
||||
return true;
|
||||
|
||||
|
|
@ -758,7 +771,7 @@ popup_tap_layer_menu (lay::LayoutViewBase *view, const std::set<db::LayerPropert
|
|||
std::set<std::pair<unsigned int, unsigned int> > layers_in_selection;
|
||||
|
||||
for (lay::ShapeFinder::iterator f = finder.begin (); f != finder.end (); ++f) {
|
||||
if (cv_index < 0 || f->cv_index () == cv_index) {
|
||||
if (cv_index < 0 || int (f->cv_index ()) == cv_index) {
|
||||
const db::Layout &ly = view->cellview (f->cv_index ())->layout ();
|
||||
// ignore guiding shapes and only provide layers from the filter
|
||||
if (f->layer () != ly.guiding_shape_layer ()
|
||||
|
|
|
|||
|
|
@ -56,6 +56,8 @@ namespace lay
|
|||
|
||||
namespace edt {
|
||||
|
||||
class ArrayOptions;
|
||||
|
||||
/**
|
||||
* @brief The copy mode dialog
|
||||
*/
|
||||
|
|
@ -173,10 +175,10 @@ class MakeArrayOptionsDialog
|
|||
private Ui::MakeArrayOptionsDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
MakeArrayOptionsDialog (QWidget *parent);
|
||||
bool exec_dialog (db::DVector &a, unsigned int &na, db::DVector &b, unsigned int &nb);
|
||||
bool exec_dialog (ArrayOptions &options);
|
||||
|
||||
virtual void accept ();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -81,8 +81,6 @@ MainService::MainService (db::Manager *manager, lay::LayoutViewBase *view, lay::
|
|||
m_distribute_vmode (1), m_distribute_vpitch (0.0), m_distribute_vspace (0.0),
|
||||
m_distribute_visible_layers (false),
|
||||
m_origin_mode_x (-1), m_origin_mode_y (-1), m_origin_visible_layers_for_bbox (false),
|
||||
m_array_a (0.0, 1.0), m_array_b (1.0, 0.0),
|
||||
m_array_na (1), m_array_nb (1),
|
||||
m_router (0.0), m_rinner (0.0), m_npoints (64), m_undo_before_apply (true)
|
||||
{
|
||||
#if defined(HAVE_QT)
|
||||
|
|
@ -2251,32 +2249,66 @@ MainService::cm_make_array ()
|
|||
tl_assert (false); // see TODO
|
||||
#endif
|
||||
|
||||
size_t n = 0;
|
||||
check_no_guiding_shapes ();
|
||||
|
||||
std::vector<edt::Service *> edt_services = view ()->get_plugins <edt::Service> ();
|
||||
|
||||
for (std::vector<edt::Service *>::const_iterator es = edt_services.begin (); es != edt_services.end (); ++es) {
|
||||
for (EditableSelectionIterator s = (*es)->begin_selection (); ! s.at_end (); ++s) {
|
||||
++n;
|
||||
}
|
||||
bool any = false;
|
||||
for (std::vector<edt::Service *>::const_iterator es = edt_services.begin (); es != edt_services.end () && ! any; ++es) {
|
||||
any = ! (*es)->begin_selection ().at_end ();
|
||||
}
|
||||
|
||||
if (n == 0) {
|
||||
if (! any) {
|
||||
throw tl::Exception (tl::to_string (tr ("Nothing selected to make arrays of")));
|
||||
}
|
||||
|
||||
#if defined(HAVE_QT)
|
||||
// TODO: make parameters persistent so we can set them externally
|
||||
if (! make_array_options_dialog ()->exec_dialog (m_array_a, m_array_na, m_array_b, m_array_nb)) {
|
||||
if (! make_array_options_dialog ()->exec_dialog (m_array_options)) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
unsigned int na = m_array_options.na;
|
||||
unsigned int nb = m_array_options.nb;
|
||||
db::DVector a = m_array_options.a;
|
||||
db::DVector b = m_array_options.b;
|
||||
|
||||
if (m_array_options.mode == ArrayOptions::Spaced) {
|
||||
|
||||
db::DBox bbox;
|
||||
|
||||
// get the selection bbox
|
||||
for (std::vector<edt::Service *>::const_iterator es = edt_services.begin (); es != edt_services.end (); ++es) {
|
||||
for (EditableSelectionIterator s = (*es)->begin_selection (); ! s.at_end (); ++s) {
|
||||
|
||||
const db::Layout &layout = view ()->cellview (s->cv_index ())->layout ();
|
||||
db::CplxTrans tr = db::CplxTrans (layout.dbu ()) * s->trans ();
|
||||
|
||||
if (! s->is_cell_inst ()) {
|
||||
bbox += tr * s->shape ().bbox ();
|
||||
} else {
|
||||
bbox += inst_bbox (tr, view (), s->cv_index (), s->back (), m_array_options.use_visible_layers);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// compute pitch vectors
|
||||
a = db::DVector (0.0, m_array_options.space.y () + bbox.height ()); // row-pitch
|
||||
b = db::DVector (m_array_options.space.x () + bbox.width (), 0.0); // column-pitch
|
||||
|
||||
}
|
||||
|
||||
make_array (na, nb, a, b);
|
||||
}
|
||||
|
||||
void
|
||||
MainService::make_array (unsigned int na, unsigned int nb, const db::DVector &a, const db::DVector &b)
|
||||
{
|
||||
view ()->cancel_edits ();
|
||||
|
||||
// undo support for small arrays only
|
||||
bool has_undo = (m_array_na * m_array_nb < 1000);
|
||||
bool has_undo = (na * nb < 1000);
|
||||
|
||||
// No undo support currently - the undo buffering is pretty inefficient right now.
|
||||
if (manager ()) {
|
||||
|
|
@ -2287,7 +2319,17 @@ MainService::cm_make_array ()
|
|||
}
|
||||
}
|
||||
|
||||
tl::RelativeProgress progress (tl::to_string (tr ("Make array")), (size_t (m_array_na) * size_t (m_array_nb) - 1) * n, 1000);
|
||||
std::vector<edt::Service *> edt_services = view ()->get_plugins <edt::Service> ();
|
||||
|
||||
// count selected items for progress
|
||||
size_t n = 0;
|
||||
for (std::vector<edt::Service *>::const_iterator es = edt_services.begin (); es != edt_services.end (); ++es) {
|
||||
for (EditableSelectionIterator s = (*es)->begin_selection (); ! s.at_end (); ++s) {
|
||||
++n;
|
||||
}
|
||||
}
|
||||
|
||||
tl::RelativeProgress progress (tl::to_string (tr ("Make array")), (size_t (na) * size_t (nb) - 1) * n, 1000);
|
||||
|
||||
for (std::vector<edt::Service *>::const_iterator es = edt_services.begin (); es != edt_services.end (); ++es) {
|
||||
|
||||
|
|
@ -2302,15 +2344,15 @@ MainService::cm_make_array ()
|
|||
|
||||
if (s->is_cell_inst ()) {
|
||||
|
||||
for (unsigned int ia = 0; ia < m_array_na; ++ia) {
|
||||
for (unsigned int ib = 0; ib < m_array_nb; ++ib) {
|
||||
for (unsigned int ia = 0; ia < na; ++ia) {
|
||||
for (unsigned int ib = 0; ib < nb; ++ib) {
|
||||
|
||||
// don't create a copy
|
||||
if (ia == 0 && ib == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
db::DCplxTrans dtrans (m_array_a * double (ia) + m_array_b * double (ib));
|
||||
db::DCplxTrans dtrans (a * double (ia) + b * double (ib));
|
||||
db::ICplxTrans itrans (db::DCplxTrans (s->trans ()).inverted () * db::DCplxTrans (1.0 / cv->layout ().dbu ()) * dtrans * db::DCplxTrans (cv->layout ().dbu ()) * db::DCplxTrans (s->trans ()));
|
||||
|
||||
db::Instance new_inst = target_cell.insert (s->back ().inst_ptr);
|
||||
|
|
@ -2326,15 +2368,15 @@ MainService::cm_make_array ()
|
|||
|
||||
db::Shapes &target_shapes = target_cell.shapes (s->layer ());
|
||||
|
||||
for (unsigned int ia = 0; ia < m_array_na; ++ia) {
|
||||
for (unsigned int ib = 0; ib < m_array_nb; ++ib) {
|
||||
for (unsigned int ia = 0; ia < na; ++ia) {
|
||||
for (unsigned int ib = 0; ib < nb; ++ib) {
|
||||
|
||||
// don't create a copy
|
||||
if (ia == 0 && ib == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
db::DCplxTrans dtrans (m_array_a * double (ia) + m_array_b * double (ib));
|
||||
db::DCplxTrans dtrans (a * double (ia) + b * double (ib));
|
||||
db::ICplxTrans itrans (db::DCplxTrans (s->trans ()).inverted () * db::DCplxTrans (1.0 / cv->layout ().dbu ()) * dtrans * db::DCplxTrans (cv->layout ().dbu ()) * db::DCplxTrans (s->trans ()));
|
||||
|
||||
db::Shape new_shape = target_shapes.insert (s->shape ());
|
||||
|
|
|
|||
|
|
@ -56,6 +56,21 @@ class DistributeOptionsDialog;
|
|||
|
||||
// -------------------------------------------------------------
|
||||
|
||||
struct ArrayOptions
|
||||
{
|
||||
enum mode_type { PitchVectors, Spaced };
|
||||
|
||||
ArrayOptions () : mode (PitchVectors), a (0.0, 1.0), b (1.0, 0.0), na (1), nb (1) { }
|
||||
|
||||
mode_type mode;
|
||||
db::DVector a, b;
|
||||
unsigned int na, nb;
|
||||
db::DVector space;
|
||||
bool use_visible_layers;
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------
|
||||
|
||||
class MainService
|
||||
: public lay::Plugin,
|
||||
public lay::Editable,
|
||||
|
|
@ -155,6 +170,11 @@ public:
|
|||
*/
|
||||
void cm_make_array ();
|
||||
|
||||
/**
|
||||
* @brief The parameterized function for making arrays
|
||||
*/
|
||||
void make_array (unsigned na, unsigned nb, const db::DVector &a, const db::DVector &b);
|
||||
|
||||
/**
|
||||
* @brief Align the selected shapes and instances
|
||||
*/
|
||||
|
|
@ -242,11 +262,11 @@ private:
|
|||
std::string m_make_cell_name;
|
||||
int m_origin_mode_x, m_origin_mode_y;
|
||||
bool m_origin_visible_layers_for_bbox;
|
||||
db::DVector m_array_a, m_array_b;
|
||||
unsigned int m_array_na, m_array_nb;
|
||||
double m_router, m_rinner;
|
||||
unsigned int m_npoints;
|
||||
bool m_undo_before_apply;
|
||||
ArrayOptions m_array_options;
|
||||
|
||||
#if defined(HAVE_QT)
|
||||
edt::RoundCornerOptionsDialog *mp_round_corners_dialog;
|
||||
edt::AreaAndPerimeterDialog *mp_area_and_perimeter_dialog;
|
||||
|
|
|
|||
|
|
@ -1060,47 +1060,72 @@ ApplicationBase::usage ()
|
|||
{
|
||||
std::string r;
|
||||
r = std::string (lay::Version::exe_name ()) + " [<options>] [<file>] ..\n";
|
||||
r += tl::to_string (QObject::tr ("options")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -b Batch mode (same as -zz -nc -rx)")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -c <config file> Use this configuration file")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -nc Don't use a configuration file (implies -t)")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -d <log level> Set log level")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -e Editable mode (allow editing of files)")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -ne Readonly mode (editing of files is disabled)")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -gr <file name> Record GUI test file")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -gp <file name> Replay GUI test file")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -gb <line number> Replay GUI test file up to (including) line")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -gx <millisec> Replay rate for GUI test file")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -gi Incremental logs for GUI test file")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -i Disable undo buffering (less memory requirements)")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -ni Enable undo buffering (default, overrides previous -i option)")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -j <path> Add the given path to the macro project paths")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -k <log file> Write log to the given file plus stdout/stderr")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -l <lyp file> Use layer properties file")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -lx With -l: add other layers as well")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -lf With -l: use the lyp file as it is (no expansion to multiple layouts)")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -m <database file> Load RDB (report database) file (into previous layout view)")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -mn <database file> Load L2NDB (layout to netlist database) file (into previous layout view)")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -n <technology> Technology to use for next layout(s) on command line")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -nn <tech file> Technology file (.lyt) to use for next layout(s) on command line")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -p <plugin> Load the plugin (can be used multiple times)")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -r <script> Execute main script on startup (after having loaded files etc.)")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -rr <script> Like -r, but does not exit after executing the script")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -rm <script> Execute script on startup before loading files (can be used multiple times)")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -rd <name>=<value> Specify script variable")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -rx Ignore all implicit macros (*.rbm, rbainit, *.lym)")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -s Load files into same view")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -t Don't update the configuration file on exit")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -nt Update the configuration file on exit (default, overrides previous -t option)")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -u <file name> Restore session from given file")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -v Print program version and exit (also available as --version)")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -wd <name>=<value> Define a variable within expressions")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -x Synchronous drawing mode")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -y <package> Package installation: install package(s) and exit - can be used more than once")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" ('package' is a name, an URL and optionally a version in round brackets)")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -yd With -y: include dependencies")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -z Non-GUI mode (hidden views)")) + "\n";
|
||||
r += tl::to_string (QObject::tr (" -zz Non-GUI mode (database only, implies -nc)")) + "\n";
|
||||
r += tl::to_string (tr (
|
||||
"\n"
|
||||
"The format of the input files is usually detected automatically. In some cases, the format is derived from\n"
|
||||
"the file's suffix. If your file does not have the neccessary suffix, you can explicitly specify the format\n"
|
||||
"by adding the respective suffix to the file name in square brackets - e.g. 'file.data[def]' will read\n"
|
||||
"the file 'file.data' as a DEF file.\n"
|
||||
"\n"
|
||||
"Options:\n"
|
||||
" -b Batch mode (same as -zz -nc -rx)\n"
|
||||
" -c <config file> Use this configuration file\n"
|
||||
" -nc Don't use a configuration file (implies -t)\n"
|
||||
" -d <log level> Set log level\n"
|
||||
" -e Editable mode (allow editing of files)\n"
|
||||
" -ne Readonly mode (editing of files is disabled)\n"
|
||||
" -gr <file name> Record GUI test file\n"
|
||||
" -gp <file name> Replay GUI test file\n"
|
||||
" -gb <line number> Replay GUI test file up to (including) line\n"
|
||||
" -gx <millisec> Replay rate for GUI test file\n"
|
||||
" -gi Incremental logs for GUI test file\n"
|
||||
" -i Disable undo buffering (less memory requirements)\n"
|
||||
" -ni Enable undo buffering (default, overrides previous -i option)\n"
|
||||
" -j <path> Add the given path to the macro project paths\n"
|
||||
" -k <log file> Write log to the given file plus stdout/stderr\n"
|
||||
" -l <lyp file> Use layer properties file\n"
|
||||
" -lx With -l: add other layers as well\n"
|
||||
" -lf With -l: use the lyp file as it is (no expansion to multiple layouts)\n"
|
||||
" -m <database file> Load RDB (report database) file (into previous layout view)\n"
|
||||
" -mn <database file> Load L2NDB (layout to netlist database) file (into previous layout view)\n"
|
||||
" -n <technology> Technology to use for next layout(s) on command line\n"
|
||||
" -nn <tech file> Technology file (.lyt) to use for next layout(s) on command line\n"
|
||||
" -p <plugin> Load the plugin (can be used multiple times)\n"
|
||||
" -r <script> Execute main script on startup (after having loaded files etc.)\n"
|
||||
" -rr <script> Like -r, but does not exit after executing the script\n"
|
||||
" -rm <script> Execute script on startup before loading files (can be used multiple times)\n"
|
||||
" -rd <name>=<value> Specify script variable\n"
|
||||
" -rx Ignore all implicit macros (*.rbm, rbainit, *.lym)\n"
|
||||
" -s Load files into same view\n"
|
||||
" -t Don't update the configuration file on exit\n"
|
||||
" -nt Update the configuration file on exit (default, overrides previous -t option)\n"
|
||||
" -u <file name> Restore session from given file\n"
|
||||
" -v Print program version and exit (also available as --version)\n"
|
||||
" -wd <name>=<value> Define a variable within expressions\n"
|
||||
" -x Synchronous drawing mode\n"
|
||||
" -y <package> Package installation: install package(s) and exit - can be used more than once\n"
|
||||
" ('package' is a name, an URL and optionally a version in round brackets)\n"
|
||||
" -yd With -y: include dependencies\n"
|
||||
" -z Non-GUI mode (hidden views)\n"
|
||||
" -zz Non-GUI mode (database only, implies -nc)\n"
|
||||
"\n"
|
||||
"Environment variables:\n"
|
||||
" KLAYOUT_HOME The path to KLayout's data (configuration, macros, libraries etc.).\n"
|
||||
" Default path is '~/.klayout' on Linux and '%USERPROFILE%\\KLayout' on Windows.\n"
|
||||
" KLAYOUT_PATH A list of locations to look into additionally to KLAYOUT_HOME for macros, libraries etc.\n"
|
||||
" Separator for the locations is ':' on Linux and ';' on Windows.\n"
|
||||
" KLAYOUT_SALT_MINE The package manager repository URL. Default is 'http://sami.klayout.org/repository.xml'.\n"
|
||||
" KLAYOUT_IGNORE_MACRO_DIRS A colon-separated list of folder names to ignore in the macro editor tree.\n"
|
||||
" By default, only '__pycache__' is ignored.\n"
|
||||
" KLAYOUT_LEF_FORMAT A space-separated list of formats to be recognized as LEF files.\n"
|
||||
" By default this format list is '*.lef *.LEF *.lef.gz *.LEF.gz'.\n"
|
||||
" KLAYOUT_DEF_FORMAT A space-separated list of formats to be recognized as DEF files.\n"
|
||||
" By default this format list is '*.def *.DEF *.def.gz *.DEF.gz'.\n"
|
||||
" KLAYOUT_PYTHONPATH The equivalent of PYTHONPATH for KLayout.\n"
|
||||
" KLAYOUT_PYTHONHOME The equivalent of PYTHONHOME for KLayout.\n"
|
||||
" KLAYOUT_HTTP_TIMEOUT The timeout for HTTP(S) requests in seconds. The default value is 10.\n"
|
||||
" KLAYOUT_VERBOSITY The default verbosity (see -d option).\n"
|
||||
));
|
||||
return r;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -124,10 +124,14 @@ MacroEditorNotificationWidget::MacroEditorNotificationWidget (MacroEditorPage *p
|
|||
void
|
||||
MacroEditorNotificationWidget::action_triggered ()
|
||||
{
|
||||
BEGIN_PROTECTED
|
||||
|
||||
auto a = m_action_buttons.find (sender ());
|
||||
if (a != m_action_buttons.end ()) {
|
||||
mp_parent->notification_action (*mp_notification, a->second);
|
||||
}
|
||||
|
||||
END_PROTECTED_W (this)
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -544,7 +548,9 @@ void MacroEditorSidePanel::paintEvent (QPaintEvent *)
|
|||
// MacroEditorPage implementation
|
||||
|
||||
MacroEditorPage::MacroEditorPage (QWidget * /*parent*/, MacroEditorHighlighters *highlighters)
|
||||
: mp_macro (0), mp_highlighters (highlighters), mp_highlighter (0), m_error_line (-1), m_ntab (8), m_nindent (2), m_ignore_cursor_changed_event (false)
|
||||
: mp_macro (0), mp_highlighters (highlighters), mp_highlighter (0),
|
||||
m_error_line (-1), m_ntab (8), m_nindent (2), m_ignore_cursor_changed_event (false),
|
||||
dm_run_mode_changed (this, &MacroEditorPage::do_run_mode_changed)
|
||||
{
|
||||
mp_layout = new QVBoxLayout (this);
|
||||
mp_layout->setContentsMargins (0, 0, 0, 0);
|
||||
|
|
@ -658,6 +664,11 @@ void MacroEditorPage::current_line_changed ()
|
|||
}
|
||||
|
||||
void MacroEditorPage::run_mode_changed ()
|
||||
{
|
||||
dm_run_mode_changed ();
|
||||
}
|
||||
|
||||
void MacroEditorPage::do_run_mode_changed ()
|
||||
{
|
||||
// this prevents recursion when the following lines trigger anything that routes through the interpreter
|
||||
bool bl = mp_exec_model->blockSignals (true);
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
#include "lymMacro.h"
|
||||
#include "layGenericSyntaxHighlighter.h"
|
||||
#include "tlVariant.h"
|
||||
#include "tlDeferredExecution.h"
|
||||
|
||||
#include <QDialog>
|
||||
#include <QPixmap>
|
||||
|
|
@ -417,12 +418,14 @@ private:
|
|||
QListWidget *mp_completer_list;
|
||||
std::list<MacroEditorNotification> m_notifications;
|
||||
std::map<const MacroEditorNotification *, QWidget *, CompareNotificationPointers> m_notification_widgets;
|
||||
tl::DeferredMethod<lay::MacroEditorPage> dm_run_mode_changed;
|
||||
|
||||
void update_extra_selections ();
|
||||
bool return_pressed ();
|
||||
bool backspace_pressed ();
|
||||
bool back_tab_key_pressed ();
|
||||
bool tab_key_pressed ();
|
||||
void do_run_mode_changed ();
|
||||
void fill_completer_list ();
|
||||
void complete ();
|
||||
QTextCursor get_completer_cursor (int &pos0, int &pos);
|
||||
|
|
|
|||
|
|
@ -2270,7 +2270,7 @@ MainWindow::cm_save_current_cell_as ()
|
|||
|
||||
db::SaveLayoutOptions options (cv->save_options ());
|
||||
options.set_dbu (cv->layout ().dbu ());
|
||||
options.set_format_from_filename (fn);
|
||||
fn = options.set_format_from_filename (fn).second;
|
||||
|
||||
tl::OutputStream::OutputStreamMode om = tl::OutputStream::OM_Auto;
|
||||
if (mp_layout_save_as_options->get_options (current_view (), cv_index, fn, om, options)) {
|
||||
|
|
@ -2370,7 +2370,7 @@ MainWindow::do_save (bool as)
|
|||
db::SaveLayoutOptions options = get_save_options_from_cv (cv);
|
||||
|
||||
if (as || options.format ().empty ()) {
|
||||
options.set_format_from_filename (fn);
|
||||
fn = options.set_format_from_filename (fn).second;
|
||||
}
|
||||
|
||||
tl::OutputStream::OutputStreamMode om = tl::OutputStream::OM_Auto;
|
||||
|
|
@ -2419,7 +2419,7 @@ MainWindow::cm_save_all ()
|
|||
db::SaveLayoutOptions options = get_save_options_from_cv (cv);
|
||||
|
||||
if (options.format ().empty ()) {
|
||||
options.set_format_from_filename (fn);
|
||||
fn = options.set_format_from_filename (fn).second;
|
||||
}
|
||||
|
||||
tl::OutputStream::OutputStreamMode om = tl::OutputStream::OM_Auto;
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>432</width>
|
||||
<height>349</height>
|
||||
<width>449</width>
|
||||
<height>370</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
|
|
@ -405,6 +405,13 @@
|
|||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QFrame" name="frame">
|
||||
<property name="frameShape">
|
||||
|
|
@ -429,44 +436,12 @@
|
|||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>209</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton">
|
||||
<property name="text">
|
||||
<string>Ok</string>
|
||||
</property>
|
||||
<property name="default">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton_2">
|
||||
<property name="text">
|
||||
<string>Cancel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<tabstops>
|
||||
<tabstop>pushButton</tabstop>
|
||||
<tabstop>pushButton_2</tabstop>
|
||||
<tabstop>lt</tabstop>
|
||||
<tabstop>ct</tabstop>
|
||||
<tabstop>rt</tabstop>
|
||||
|
|
@ -486,34 +461,34 @@
|
|||
</resources>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>pushButton</sender>
|
||||
<signal>clicked()</signal>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>AlignCellOptionsDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>237</x>
|
||||
<y>203</y>
|
||||
<x>224</x>
|
||||
<y>295</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>147</x>
|
||||
<y>81</y>
|
||||
<x>224</x>
|
||||
<y>176</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>pushButton_2</sender>
|
||||
<signal>clicked()</signal>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>AlignCellOptionsDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>325</x>
|
||||
<y>202</y>
|
||||
<x>224</x>
|
||||
<y>295</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>325</x>
|
||||
<y>57</y>
|
||||
<x>224</x>
|
||||
<y>176</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
|
|
|
|||
|
|
@ -136,6 +136,83 @@ static lay::NetlistObjectPath second (const lay::NetlistObjectsPath *pp)
|
|||
return pp->second ();
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
struct First
|
||||
{
|
||||
lay::NetlistObjectsPath operator() (const lay::NetlistObjectPath &p)
|
||||
{
|
||||
return lay::NetlistObjectsPath::from_first (p);
|
||||
}
|
||||
};
|
||||
|
||||
struct Second
|
||||
{
|
||||
lay::NetlistObjectsPath operator() (const lay::NetlistObjectPath &p)
|
||||
{
|
||||
return lay::NetlistObjectsPath::from_second (p);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template <class Which>
|
||||
static lay::NetlistObjectsPath from (const lay::NetlistObjectPath &p)
|
||||
{
|
||||
return Which () (p);
|
||||
}
|
||||
|
||||
template <class Which>
|
||||
static lay::NetlistObjectsPath from_net (const db::Net *net)
|
||||
{
|
||||
if (! net) {
|
||||
return lay::NetlistObjectsPath ();
|
||||
}
|
||||
|
||||
lay::NetlistObjectPath p;
|
||||
p.root = net->circuit ();
|
||||
p.net = net;
|
||||
return Which () (p);
|
||||
}
|
||||
|
||||
template <class Which>
|
||||
static lay::NetlistObjectsPath from_device (const db::Device *device)
|
||||
{
|
||||
if (! device) {
|
||||
return lay::NetlistObjectsPath ();
|
||||
}
|
||||
|
||||
lay::NetlistObjectPath p;
|
||||
p.root = device->circuit ();
|
||||
p.device = device;
|
||||
return Which () (p);
|
||||
}
|
||||
|
||||
template <class Which>
|
||||
static lay::NetlistObjectsPath from_circuit (const db::Circuit *circuit)
|
||||
{
|
||||
if (! circuit) {
|
||||
return lay::NetlistObjectsPath ();
|
||||
}
|
||||
|
||||
lay::NetlistObjectPath p;
|
||||
p.root = circuit;
|
||||
return Which () (p);
|
||||
}
|
||||
|
||||
template <class Which>
|
||||
static lay::NetlistObjectsPath from_subcircuit (const db::SubCircuit *subcircuit)
|
||||
{
|
||||
if (! subcircuit) {
|
||||
return lay::NetlistObjectsPath ();
|
||||
}
|
||||
|
||||
lay::NetlistObjectPath p;
|
||||
p.root = subcircuit->circuit ();
|
||||
p.path.push_back (subcircuit);
|
||||
return Which () (p);
|
||||
}
|
||||
|
||||
Class<lay::NetlistObjectsPath> decl_NetlistObjectsPath ("lay", "NetlistObjectsPath",
|
||||
gsi::method_ext ("first", &first,
|
||||
"@brief Gets the first object's path.\n"
|
||||
|
|
@ -146,6 +223,67 @@ Class<lay::NetlistObjectsPath> decl_NetlistObjectsPath ("lay", "NetlistObjectsPa
|
|||
"@brief Gets the second object's path.\n"
|
||||
"In cases of paired netlists (LVS database), the first path points to the schematic netlist object.\n"
|
||||
"For the single netlist, the second path is always a null path."
|
||||
) +
|
||||
gsi::method ("from_first", &from<First>, gsi::arg ("p"),
|
||||
"@brief Creates a path from given first coordinates.\n"
|
||||
"Use this constructor to create a paired path from a first set of coordinates (net, circuit, device).\n"
|
||||
"For single-sided databases (i.e. extracted netlist or schematic only), use the first coordinates. "
|
||||
"For two-sided database (i.e. LVS cross references), use the first coordinates when you refer to "
|
||||
"layout netlist objects.\n"
|
||||
"\n"
|
||||
"In this version, the minimum requirement for the path is to have a root.\n"
|
||||
"\n"
|
||||
"This constructor has been added in version 0.30.8."
|
||||
) +
|
||||
gsi::method ("from_first", &from_net<First>, gsi::arg ("net"),
|
||||
"@brief Creates a path from a given net in the first netlist space.\n"
|
||||
"\n"
|
||||
"This constructor has been added in version 0.30.8."
|
||||
) +
|
||||
gsi::method ("from_first", &from_device<First>, gsi::arg ("device"),
|
||||
"@brief Creates a path from a given device in the first netlist space.\n"
|
||||
"\n"
|
||||
"This constructor has been added in version 0.30.8."
|
||||
) +
|
||||
gsi::method ("from_first", &from_circuit<First>, gsi::arg ("circuit"),
|
||||
"@brief Creates a path from a given circuit in the first netlist space.\n"
|
||||
"\n"
|
||||
"This constructor has been added in version 0.30.8."
|
||||
) +
|
||||
gsi::method ("from_first", &from_subcircuit<First>, gsi::arg ("subcircuit"),
|
||||
"@brief Creates a path from a given subcircuit in the first netlist space.\n"
|
||||
"\n"
|
||||
"This constructor has been added in version 0.30.8."
|
||||
) +
|
||||
gsi::method ("from_second", &from<Second>, gsi::arg ("p"),
|
||||
"@brief Creates a path from given second coordinates.\n"
|
||||
"Use this constructor to create a paired path from a second set of coordinates (net, circuit, device).\n"
|
||||
"For two-sided database (i.e. LVS cross references), use the second coordinates when you refer to "
|
||||
"schematic netlist objects.\n"
|
||||
"\n"
|
||||
"In this version, the minimum requirement for the path is to have a root.\n"
|
||||
"\n"
|
||||
"This constructor has been added in version 0.30.8."
|
||||
) +
|
||||
gsi::method ("from_second", &from_net<Second>, gsi::arg ("net"),
|
||||
"@brief Creates a path from a given net in the second netlist space.\n"
|
||||
"\n"
|
||||
"This constructor has been added in version 0.30.8."
|
||||
) +
|
||||
gsi::method ("from_second", &from_device<Second>, gsi::arg ("device"),
|
||||
"@brief Creates a path from a given device in the second netlist space.\n"
|
||||
"\n"
|
||||
"This constructor has been added in version 0.30.8."
|
||||
) +
|
||||
gsi::method ("from_second", &from_circuit<Second>, gsi::arg ("circuit"),
|
||||
"@brief Creates a path from a given circuit in the second netlist space.\n"
|
||||
"\n"
|
||||
"This constructor has been added in version 0.30.8."
|
||||
) +
|
||||
gsi::method ("from_second", &from_subcircuit<Second>, gsi::arg ("subcircuit"),
|
||||
"@brief Creates a path from a given subcircuit in the second netlist space.\n"
|
||||
"\n"
|
||||
"This constructor has been added in version 0.30.8."
|
||||
),
|
||||
"@brief An object describing the instantiation of a single netlist object or a pair of those.\n"
|
||||
"This class is basically a pair of netlist object paths (see \\NetlistObjectPath). When derived from a single netlist view, "
|
||||
|
|
@ -156,7 +294,16 @@ Class<lay::NetlistObjectsPath> decl_NetlistObjectsPath ("lay", "NetlistObjectsPa
|
|||
"If the selected object isn't a matched one, either the first or second path may be a null or a partial path without a final net or device object "
|
||||
"or a partial path.\n"
|
||||
"\n"
|
||||
"This class has been introduced in version 0.27.\n"
|
||||
"To create a paired path from an existing object (net, device, circuit, subcircuit), use \\from_first and \\from_second.\n"
|
||||
"Use \\from_first, if the object belongs to the first netlist of the database ('netlist', layout netlist in the LVS context).\n"
|
||||
"Use \\from_second, if the object belongs to the second netlist of the database ('reference', schematic netlist in the LVS context).\n"
|
||||
"\n"
|
||||
"It is also possible to create a paired path from a full path object (including root, a subcircuit path and a target object), either "
|
||||
"for the first or second side. Use \\from_first and \\from_second with a \\NetlistObjectPath argument in that case.\n"
|
||||
"A minimum requirement in that case is to set the root (the origin of the path). If no subcircuit path is "
|
||||
"given (see \\NetlistObjectPath#path), a suitable path leading from the target object (net or device) to the root will be constructed.\n"
|
||||
"\n"
|
||||
"This class has been introduced in version 0.27 and has been extended in version 0.30.8.\n"
|
||||
);
|
||||
|
||||
static lay::NetlistObjectPath current_path_first (lay::NetlistBrowserDialog *dialog)
|
||||
|
|
@ -169,6 +316,20 @@ static lay::NetlistObjectPath current_path_second (lay::NetlistBrowserDialog *di
|
|||
return dialog->current_path ().second ();
|
||||
}
|
||||
|
||||
static void set_current_path (lay::NetlistBrowserDialog *dialog, const lay::NetlistObjectsPath *path)
|
||||
{
|
||||
if (! path) {
|
||||
dialog->set_current_path (lay::NetlistObjectsPath ());
|
||||
} else {
|
||||
dialog->set_current_path (*path);
|
||||
}
|
||||
}
|
||||
|
||||
static lay::LayoutViewBase *get_view (lay::NetlistBrowserDialog *dialog)
|
||||
{
|
||||
return dialog->view ();
|
||||
}
|
||||
|
||||
Class<lay::NetlistBrowserDialog> decl_NetlistBrowserDialog ("lay", "NetlistBrowserDialog",
|
||||
gsi::event ("on_current_db_changed", &lay::NetlistBrowserDialog::current_db_changed_event,
|
||||
"@brief This event is triggered when the current database is changed.\n"
|
||||
|
|
@ -187,6 +348,16 @@ Class<lay::NetlistBrowserDialog> decl_NetlistBrowserDialog ("lay", "NetlistBrows
|
|||
gsi::method ("db", &lay::NetlistBrowserDialog::db,
|
||||
"@brief Gets the database the browser is connected to.\n"
|
||||
) +
|
||||
gsi::method ("db_index", &lay::NetlistBrowserDialog::l2n_index,
|
||||
"@brief Gets the database index inside the view the browser is connected to.\n"
|
||||
"\n"
|
||||
"This attribute has been introduced in version 0.30.8.\n"
|
||||
) +
|
||||
gsi::method_ext ("view", &get_view,
|
||||
"@brief Gets the view the browser is connected to.\n"
|
||||
"\n"
|
||||
"This attribute has been introduced in version 0.30.8.\n"
|
||||
) +
|
||||
gsi::method_ext ("current_path_first", ¤t_path_first,
|
||||
"@brief Gets the path of the current object on the first (layout in case of LVS database) side.\n"
|
||||
) +
|
||||
|
|
@ -196,6 +367,16 @@ Class<lay::NetlistBrowserDialog> decl_NetlistBrowserDialog ("lay", "NetlistBrows
|
|||
gsi::method ("current_path", &lay::NetlistBrowserDialog::current_path,
|
||||
"@brief Gets the path of the current object as a path pair (combines layout and schematic object paths in case of a LVS database view).\n"
|
||||
) +
|
||||
gsi::method_ext ("current_path=", &set_current_path,
|
||||
"@brief Sets the current path.\n"
|
||||
"This is the setter corresponding to the 'current_path' getter. Passing nil clears the selection.\n"
|
||||
"Changing the selection will update the highlights and navigate to the location depending on the "
|
||||
"settings. An \\on_selection_changed signal is not emitted.\n"
|
||||
"\n"
|
||||
"To get a suitable path, see the \\NetlistObjectsPath#from_first and \\NetlistObjectsPath#from_second generators.\n"
|
||||
"\n"
|
||||
"This setter has been introduced in version 0.30.8.\n"
|
||||
) +
|
||||
gsi::method ("selected_paths", &lay::NetlistBrowserDialog::selected_paths,
|
||||
"@brief Gets the nets currently selected objects (paths) in the netlist database browser.\n"
|
||||
"The result is an array of path pairs. See \\NetlistObjectsPath for details about these pairs."
|
||||
|
|
|
|||
|
|
@ -306,28 +306,28 @@ SingleIndexedNetlistModel::parent_of (const subcircuit_pair &subcircuits) const
|
|||
return std::make_pair (subcircuits.first ? subcircuits.first->circuit () : 0, (const db::Circuit *) 0);
|
||||
}
|
||||
|
||||
std::pair<IndexedNetlistModel::circuit_pair, std::pair<IndexedNetlistModel::Status, std::string> > SingleIndexedNetlistModel::top_circuit_from_index(size_t index) const
|
||||
std::pair<IndexedNetlistModel::circuit_pair, std::pair<IndexedNetlistModel::Status, std::string> > SingleIndexedNetlistModel::top_circuit_from_index (size_t index) const
|
||||
{
|
||||
db::Netlist::const_top_down_circuit_iterator none;
|
||||
return std::make_pair (attr_by_object_and_index (std::make_pair ((const db::Circuit *) 0, (const db::Circuit *) 0), index, mp_netlist->begin_top_down (), mp_netlist->begin_top_down () + mp_netlist->top_circuit_count (), none, none, m_child_circuit_by_circuit_and_index, sort_by_name<db::Circuit> ()), std::make_pair (db::NetlistCrossReference::None, std::string ()));
|
||||
}
|
||||
|
||||
std::pair<IndexedNetlistModel::circuit_pair, std::pair<IndexedNetlistModel::Status, std::string> > SingleIndexedNetlistModel::child_circuit_from_index(const circuit_pair &circuits, size_t index) const
|
||||
std::pair<IndexedNetlistModel::circuit_pair, std::pair<IndexedNetlistModel::Status, std::string> > SingleIndexedNetlistModel::child_circuit_from_index (const circuit_pair &circuits, size_t index) const
|
||||
{
|
||||
db::Circuit::const_child_circuit_iterator none;
|
||||
return std::make_pair (attr_by_object_and_index (circuits, index, circuits.first->begin_children (), circuits.first->end_children (), none, none, m_child_circuit_by_circuit_and_index, sort_by_name<db::Circuit> ()), std::make_pair (db::NetlistCrossReference::None, std::string ()));
|
||||
}
|
||||
|
||||
std::pair<IndexedNetlistModel::circuit_pair, std::pair<IndexedNetlistModel::Status, std::string> > SingleIndexedNetlistModel::circuit_from_index(size_t index) const
|
||||
std::pair<IndexedNetlistModel::circuit_pair, std::pair<IndexedNetlistModel::Status, std::string> > SingleIndexedNetlistModel::circuit_from_index (size_t index) const
|
||||
{
|
||||
db::Netlist::const_circuit_iterator none;
|
||||
return std::make_pair (attr_by_object_and_index (std::make_pair (mp_netlist, (const db::Netlist *) 0), index, mp_netlist->begin_circuits (), mp_netlist->end_circuits (), none, none, m_circuit_by_index, sort_by_name<db::Circuit> ()), std::make_pair (db::NetlistCrossReference::None, std::string ()));
|
||||
}
|
||||
|
||||
std::pair<IndexedNetlistModel::net_pair, std::pair<IndexedNetlistModel::Status, std::string> > SingleIndexedNetlistModel::net_from_index(const circuit_pair &circuits, size_t index) const
|
||||
std::pair<IndexedNetlistModel::net_pair, std::pair<IndexedNetlistModel::Status, std::string> > SingleIndexedNetlistModel::net_from_index (const circuit_pair &circuits, size_t index) const
|
||||
{
|
||||
db::Circuit::const_net_iterator none;
|
||||
return std::make_pair (attr_by_object_and_index (circuits, index, circuits.first->begin_nets (), circuits.first->end_nets (), none, none, m_net_by_circuit_and_index, sort_by_expanded_name<db::Net> ()), std::make_pair (db::NetlistCrossReference::None, std::string ()));
|
||||
return std::make_pair (attr_by_object_and_index (std::make_pair (circuits.first, (const db::Circuit *) 0), index, circuits.first->begin_nets (), circuits.first->end_nets (), none, none, m_net_by_circuit_and_index, sort_by_expanded_name<db::Net> ()), std::make_pair (db::NetlistCrossReference::None, std::string ()));
|
||||
}
|
||||
|
||||
const db::Net *
|
||||
|
|
@ -346,12 +346,15 @@ IndexedNetlistModel::net_subcircuit_pin_pair
|
|||
SingleIndexedNetlistModel::net_subcircuit_pinref_from_index (const net_pair &nets, size_t index) const
|
||||
{
|
||||
db::Net::const_subcircuit_pin_iterator none;
|
||||
return attr_by_object_and_index (nets, index, nets.first->begin_subcircuit_pins (), nets.first->end_subcircuit_pins (), none, none, m_subcircuit_pinref_by_net_and_index, sort_by_pin_name<db::NetSubcircuitPinRef> ());
|
||||
return attr_by_object_and_index (std::make_pair (nets.first, (const db::Net *) 0), index, nets.first->begin_subcircuit_pins (), nets.first->end_subcircuit_pins (), none, none, m_subcircuit_pinref_by_net_and_index, sort_by_pin_name<db::NetSubcircuitPinRef> ());
|
||||
}
|
||||
|
||||
IndexedNetlistModel::net_subcircuit_pin_pair
|
||||
SingleIndexedNetlistModel::subcircuit_pinref_from_index (const subcircuit_pair &subcircuits, size_t index) const
|
||||
SingleIndexedNetlistModel::subcircuit_pinref_from_index (const subcircuit_pair &subcircuits_in, size_t index) const
|
||||
{
|
||||
subcircuit_pair subcircuits = subcircuits_in;
|
||||
subcircuits.second = 0;
|
||||
|
||||
if (! subcircuits.first) {
|
||||
return IndexedNetlistModel::net_subcircuit_pin_pair ((const db::NetSubcircuitPinRef *) 0, (const db::NetSubcircuitPinRef *) 0);
|
||||
}
|
||||
|
|
@ -381,62 +384,68 @@ IndexedNetlistModel::net_terminal_pair
|
|||
SingleIndexedNetlistModel::net_terminalref_from_index (const net_pair &nets, size_t index) const
|
||||
{
|
||||
db::Net::const_terminal_iterator none;
|
||||
return attr_by_object_and_index (nets, index, nets.first->begin_terminals (), nets.first->end_terminals (), none, none, m_terminalref_by_net_and_index, sort_by_terminal_id<db::NetTerminalRef> ());
|
||||
return attr_by_object_and_index (std::make_pair (nets.first, (const db::Net *) 0), index, nets.first->begin_terminals (), nets.first->end_terminals (), none, none, m_terminalref_by_net_and_index, sort_by_terminal_id<db::NetTerminalRef> ());
|
||||
}
|
||||
|
||||
IndexedNetlistModel::net_pin_pair
|
||||
SingleIndexedNetlistModel::net_pinref_from_index (const net_pair &nets, size_t index) const
|
||||
{
|
||||
db::Net::const_pin_iterator none;
|
||||
return attr_by_object_and_index (nets, index, nets.first->begin_pins (), nets.first->end_pins (), none, none, m_pinref_by_net_and_index, sort_by_pin_name<db::NetPinRef> ());
|
||||
return attr_by_object_and_index (std::make_pair (nets.first, (const db::Net *) 0), index, nets.first->begin_pins (), nets.first->end_pins (), none, none, m_pinref_by_net_and_index, sort_by_pin_name<db::NetPinRef> ());
|
||||
}
|
||||
|
||||
std::pair<IndexedNetlistModel::device_pair, std::pair<IndexedNetlistModel::Status, std::string> > SingleIndexedNetlistModel::device_from_index(const circuit_pair &circuits, size_t index) const
|
||||
std::pair<IndexedNetlistModel::device_pair, std::pair<IndexedNetlistModel::Status, std::string> > SingleIndexedNetlistModel::device_from_index (const circuit_pair &circuits, size_t index) const
|
||||
{
|
||||
db::Circuit::const_device_iterator none;
|
||||
return std::make_pair (attr_by_object_and_index (circuits, index, circuits.first->begin_devices (), circuits.first->end_devices (), none, none, m_device_by_circuit_and_index, sort_by_expanded_name<db::Device> ()), std::make_pair (db::NetlistCrossReference::None, std::string ()));
|
||||
return std::make_pair (attr_by_object_and_index (std::make_pair (circuits.first, (const db::Circuit *) 0), index, circuits.first->begin_devices (), circuits.first->end_devices (), none, none, m_device_by_circuit_and_index, sort_by_expanded_name<db::Device> ()), std::make_pair (db::NetlistCrossReference::None, std::string ()));
|
||||
}
|
||||
|
||||
std::pair<IndexedNetlistModel::pin_pair, std::pair<IndexedNetlistModel::Status, std::string> > SingleIndexedNetlistModel::pin_from_index(const circuit_pair &circuits, size_t index) const
|
||||
std::pair<IndexedNetlistModel::pin_pair, std::pair<IndexedNetlistModel::Status, std::string> > SingleIndexedNetlistModel::pin_from_index (const circuit_pair &circuits, size_t index) const
|
||||
{
|
||||
db::Circuit::const_pin_iterator none;
|
||||
return std::make_pair (attr_by_object_and_index (circuits, index, circuits.first->begin_pins (), circuits.first->end_pins (), none, none, m_pin_by_circuit_and_index, Unsorted ()), std::make_pair (db::NetlistCrossReference::None, std::string ()));
|
||||
return std::make_pair (attr_by_object_and_index (std::make_pair (circuits.first, (const db::Circuit *) 0), index, circuits.first->begin_pins (), circuits.first->end_pins (), none, none, m_pin_by_circuit_and_index, Unsorted ()), std::make_pair (db::NetlistCrossReference::None, std::string ()));
|
||||
}
|
||||
|
||||
std::pair<IndexedNetlistModel::subcircuit_pair, std::pair<IndexedNetlistModel::Status, std::string> > SingleIndexedNetlistModel::subcircuit_from_index(const circuit_pair &circuits, size_t index) const
|
||||
std::pair<IndexedNetlistModel::subcircuit_pair, std::pair<IndexedNetlistModel::Status, std::string> > SingleIndexedNetlistModel::subcircuit_from_index (const circuit_pair &circuits, size_t index) const
|
||||
{
|
||||
db::Circuit::const_subcircuit_iterator none;
|
||||
return std::make_pair (attr_by_object_and_index (circuits, index, circuits.first->begin_subcircuits (), circuits.first->end_subcircuits (), none, none, m_subcircuit_by_circuit_and_index, sort_by_expanded_name<db::SubCircuit> ()), std::make_pair (db::NetlistCrossReference::None, std::string ()));
|
||||
return std::make_pair (attr_by_object_and_index (std::make_pair (circuits.first, (const db::Circuit *) 0), index, circuits.first->begin_subcircuits (), circuits.first->end_subcircuits (), none, none, m_subcircuit_by_circuit_and_index, sort_by_expanded_name<db::SubCircuit> ()), std::make_pair (db::NetlistCrossReference::None, std::string ()));
|
||||
}
|
||||
|
||||
size_t
|
||||
SingleIndexedNetlistModel::circuit_index (const circuit_pair &circuits) const
|
||||
{
|
||||
db::Netlist::const_circuit_iterator none;
|
||||
return index_from_attr (circuits, mp_netlist->begin_circuits (), mp_netlist->end_circuits (), none, none, m_circuit_index_by_object, sort_by_name<db::Circuit> ());
|
||||
return index_from_attr (std::make_pair (circuits.first, (const db::Circuit *) 0), mp_netlist->begin_circuits (), mp_netlist->end_circuits (), none, none, m_circuit_index_by_object, sort_by_name<db::Circuit> ());
|
||||
}
|
||||
|
||||
size_t
|
||||
SingleIndexedNetlistModel::net_index (const net_pair &nets) const
|
||||
SingleIndexedNetlistModel::net_index (const net_pair &nets_in) const
|
||||
{
|
||||
db::Circuit::const_net_iterator none;
|
||||
|
||||
net_pair nets = nets_in;
|
||||
nets.second = 0;
|
||||
|
||||
circuit_pair circuits = parent_of (nets);
|
||||
return index_from_attr (nets,
|
||||
circuits.first ? circuits.first->begin_nets () : none, circuits.first ? circuits.first->end_nets () : none,
|
||||
circuits.second ? circuits.second->begin_nets () : none, circuits.second ? circuits.second->end_nets () : none,
|
||||
none, none,
|
||||
m_net_index_by_object, sort_by_expanded_name<db::Net> ());
|
||||
}
|
||||
|
||||
size_t
|
||||
SingleIndexedNetlistModel::device_index (const device_pair &devices) const
|
||||
SingleIndexedNetlistModel::device_index (const device_pair &devices_in) const
|
||||
{
|
||||
db::Circuit::const_device_iterator none;
|
||||
|
||||
device_pair devices = devices_in;
|
||||
devices.second = 0;
|
||||
|
||||
circuit_pair circuits = parent_of (devices);
|
||||
return index_from_attr (devices,
|
||||
circuits.first ? circuits.first->begin_devices () : none, circuits.first ? circuits.first->end_devices () : none,
|
||||
circuits.second ? circuits.second->begin_devices () : none, circuits.second ? circuits.second->end_devices () : none,
|
||||
none, none,
|
||||
m_device_index_by_object, sort_by_expanded_name<db::Device> ());
|
||||
}
|
||||
|
||||
|
|
@ -445,21 +454,24 @@ SingleIndexedNetlistModel::pin_index (const pin_pair &pins, const circuit_pair &
|
|||
{
|
||||
db::Circuit::const_pin_iterator none;
|
||||
|
||||
return index_from_attr (pins,
|
||||
return index_from_attr (std::make_pair (pins.first, (const db::Pin *) 0),
|
||||
circuits.first ? circuits.first->begin_pins () : none, circuits.first ? circuits.first->end_pins () : none,
|
||||
circuits.second ? circuits.second->begin_pins () : none, circuits.second ? circuits.second->end_pins () : none,
|
||||
none, none,
|
||||
m_pin_index_by_object, sort_by_expanded_name<db::Pin> ());
|
||||
}
|
||||
|
||||
size_t
|
||||
SingleIndexedNetlistModel::subcircuit_index (const subcircuit_pair &subcircuits) const
|
||||
SingleIndexedNetlistModel::subcircuit_index (const subcircuit_pair &subcircuits_in) const
|
||||
{
|
||||
db::Circuit::const_subcircuit_iterator none;
|
||||
|
||||
subcircuit_pair subcircuits = subcircuits_in;
|
||||
subcircuits.second = 0;
|
||||
|
||||
circuit_pair circuits = parent_of (subcircuits);
|
||||
return index_from_attr (subcircuits,
|
||||
circuits.first ? circuits.first->begin_subcircuits () : none, circuits.first ? circuits.first->end_subcircuits () : none,
|
||||
circuits.second ? circuits.second->begin_subcircuits () : none, circuits.second ? circuits.second->end_subcircuits () : none,
|
||||
none, none,
|
||||
m_subcircuit_index_by_object, sort_by_expanded_name<db::SubCircuit> ());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -141,6 +141,12 @@ NetlistBrowserDialog::db ()
|
|||
return mp_ui->browser_page->db ();
|
||||
}
|
||||
|
||||
int
|
||||
NetlistBrowserDialog::l2n_index ()
|
||||
{
|
||||
return m_l2n_index;
|
||||
}
|
||||
|
||||
const lay::NetlistObjectsPath &
|
||||
NetlistBrowserDialog::current_path () const
|
||||
{
|
||||
|
|
@ -152,6 +158,14 @@ NetlistBrowserDialog::current_path () const
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
NetlistBrowserDialog::set_current_path (const lay::NetlistObjectsPath &path)
|
||||
{
|
||||
if (mp_ui->browser_page) {
|
||||
mp_ui->browser_page->select_path (path);
|
||||
}
|
||||
}
|
||||
|
||||
const std::vector<lay::NetlistObjectsPath> &
|
||||
NetlistBrowserDialog::selected_paths () const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -77,11 +77,26 @@ public:
|
|||
*/
|
||||
db::LayoutToNetlist *db ();
|
||||
|
||||
/**
|
||||
* @brief Gets the index of the currently selected database in the view
|
||||
*/
|
||||
int l2n_index ();
|
||||
|
||||
/**
|
||||
* @brief Gets the current object's path
|
||||
*/
|
||||
const lay::NetlistObjectsPath ¤t_path () const;
|
||||
|
||||
/**
|
||||
* @brief Sets the current object's path
|
||||
*
|
||||
* This will make the given netlist object the current one and change the
|
||||
* selection to this one.
|
||||
*
|
||||
* Passing a null path will clear the selection.
|
||||
*/
|
||||
void set_current_path (const lay::NetlistObjectsPath &path);
|
||||
|
||||
/**
|
||||
* @brief Gets the selected nets
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -3025,9 +3025,9 @@ NetlistBrowserModel::index_from_subcircuit (const std::pair<const db::SubCircuit
|
|||
}
|
||||
|
||||
QModelIndex
|
||||
NetlistBrowserModel::index_from_circuit (const db::Circuit *net) const
|
||||
NetlistBrowserModel::index_from_circuit (const db::Circuit *circuit) const
|
||||
{
|
||||
return index_from_circuit (std::make_pair (net, mp_indexer->second_circuit_for (net)));
|
||||
return index_from_circuit (std::make_pair (circuit, mp_indexer->second_circuit_for (circuit)));
|
||||
}
|
||||
|
||||
std::pair<const db::Circuit *, const db::Circuit *>
|
||||
|
|
|
|||
|
|
@ -502,9 +502,9 @@ NetlistBrowserPage::select_path (const lay::NetlistObjectsPath &path)
|
|||
{
|
||||
if (path.is_null ()) {
|
||||
|
||||
nl_directory_tree->clearSelection ();
|
||||
sch_directory_tree->clearSelection ();
|
||||
xref_directory_tree->clearSelection ();
|
||||
nl_directory_tree->setCurrentIndex (QModelIndex ());
|
||||
sch_directory_tree->setCurrentIndex (QModelIndex ());
|
||||
xref_directory_tree->setCurrentIndex (QModelIndex ());
|
||||
|
||||
} else {
|
||||
|
||||
|
|
@ -514,17 +514,33 @@ NetlistBrowserPage::select_path (const lay::NetlistObjectsPath &path)
|
|||
|
||||
model = dynamic_cast<NetlistBrowserModel *> (nl_directory_tree->model ());
|
||||
if (model) {
|
||||
nl_directory_tree->setCurrentIndex (model->index_from_path (path));
|
||||
if (lvsdb && lvsdb->cross_ref () && ! path.root.first) {
|
||||
lay::NetlistObjectsPath nl_path = lay::NetlistObjectsPath::from_first (path.second ());
|
||||
// Note: translation helps generating a layout-netlist index to
|
||||
// naviate to the layout netlist in case of schematic probing for example (only
|
||||
// works if all path components can be translated)
|
||||
if (lay::NetlistObjectsPath::translate (nl_path, *lvsdb->cross_ref ())) {
|
||||
nl_directory_tree->setCurrentIndex (model->index_from_path (nl_path));
|
||||
}
|
||||
} else {
|
||||
nl_directory_tree->setCurrentIndex (model->index_from_path (path));
|
||||
}
|
||||
}
|
||||
|
||||
model = dynamic_cast<NetlistBrowserModel *> (sch_directory_tree->model ());
|
||||
if (model && lvsdb && lvsdb->cross_ref ()) {
|
||||
lay::NetlistObjectsPath sch_path = path;
|
||||
// Note: translation helps generating a schematic-netlist index to
|
||||
// naviate to the schematic netlist in case of probing for example (only
|
||||
// works if all path components can be translated)
|
||||
if (lay::NetlistObjectsPath::translate (sch_path, *lvsdb->cross_ref ())) {
|
||||
if (! path.root.first) {
|
||||
// No first path given: use second one for schematic directly.
|
||||
lay::NetlistObjectsPath sch_path = lay::NetlistObjectsPath::from_first (path.second ());
|
||||
sch_directory_tree->setCurrentIndex (model->index_from_path (sch_path));
|
||||
} else {
|
||||
lay::NetlistObjectsPath sch_path = path;
|
||||
// Note: translation helps generating a schematic-netlist index to
|
||||
// naviate to the schematic netlist in case of probing for example (only
|
||||
// works if all path components can be translated)
|
||||
if (lay::NetlistObjectsPath::translate (sch_path, *lvsdb->cross_ref ())) {
|
||||
sch_directory_tree->setCurrentIndex (model->index_from_path (sch_path));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1315,7 +1331,7 @@ NetlistBrowserPage::clear_highlights ()
|
|||
void
|
||||
NetlistBrowserPage::highlight (const NetlistObjectsPath ¤t_path, const std::vector<NetlistObjectsPath> &selected_paths)
|
||||
{
|
||||
if (current_path != m_current_path && selected_paths != m_selected_paths) {
|
||||
if (current_path != m_current_path || selected_paths != m_selected_paths) {
|
||||
|
||||
m_current_path = current_path;
|
||||
m_selected_paths = selected_paths;
|
||||
|
|
|
|||
|
|
@ -169,6 +169,11 @@ public:
|
|||
*/
|
||||
void update_highlights ();
|
||||
|
||||
/**
|
||||
* @brief Adjusts the view depending on the current settings
|
||||
*/
|
||||
void adjust_view ();
|
||||
|
||||
/**
|
||||
* @brief Gets the current object's path
|
||||
*/
|
||||
|
|
@ -255,7 +260,6 @@ private:
|
|||
void setup_trees ();
|
||||
void add_to_history (const QModelIndex &index, bool fwd);
|
||||
void navigate_to (const QModelIndex &index, bool forward = true);
|
||||
void adjust_view ();
|
||||
void clear_markers ();
|
||||
void highlight (const NetlistObjectsPath ¤t_path, const std::vector<NetlistObjectsPath> &selected_paths);
|
||||
void clear_highlights ();
|
||||
|
|
|
|||
|
|
@ -139,10 +139,14 @@ LayoutViewNotificationWidget::LayoutViewNotificationWidget (LayoutViewWidget *pa
|
|||
void
|
||||
LayoutViewNotificationWidget::action_triggered ()
|
||||
{
|
||||
BEGIN_PROTECTED
|
||||
|
||||
auto a = m_action_buttons.find (sender ());
|
||||
if (a != m_action_buttons.end ()) {
|
||||
mp_parent->notification_action (*mp_notification, a->second);
|
||||
}
|
||||
|
||||
END_PROTECTED_W (this)
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
#include "tlTimer.h"
|
||||
#include "tlStream.h"
|
||||
#include "tlFileUtils.h"
|
||||
#include "tlEnv.h"
|
||||
|
||||
#include "dbReader.h"
|
||||
#include "dbStream.h"
|
||||
|
|
@ -40,44 +41,31 @@ namespace db
|
|||
// ---------------------------------------------------------------
|
||||
// Plugin for the stream reader
|
||||
|
||||
static std::string lef_file_formats ()
|
||||
{
|
||||
static std::string s;
|
||||
if (s.empty ()) {
|
||||
s = tl::get_env ("KLAYOUT_LEF_FORMAT", "*.lef *.LEF *.lef.gz *.LEF.gz");
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
static std::string def_file_formats ()
|
||||
{
|
||||
static std::string s;
|
||||
if (s.empty ()) {
|
||||
s = tl::get_env ("KLAYOUT_DEF_FORMAT", "*.def *.DEF *.def.gz *.DEF.gz");
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Determines the format of the given stream
|
||||
* Returns true, if the stream has LEF format
|
||||
*/
|
||||
static bool is_lef_format (const std::string &fn)
|
||||
{
|
||||
static const char *suffixes[] = { ".lef", ".LEF", ".lef.gz", ".LEF.gz" };
|
||||
|
||||
// NOTE: there is no reliable way of (easily) detecting the format. Hence we use the file
|
||||
// name's suffix for the format hint.
|
||||
for (size_t i = 0; i < sizeof (suffixes) / sizeof (suffixes[0]); ++i) {
|
||||
std::string suffix = suffixes [i];
|
||||
if (fn.size () > suffix.size () && fn.find (suffix) == fn.size () - suffix.size ()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Determines the format of the given stream
|
||||
* Returns true, if the stream has DEF format
|
||||
*/
|
||||
static bool is_def_format (const std::string &fn)
|
||||
{
|
||||
static const char *suffixes[] = { ".def", ".DEF", ".def.gz", ".DEF.gz" };
|
||||
|
||||
// NOTE: there is no reliable way of (easily) detecting the format. Hence we use the file
|
||||
// name's suffix for the format hint.
|
||||
for (size_t i = 0; i < sizeof (suffixes) / sizeof (suffixes[0]); ++i) {
|
||||
std::string suffix = suffixes [i];
|
||||
if (fn.size () > suffix.size () && fn.find (suffix) == fn.size () - suffix.size ()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return tl::match_filename_to_format (fn, std::string ("LEF files (") + lef_file_formats () + ")");
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
|
@ -92,13 +80,13 @@ LEFDEFReader::LEFDEFReader (tl::InputStream &s)
|
|||
const db::LayerMap &
|
||||
LEFDEFReader::read (db::Layout &layout, const db::LoadLayoutOptions &options)
|
||||
{
|
||||
return read_lefdef (layout, options, is_lef_format (m_stream.filename ()));
|
||||
return read_lefdef (layout, options, is_lef_format ("." + m_stream.suffix ()));
|
||||
}
|
||||
|
||||
const db::LayerMap &
|
||||
LEFDEFReader::read (db::Layout &layout)
|
||||
{
|
||||
return read_lefdef (layout, db::LoadLayoutOptions (), is_lef_format (m_stream.filename ()));
|
||||
return read_lefdef (layout, db::LoadLayoutOptions (), is_lef_format ("." + m_stream.suffix ()));
|
||||
}
|
||||
|
||||
const char *
|
||||
|
|
@ -283,11 +271,11 @@ class LEFDEFFormatDeclaration
|
|||
virtual std::string format_name () const { return "LEFDEF"; }
|
||||
virtual std::string format_desc () const { return "LEF/DEF"; }
|
||||
virtual std::string format_title () const { return "LEF/DEF (unified reader)"; }
|
||||
virtual std::string file_format () const { return "LEF/DEF files (*.lef *.LEF *.lef.gz *.LEF.gz *.def *.DEF *.def.gz *.DEF.gz)"; }
|
||||
virtual std::string file_format () const { return std::string ("LEF/DEF files (") + lef_file_formats () + " " + def_file_formats () + ")"; }
|
||||
|
||||
virtual bool detect (tl::InputStream &stream) const
|
||||
{
|
||||
return is_lef_format (stream.filename ()) || is_def_format (stream.filename ());
|
||||
return tl::match_filename_to_format (stream.filename (), file_format ());
|
||||
}
|
||||
|
||||
virtual db::ReaderBase *create_reader (tl::InputStream &s) const
|
||||
|
|
|
|||
|
|
@ -467,15 +467,27 @@ TEST(100)
|
|||
run_test (_this, "issue-172", "lef:in.lef+def:in.def", "au.oas.gz", default_options (), false);
|
||||
}
|
||||
|
||||
TEST(101)
|
||||
TEST(101a)
|
||||
{
|
||||
db::LEFDEFReaderOptions opt = default_options ();
|
||||
opt.set_produce_pin_names (true);
|
||||
opt.set_pin_property_name (2);
|
||||
opt.set_cell_outline_layer ("OUTLINE (13/0)");
|
||||
|
||||
run_test (_this, "issue-489", "lef:in.lef+def:in.def", "au.oas", opt, false);
|
||||
}
|
||||
|
||||
TEST(101b)
|
||||
{
|
||||
db::LEFDEFReaderOptions opt = default_options ();
|
||||
opt.set_produce_pin_names (true);
|
||||
opt.set_pin_property_name (2);
|
||||
opt.set_cell_outline_layer ("OUTLINE (13/0)");
|
||||
|
||||
// also with fake suffix
|
||||
run_test (_this, "issue-489", "lef:'in.l[lef]'+def:'in.d[def]'", "au.oas", opt, false);
|
||||
}
|
||||
|
||||
TEST(102)
|
||||
{
|
||||
db::LEFDEFReaderOptions opt = default_options ();
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
#include "dbOASISWriter.h"
|
||||
#include "dbTextWriter.h"
|
||||
#include "dbTestSupport.h"
|
||||
#include "dbLayoutDiff.h"
|
||||
#include "tlLog.h"
|
||||
#include "tlUnitTest.h"
|
||||
#include "tlStream.h"
|
||||
|
|
@ -696,3 +697,49 @@ TEST(BlendCrash)
|
|||
std::string fn_au (tl::testdata () + "/oasis/blend_crash_au.gds.gz");
|
||||
db::compare_layouts (_this, layout, fn_au, db::WriteGDS2, 1);
|
||||
}
|
||||
|
||||
TEST(CBlockLargePropertyString)
|
||||
{
|
||||
// NOTE: we try different blob sizes for triggering various reallocation szenarios
|
||||
for (size_t f = 0; f < 50; ++f) {
|
||||
|
||||
size_t blob_size = size_t (12345) * f;
|
||||
|
||||
tl::info << "Trying blob size of " << blob_size;
|
||||
|
||||
db::Layout layout_org (false);
|
||||
|
||||
unsigned int layer = layout_org.insert_layer (db::LayerProperties (1, 0));
|
||||
db::Cell &top = layout_org.cell (layout_org.add_cell ("TOP"));
|
||||
|
||||
std::string large_value (blob_size, 'a');
|
||||
|
||||
db::PropertiesSet ps;
|
||||
ps.insert (db::property_names_id (tl::Variant ("blob")), tl::Variant (large_value));
|
||||
|
||||
top.shapes (layer).insert (db::BoxWithProperties (db::Box (0, 0, 100, 100), db::properties_id (ps)));
|
||||
|
||||
std::string tmp_file = tl::TestBase::tmp_file ("tmp_OASISReaderLargeString.oas");
|
||||
|
||||
{
|
||||
tl::OutputStream out (tmp_file);
|
||||
db::SaveLayoutOptions options;
|
||||
db::OASISWriterOptions &oasis_options = options.get_options<db::OASISWriterOptions> ();
|
||||
oasis_options.write_cblocks = true;
|
||||
oasis_options.strict_mode = false;
|
||||
db::OASISWriter writer;
|
||||
writer.write (layout_org, out, options);
|
||||
}
|
||||
|
||||
db::Layout layout_read;
|
||||
|
||||
{
|
||||
tl::InputStream in (tmp_file);
|
||||
db::OASISReader reader (in);
|
||||
reader.read (layout_read);
|
||||
}
|
||||
|
||||
EXPECT_EQ (db::compare_layouts (layout_org, layout_read, db::layout_diff::f_verbose, 0), true);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -149,6 +149,7 @@ RUBYTEST (extNetTracer, "extNetTracer.rb")
|
|||
RUBYTEST (imgObject, "imgObject.rb")
|
||||
RUBYTEST (layLayers, "layLayers.rb")
|
||||
RUBYTEST (layLayoutView, "layLayoutView.rb")
|
||||
RUBYTEST (layNetlistBrowser, "layNetlistBrowser.rb")
|
||||
RUBYTEST (layMainWindow, "layMainWindow.rb")
|
||||
RUBYTEST (layMarkers, "layMarkers.rb")
|
||||
RUBYTEST (layMacro, "layMacro.rb")
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
#include "tlAssert.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
|
|
@ -227,9 +228,12 @@ InflateFilter::InflateFilter (tl::InputStream &input)
|
|||
m_last_block (false),
|
||||
m_uncompressed_length (0) // this forces a new block on "process()"
|
||||
{
|
||||
for (size_t i = 0; i < sizeof (m_buffer) / sizeof (m_buffer [0]); ++i) {
|
||||
m_buffer[i] = 0;
|
||||
}
|
||||
// NOTE: the minimum buffer size of 65536 corresponds to the maximum block size
|
||||
// of the block repetition decoder
|
||||
m_blen = 65536; // initially
|
||||
|
||||
m_buffer = new char [m_blen];
|
||||
std::memset (m_buffer, 0, m_blen);
|
||||
|
||||
mp_dist_decoder = new HuffmannDecoder ();
|
||||
mp_lit_decoder = new HuffmannDecoder ();
|
||||
|
|
@ -237,6 +241,9 @@ InflateFilter::InflateFilter (tl::InputStream &input)
|
|||
|
||||
InflateFilter::~InflateFilter ()
|
||||
{
|
||||
delete[] m_buffer;
|
||||
m_buffer = 0;
|
||||
m_blen = 0;
|
||||
delete mp_dist_decoder;
|
||||
mp_dist_decoder = 0;
|
||||
delete mp_lit_decoder;
|
||||
|
|
@ -246,9 +253,36 @@ InflateFilter::~InflateFilter ()
|
|||
const char *
|
||||
InflateFilter::get (size_t n)
|
||||
{
|
||||
tl_assert (n < sizeof (m_buffer) / 2);
|
||||
size_t blen = m_blen;
|
||||
while (n >= blen / 2) {
|
||||
blen *= 2;
|
||||
}
|
||||
|
||||
while ((m_b_insert + sizeof (m_buffer) - m_b_read) % sizeof (m_buffer) < n) {
|
||||
// buffer needs to be enlarged - reallocate
|
||||
if (blen != m_blen) {
|
||||
|
||||
// NOTE: the deflate implementation actually looks back past the read pointer
|
||||
// (in put_byte_dist), so we have to maintain the bytes between m_b_read
|
||||
// and m_b_insert too.
|
||||
|
||||
char *new_buffer = new char[blen];
|
||||
|
||||
// place the current block twice at start and end of the block
|
||||
std::memcpy (new_buffer, m_buffer, m_blen);
|
||||
std::memcpy (new_buffer + blen - m_blen, m_buffer, m_blen);
|
||||
|
||||
// adjust read pointer if the stored byte array wrapped around the buffer
|
||||
if (m_b_insert < m_b_read) {
|
||||
m_b_read += blen - m_blen;
|
||||
}
|
||||
|
||||
delete[] m_buffer;
|
||||
m_buffer = new_buffer;
|
||||
m_blen = blen;
|
||||
|
||||
}
|
||||
|
||||
while ((m_b_insert + m_blen - m_b_read) % m_blen < n) {
|
||||
if (! process ()) {
|
||||
throw tl::Exception (tl::to_string (tr ("Unexpected end of file (DEFLATE implementation)")));
|
||||
}
|
||||
|
|
@ -257,14 +291,14 @@ InflateFilter::get (size_t n)
|
|||
tl_assert (m_b_read != m_b_insert);
|
||||
|
||||
// ensure the block is accessible as a coherent chunk:
|
||||
if (m_b_read + n >= sizeof (m_buffer)) {
|
||||
std::rotate (m_buffer, m_buffer + m_b_read, m_buffer + sizeof (m_buffer));
|
||||
m_b_insert = (m_b_insert - m_b_read + sizeof (m_buffer)) % sizeof (m_buffer);
|
||||
if (m_b_read + n >= m_blen) {
|
||||
std::rotate (m_buffer, m_buffer + m_b_read, m_buffer + m_blen);
|
||||
m_b_insert = (m_b_insert - m_b_read + m_blen) % m_blen;
|
||||
m_b_read = 0;
|
||||
}
|
||||
|
||||
const char *r = m_buffer + m_b_read;
|
||||
m_b_read = (m_b_read + n) % sizeof (m_buffer);
|
||||
m_b_read = (m_b_read + n) % m_blen;
|
||||
return r;
|
||||
}
|
||||
|
||||
|
|
@ -290,13 +324,16 @@ void
|
|||
InflateFilter::put_byte (char b)
|
||||
{
|
||||
m_buffer [m_b_insert] = b;
|
||||
m_b_insert = (m_b_insert + 1) % sizeof (m_buffer);
|
||||
m_b_insert = (m_b_insert + 1) % m_blen;
|
||||
// buffer overrun
|
||||
tl_assert (m_b_insert != m_b_read);
|
||||
}
|
||||
|
||||
void
|
||||
InflateFilter::put_byte_dist (unsigned int d)
|
||||
{
|
||||
put_byte (m_buffer [(m_b_insert - d) % sizeof (m_buffer)]);
|
||||
tl_assert (d < m_blen);
|
||||
put_byte (m_buffer [(m_b_insert + m_blen - d) % m_blen]);
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
|||
|
|
@ -232,7 +232,8 @@ public:
|
|||
private:
|
||||
BitStream m_input;
|
||||
|
||||
char m_buffer[65536];
|
||||
char *m_buffer;
|
||||
size_t m_blen;
|
||||
unsigned int m_b_insert;
|
||||
unsigned int m_b_read;
|
||||
bool m_at_end;
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@
|
|||
#include "tlString.h"
|
||||
#include "tlUri.h"
|
||||
#include "tlHttpStream.h"
|
||||
#include "tlGlobPattern.h"
|
||||
|
||||
#if defined(HAVE_QT)
|
||||
# include <QByteArray>
|
||||
|
|
@ -304,6 +305,9 @@ InputStream::InputStream (InputStreamBase &delegate)
|
|||
m_bcap = 4096; // initial buffer capacity
|
||||
m_blen = 0;
|
||||
mp_buffer = new char [m_bcap];
|
||||
|
||||
m_explicit_suffix = false;
|
||||
m_suffix = tl::extension (delegate.filename ());
|
||||
}
|
||||
|
||||
InputStream::InputStream (InputStreamBase *delegate)
|
||||
|
|
@ -312,9 +316,14 @@ InputStream::InputStream (InputStreamBase *delegate)
|
|||
m_bcap = 4096; // initial buffer capacity
|
||||
m_blen = 0;
|
||||
mp_buffer = new char [m_bcap];
|
||||
|
||||
m_explicit_suffix = false;
|
||||
if (delegate) {
|
||||
m_suffix = tl::extension (delegate->filename ());
|
||||
}
|
||||
}
|
||||
|
||||
InputStream::InputStream (const std::string &abstract_path)
|
||||
InputStream::InputStream (const std::string &abstract_path_in, bool allow_explicit_suffix)
|
||||
: m_pos (0), mp_bptr (0), mp_delegate (0), m_owns_delegate (false), mp_inflate (0), m_inflate_always (false), m_stop_after_inflate (false)
|
||||
{
|
||||
m_bcap = 4096; // initial buffer capacity
|
||||
|
|
@ -323,6 +332,22 @@ InputStream::InputStream (const std::string &abstract_path)
|
|||
|
||||
bool needs_inflate = false;
|
||||
|
||||
std::string abstract_path = abstract_path_in;
|
||||
m_explicit_suffix = false;
|
||||
|
||||
// extract override suffix if needed
|
||||
if (allow_explicit_suffix) {
|
||||
|
||||
tl::GlobPattern pat ("(*)\\[(*)\\]");
|
||||
std::vector<std::string> pat_parts;
|
||||
if (pat.match (abstract_path_in, pat_parts) && pat_parts.size () == 2) {
|
||||
abstract_path = pat_parts[0];
|
||||
m_suffix = pat_parts[1];
|
||||
m_explicit_suffix = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
tl::Extractor ex (abstract_path.c_str ());
|
||||
|
||||
if (ex.test (":")) {
|
||||
|
|
@ -404,6 +429,10 @@ InputStream::InputStream (const std::string &abstract_path)
|
|||
|
||||
m_owns_delegate = true;
|
||||
|
||||
if (mp_delegate && ! m_explicit_suffix) {
|
||||
m_suffix = tl::extension (mp_delegate->filename ());
|
||||
}
|
||||
|
||||
if (needs_inflate) {
|
||||
inflate_always ();
|
||||
}
|
||||
|
|
@ -1696,7 +1725,7 @@ match_filename_to_format (const std::string &fn, const std::string &fmt)
|
|||
while (*fpp && *fpp != ' ' && *fpp != ')') {
|
||||
++fpp;
|
||||
}
|
||||
if (fn.size () > (unsigned int) (fpp - fp) && strncmp (fn.c_str () + fn.size () - (fpp - fp), fp, fpp - fp) == 0) {
|
||||
if (fn.size () >= (unsigned int) (fpp - fp) && strncmp (fn.c_str () + fn.size () - (fpp - fp), fp, fpp - fp) == 0) {
|
||||
return true;
|
||||
}
|
||||
fp = fpp;
|
||||
|
|
|
|||
|
|
@ -408,9 +408,14 @@ public:
|
|||
* This will automatically create the appropriate delegate and
|
||||
* delete it later.
|
||||
*
|
||||
* The abstract path
|
||||
* @param abstract_path The abstract path (can be "pipe:<cmd>", "data:<base64-data>", "file:...", "http(s):...".
|
||||
* @param allow_explicit_suffix If true, extracts the suffix from the abstract path
|
||||
*
|
||||
* With explicit suffix, the abstract path can be appended an override suffix in the
|
||||
* form "path[suffix]" (e.g. "file.any[gds]"). The override suffix can be accessed with
|
||||
* the "suffix" accessor. If an explicit suffix is given, "is_explicit_suffix" is true.
|
||||
*/
|
||||
InputStream (const std::string &abstract_path);
|
||||
InputStream (const std::string &abstract_path, bool allow_explicit_suffix = true);
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
|
|
@ -528,6 +533,25 @@ public:
|
|||
return mp_delegate->absolute_path ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the suffix
|
||||
*
|
||||
* The suffix is either the override suffix or the
|
||||
* filename's suffix if no override is given.
|
||||
*/
|
||||
const std::string &suffix () const
|
||||
{
|
||||
return m_suffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating if an explicit suffix is given
|
||||
*/
|
||||
bool is_explicit_suffix () const
|
||||
{
|
||||
return m_explicit_suffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reset to the initial position
|
||||
*/
|
||||
|
|
@ -593,6 +617,9 @@ private:
|
|||
InputStreamBase *mp_delegate;
|
||||
bool m_owns_delegate;
|
||||
|
||||
std::string m_suffix;
|
||||
bool m_explicit_suffix;
|
||||
|
||||
// inflate support
|
||||
InflateFilter *mp_inflate;
|
||||
bool m_inflate_always;
|
||||
|
|
|
|||
|
|
@ -187,6 +187,29 @@ TEST(DataInputStream)
|
|||
EXPECT_EQ (tis.get_line (), "separated by a LFCR and CRLF.");
|
||||
EXPECT_EQ (tis.line_number (), size_t (4));
|
||||
EXPECT_EQ (tis.at_end (), true);
|
||||
|
||||
EXPECT_EQ (is.is_explicit_suffix (), false);
|
||||
EXPECT_EQ (is.suffix (), "");
|
||||
}
|
||||
|
||||
TEST(DataInputStreamWithSuffix)
|
||||
{
|
||||
tl::InputStream is ("data:SGVsbG8sIHdvcmxkIQpXaXRoIGFub3RoZXIgbGluZQoNDQpzZXBhcmF0ZWQgYnkgYSBMRkNSIGFuZCBDUkxGLg==[txt]");
|
||||
tl::TextInputStream tis (is);
|
||||
EXPECT_EQ (tis.get_line (), "Hello, world!");
|
||||
EXPECT_EQ (tis.line_number (), size_t (1));
|
||||
EXPECT_EQ (tis.get_line (), "With another line");
|
||||
EXPECT_EQ (tis.line_number (), size_t (2));
|
||||
EXPECT_EQ (tis.peek_char (), '\n');
|
||||
EXPECT_EQ (tis.get_line (), "");
|
||||
EXPECT_EQ (tis.line_number (), size_t (3));
|
||||
EXPECT_EQ (tis.peek_char (), 's');
|
||||
EXPECT_EQ (tis.get_line (), "separated by a LFCR and CRLF.");
|
||||
EXPECT_EQ (tis.line_number (), size_t (4));
|
||||
EXPECT_EQ (tis.at_end (), true);
|
||||
|
||||
EXPECT_EQ (is.is_explicit_suffix (), true);
|
||||
EXPECT_EQ (is.suffix (), "txt");
|
||||
}
|
||||
|
||||
namespace
|
||||
|
|
@ -588,3 +611,16 @@ TEST(AbstractPathFunctions)
|
|||
EXPECT_EQ (tl::InputStream::as_file_path ("a\\b\\c"), "a\\b\\c");
|
||||
tl::file_utils_force_reset ();
|
||||
}
|
||||
|
||||
TEST(MatchFormat)
|
||||
{
|
||||
EXPECT_EQ (tl::match_filename_to_format ("abc.txt", "Text files (*.txt *.TXT)"), true);
|
||||
EXPECT_EQ (tl::match_filename_to_format ("abc.txt", "Text files (*.txt)"), true);
|
||||
EXPECT_EQ (tl::match_filename_to_format ("abc.txt", "Text files (*.TXT)"), false);
|
||||
EXPECT_EQ (tl::match_filename_to_format (".txt", "Text files (*.txt *.TXT)"), true);
|
||||
EXPECT_EQ (tl::match_filename_to_format ("/home/xyz/abc.txt", "Text files (*.txt *.TXT)"), true);
|
||||
EXPECT_EQ (tl::match_filename_to_format ("txt", "Text files (*.txt *.TXT)"), false);
|
||||
EXPECT_EQ (tl::match_filename_to_format ("abc.TXT", "Text files (*.txt *.TXT)"), true);
|
||||
EXPECT_EQ (tl::match_filename_to_format ("abc.TEXT", "Text files (*.txt *.TXT)"), false);
|
||||
EXPECT_EQ (tl::match_filename_to_format ("abc.TEXT", "Text files (*)"), true);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
|
||||
# This is a smoke test
|
||||
deep
|
||||
|
||||
puts("This is DRC.")
|
||||
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
VERSION 5.7 ;
|
||||
DIVIDERCHAR "/" ;
|
||||
BUSBITCHARS "[]" ;
|
||||
DESIGN test ;
|
||||
UNITS DISTANCE MICRONS 2000 ;
|
||||
|
||||
DIEAREA ( 0 0 ) ( 37520 7840 ) ;
|
||||
|
||||
PINS 12 ;
|
||||
- VDD + NET VDD + SPECIAL + DIRECTION INOUT + USE POWER
|
||||
+ LAYER M2 ( -320 0 ) ( 320 37520 )
|
||||
+ FIXED ( 37520 3920 ) W ;
|
||||
- VSS + NET VSS + SPECIAL + DIRECTION INOUT + USE GROUND
|
||||
+ PORT
|
||||
+ LAYER M2 ( -18760 0 ) ( 18760 640 )
|
||||
+ FIXED ( 18760 -320 ) N
|
||||
+ PORT
|
||||
+ LAYER M2 ( -18760 0 ) ( 18760 640 )
|
||||
+ FIXED ( 18760 8160 ) S
|
||||
;
|
||||
END PINS
|
||||
|
||||
SPECIALNETS 4 ;
|
||||
- VSS ( * VSS )
|
||||
+ ROUTED M2 640 + SHAPE FOLLOWPIN ( 0 0 ) ( 37520 * )
|
||||
NEW M2 640 + SHAPE FOLLOWPIN ( 0 7840 ) ( 37520 * )
|
||||
+ USE GROUND
|
||||
;
|
||||
- VDD ( * VDD )
|
||||
+ ROUTED M2 640 + SHAPE FOLLOWPIN ( 0 3920 ) ( 37520 * )
|
||||
+ USE POWER
|
||||
;
|
||||
END SPECIALNETS
|
||||
END DESIGN
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
VERSION 5.7 ;
|
||||
|
||||
BUSBITCHARS "[]" ;
|
||||
DIVIDERCHAR "/" ;
|
||||
UNITS
|
||||
DATABASE MICRONS 1000 ;
|
||||
END UNITS
|
||||
|
||||
MANUFACTURINGGRID 0.002 ;
|
||||
|
||||
USEMINSPACING OBS OFF ;
|
||||
|
||||
LAYER overlap
|
||||
TYPE OVERLAP ;
|
||||
END overlap
|
||||
|
||||
LAYER contact
|
||||
TYPE CUT ;
|
||||
END contact
|
||||
|
||||
LAYER metal1
|
||||
TYPE ROUTING ;
|
||||
DIRECTION HORIZONTAL ;
|
||||
END metal1
|
||||
|
||||
LAYER via1
|
||||
TYPE CUT ;
|
||||
END via1
|
||||
|
||||
LAYER metal2
|
||||
TYPE ROUTING ;
|
||||
DIRECTION VERTICAL ;
|
||||
END metal2
|
||||
|
||||
LAYER via2
|
||||
TYPE CUT ;
|
||||
END via2
|
||||
|
||||
LAYER metal3
|
||||
TYPE ROUTING ;
|
||||
DIRECTION HORIZONTAL ;
|
||||
END metal3
|
||||
|
||||
LAYER via3
|
||||
TYPE CUT ;
|
||||
END via3
|
||||
|
||||
LAYER metal4
|
||||
TYPE ROUTING ;
|
||||
DIRECTION VERTICAL ;
|
||||
END metal4
|
||||
|
||||
LAYER via4
|
||||
TYPE CUT ;
|
||||
END via4
|
||||
|
||||
LAYER metal5
|
||||
TYPE ROUTING ;
|
||||
DIRECTION HORIZONTAL ;
|
||||
END metal5
|
||||
|
||||
|
||||
END LIBRARY
|
||||
Binary file not shown.
|
|
@ -0,0 +1,29 @@
|
|||
|
||||
VERSION 5.6 ;
|
||||
NAMESCASESENSITIVE ON ;
|
||||
DIVIDERCHAR "/" ;
|
||||
BUSBITCHARS "<>" ;
|
||||
DESIGN SMALL ;
|
||||
UNITS DISTANCE MICRONS 100 ;
|
||||
|
||||
DIEAREA ( -30 -30 ) ( 1030 1030 ) ;
|
||||
|
||||
VIAS 1 ;
|
||||
- via1_960x340
|
||||
+ VIARULE Via1Array-0
|
||||
+ CUTSIZE 140 140
|
||||
+ LAYERS metal1 via1 metal2
|
||||
+ CUTSPACING 160 160
|
||||
+ ENCLOSURE 110 100 110 100
|
||||
+ ROWCOL 1 3
|
||||
;
|
||||
END VIAS
|
||||
|
||||
SPECIALNETS 1 ;
|
||||
- VDD ( * VDD )
|
||||
+ ROUTED metal1 0 + SHAPE STRIPE ( 500 500 ) via1_960x340
|
||||
+ USE POWER ;
|
||||
END SPECIALNETS
|
||||
|
||||
END DESIGN
|
||||
|
||||
|
|
@ -0,0 +1,118 @@
|
|||
# encoding: UTF-8
|
||||
|
||||
# KLayout Layout Viewer
|
||||
# Copyright (C) 2006-2026 Matthias Koefferlein
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
if !$:.member?(File::dirname($0))
|
||||
$:.push(File::dirname($0))
|
||||
end
|
||||
|
||||
load("test_prologue.rb")
|
||||
|
||||
class LAYNetlistBrowser_TestClass < TestBase
|
||||
|
||||
# Basic view creation and MainWindow events
|
||||
def test_1
|
||||
|
||||
if !RBA.constants.member?(:Application)
|
||||
return
|
||||
end
|
||||
|
||||
app = RBA::Application.instance
|
||||
mw = app.main_window
|
||||
mw.close_all
|
||||
|
||||
cv = mw.load_layout(ENV["TESTSRC"] + "/testdata/lvs/ringo_mixed_hierarchy.gds", 0)
|
||||
lv = cv.view
|
||||
|
||||
nb = lv.netlist_browser
|
||||
|
||||
db = lv.lvsdb(lv.create_lvsdb("DB1"))
|
||||
db.read(ENV["TESTSRC"] + "/testdata/lvs/ringo_mixed_hierarchy.lvsdb")
|
||||
|
||||
lv.show_lvsdb(0, 0)
|
||||
|
||||
# Test path selections
|
||||
|
||||
nl = nb.db.netlist
|
||||
|
||||
# net
|
||||
n = nl.circuit_by_name("INVX1").net_by_name("OUT")
|
||||
pth = RBA::NetlistObjectsPath.from_first(n)
|
||||
nb.current_path = pth
|
||||
assert_equal(nb.current_path.first.net.to_s, "INVX1:OUT")
|
||||
assert_equal(nb.current_path.second.net.to_s, "INVX1:OUT")
|
||||
|
||||
# device
|
||||
n = nl.circuit_by_name("INVX1").device_by_id(1)
|
||||
pth = RBA::NetlistObjectsPath.from_first(n)
|
||||
nb.current_path = pth
|
||||
assert_equal(nb.current_path.first.device.expanded_name, "$1")
|
||||
assert_equal(nb.current_path.second.device.expanded_name, "$1")
|
||||
|
||||
# subcircuit
|
||||
n = nl.circuit_by_name("RINGO").subcircuit_by_id(2)
|
||||
pth = RBA::NetlistObjectsPath.from_first(n)
|
||||
nb.current_path = pth
|
||||
assert_equal(nb.current_path.first.path[-1].expanded_name, "$2")
|
||||
assert_equal(nb.current_path.second.path[-1].expanded_name, "$11")
|
||||
|
||||
# circuit
|
||||
n = nl.circuit_by_name("INVX1")
|
||||
pth = RBA::NetlistObjectsPath.from_first(n)
|
||||
nb.current_path = pth
|
||||
assert_equal(nb.current_path.first.root.name, "INVX1")
|
||||
assert_equal(nb.current_path.second.root.name, "INVX1")
|
||||
|
||||
nl = nb.db.reference
|
||||
|
||||
# net:
|
||||
n = nl.circuit_by_name("INVX1").net_by_name("OUT")
|
||||
pth = RBA::NetlistObjectsPath.from_second(n)
|
||||
nb.current_path = pth
|
||||
assert_equal(nb.current_path.first.net.to_s, "INVX1:OUT")
|
||||
assert_equal(nb.current_path.second.net.to_s, "INVX1:OUT")
|
||||
|
||||
# device
|
||||
n = nl.circuit_by_name("INVX1").device_by_name("$2")
|
||||
pth = RBA::NetlistObjectsPath.from_second(n)
|
||||
nb.current_path = pth
|
||||
assert_equal(nb.current_path.first.device.expanded_name, "$2")
|
||||
assert_equal(nb.current_path.second.device.expanded_name, "$2")
|
||||
|
||||
# subcircuit
|
||||
n = nl.circuit_by_name("RINGO").subcircuit_by_name("$3")
|
||||
pth = RBA::NetlistObjectsPath.from_second(n)
|
||||
nb.current_path = pth
|
||||
assert_equal(nb.current_path.first.path[-1].expanded_name, "$4")
|
||||
assert_equal(nb.current_path.second.path[-1].expanded_name, "$3")
|
||||
|
||||
# circuit
|
||||
n = nl.circuit_by_name("INVX1")
|
||||
pth = RBA::NetlistObjectsPath.from_second(n)
|
||||
nb.current_path = pth
|
||||
assert_equal(nb.current_path.first.root.name, "INVX1")
|
||||
assert_equal(nb.current_path.second.root.name, "INVX1")
|
||||
|
||||
mw.close_all
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
load("test_epilogue.rb")
|
||||
|
||||
Loading…
Reference in New Issue