Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions src/buddies/src/bd/bdWriterOptions.cc
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ GenericWriterOptions::init_from_options (const db::SaveLayoutOptions &save_optio
m_gds2_write_file_properties = save_options.get_option_by_name ("gds2_write_file_properties").to_bool ();
tl::Variant def_text_size = save_options.get_option_by_name ("gds2_default_text_size");
m_gds2_default_text_size = def_text_size.is_nil () ? -1.0 : def_text_size.to_double ();
m_gds2_extended_features = save_options.get_option_by_name ("gds2_extended_features").to_bool ();

m_oasis_compression_level = save_options.get_option_by_name ("oasis_compression_level").to_int ();
m_oasis_write_cblocks = save_options.get_option_by_name ("oasis_write_cblocks").to_bool ();
Expand Down Expand Up @@ -98,6 +99,20 @@ const std::string GenericWriterOptions::dxf_format_name = "DXF";
const std::string GenericWriterOptions::cif_format_name = "CIF";
const std::string GenericWriterOptions::mag_format_name = "MAG";

std::vector<std::string>
GenericWriterOptions::all_format_names ()
{
std::vector<std::string> names;
names.push_back (gds2_format_name);
names.push_back (gds2text_format_name);
names.push_back (oasis_format_name);
names.push_back (lstream_format_name);
names.push_back (dxf_format_name);
names.push_back (cif_format_name);
names.push_back (mag_format_name);
return names;
}

void
GenericWriterOptions::add_options (tl::CommandLineOptions &cmd, const std::string &format)
{
Expand All @@ -109,6 +124,15 @@ GenericWriterOptions::add_options (tl::CommandLineOptions &cmd, const std::strin
"given factor."
);

if (format.empty ()) {
cmd << tl::arg (group +
"-of|--format=format", &m_format, "Specifies the output format",
"By default, the output format is derived from the file name suffix. "
"You can also specify the format directly using this option. Allowed format names are: "
+ tl::join (all_format_names (), ", ")
);
}

if (format.empty () || format == gds2_format_name || format == gds2text_format_name || format == oasis_format_name) {
cmd << tl::arg (group +
"-od|--dbu-out=dbu", &m_dbu, "Uses the specified database unit",
Expand Down Expand Up @@ -222,6 +246,14 @@ GenericWriterOptions::add_options (tl::CommandLineOptions &cmd, const std::strin
"This option enables a GDS2 extension that allows writing of file properties to GDS2 files. "
"Consumers that don't support this feature, may not be able to read such a GDS2 files."
)
<< tl::arg (group +
"!#--no-extended-features", &m_gds2_extended_features, "Disables extended GDS2 features",
"This option disables extended GDS2 features. Extended GDS features allow writing file and cell level "
"properties without 'write-cell-properties' or 'write-file-properties', store layer names and allow "
"string names for properties and complex property values such as very long strings or lists.\n"
"\n"
"Extended features rely on the context, so they are not available with 'no-context-info'."
)
<< tl::arg (group +
"#--default-text-size", &m_gds2_default_text_size, "Default text size",
"This text size (given in micrometers) is applied to text objects not coming with their "
Expand Down Expand Up @@ -426,6 +458,22 @@ GenericWriterOptions::configure (db::SaveLayoutOptions &save_options, const db::
save_options.set_keep_instances (m_keep_instances);
save_options.set_write_context_info (m_write_context_info);

if (! m_format.empty ()) {

// check, if the format name is a valid one
std::vector<std::string> af = all_format_names ();
auto i = af.begin ();
while (i != af.end () && *i != m_format) {
++i;
}
if (i == af.end ()) {
throw tl::Exception (tl::sprintf (tl::to_string (tr ("Invalid fornat name %s. Allowed names are: %s")), m_format, tl::join (af, ", ")));
}

save_options.set_format (m_format);

}

save_options.set_option_by_name ("gds2_max_vertex_count", m_gds2_max_vertex_count);
save_options.set_option_by_name ("gds2_no_zero_length_paths", m_gds2_no_zero_length_paths);
save_options.set_option_by_name ("gds2_multi_xy_records", m_gds2_multi_xy_records);
Expand All @@ -435,6 +483,7 @@ GenericWriterOptions::configure (db::SaveLayoutOptions &save_options, const db::
save_options.set_option_by_name ("gds2_write_timestamps", m_gds2_write_timestamps);
save_options.set_option_by_name ("gds2_write_cell_properties", m_gds2_write_cell_properties);
save_options.set_option_by_name ("gds2_write_file_properties", m_gds2_write_file_properties);
save_options.set_option_by_name ("gds2_extended_features", m_gds2_extended_features);
save_options.set_option_by_name ("gds2_default_text_size", m_gds2_default_text_size < 0.0 ? tl::Variant () : tl::Variant (m_gds2_default_text_size));

save_options.set_option_by_name ("oasis_compression_level", m_oasis_compression_level);
Expand Down
8 changes: 8 additions & 0 deletions src/buddies/src/bd/bdWriterOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "bdCommon.h"

#include <string>
#include <vector>

namespace tl
{
Expand Down Expand Up @@ -60,6 +61,11 @@ class BD_PUBLIC GenericWriterOptions
*/
GenericWriterOptions (const db::SaveLayoutOptions &options);

/**
* @brief Gets a list with all format names available
*/
static std::vector<std::string> all_format_names ();

/**
* @brief Adds the generic options to the command line parser object
* The format string gives a hint about the target format. Certain options will be
Expand Down Expand Up @@ -114,6 +120,7 @@ class BD_PUBLIC GenericWriterOptions
static const std::string mag_format_name;

private:
std::string m_format;
double m_scale_factor;
double m_dbu;
bool m_dont_write_empty_cells;
Expand All @@ -132,6 +139,7 @@ class BD_PUBLIC GenericWriterOptions
bool m_gds2_write_cell_properties;
bool m_gds2_write_file_properties;
double m_gds2_default_text_size;
bool m_gds2_extended_features;

int m_oasis_compression_level;
bool m_oasis_write_cblocks;
Expand Down
68 changes: 66 additions & 2 deletions src/db/db/dbHierNetworkProcessor.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1686,6 +1686,69 @@ connected_clusters<T>::join_cluster_with (typename local_cluster<T>::id_type id,
}
}

template <class T>
void
connected_clusters<T>::join_clusters_with (typename local_cluster<T>::id_type id, typename std::set<typename local_cluster<T>::id_type>::const_iterator with_from, typename std::set<typename local_cluster<T>::id_type>::const_iterator with_to)
{
if (with_from != with_to && *with_from == id) {
++with_from;
}
if (with_from == with_to) {
return;
}

connections_type &target = m_connections [id];
std::set<connections_type::value_type> target_set;
bool target_set_valid = false;

for (auto w = with_from; w != with_to; ++w) {

local_clusters<T>::join_cluster_with (id, *w);

// handle the connections by translating

typename std::map<typename local_cluster<T>::id_type, connections_type>::iterator tc = m_connections.find (*w);
if (tc != m_connections.end ()) {

connections_type &to_join = tc->second;

for (connections_type::const_iterator c = to_join.begin (); c != to_join.end (); ++c) {
m_rev_connections [*c] = id;
}

if (target.empty ()) {

target.swap (to_join);

} else if (! to_join.empty ()) {

// Join while removing duplicates
if (! target_set_valid) {
target_set.insert (target.begin (), target.end ());
target_set_valid = true;
}

for (auto j = to_join.begin (); j != to_join.end (); ++j) {
if (target_set.find (*j) == target_set.end ()) {
target.push_back (*j);
target_set.insert (*j);
}
}

}

m_connections.erase (tc);

}

if (m_connected_clusters.find (*w) != m_connected_clusters.end ()) {
m_connected_clusters.insert (id);
m_connected_clusters.erase (*w);
}

}
}

template <class T>
typename local_cluster<T>::id_type
connected_clusters<T>::find_cluster_with_connection (const ClusterInstance &inst) const
Expand Down Expand Up @@ -1995,8 +2058,9 @@ struct hc_receiver

typename std::set<id_type>::const_iterator c = sc->begin ();
typename std::set<id_type>::const_iterator cc = c;
for (++cc; cc != sc->end (); ++cc) {
mp_cell_clusters->join_cluster_with (*c, *cc);
++cc;
if (cc != sc->end ()) {
mp_cell_clusters->join_clusters_with (*c, cc, sc->end ());
}

}
Expand Down
7 changes: 7 additions & 0 deletions src/db/db/dbHierNetworkProcessor.h
Original file line number Diff line number Diff line change
Expand Up @@ -1274,6 +1274,13 @@ class DB_PUBLIC_TEMPLATE connected_clusters
*/
void join_cluster_with (typename local_cluster<T>::id_type id, typename local_cluster<T>::id_type with_id);

/**
* @brief Joins a cluster id with the a set of clusters given by an iterator interval with_to .. with_from
*
* This function is equivalent to calling "join_cluster_with" multiple times, but more efficient.
*/
void join_clusters_with (typename local_cluster<T>::id_type id, typename std::set<typename local_cluster<T>::id_type>::const_iterator with_from, typename std::set<typename local_cluster<T>::id_type>::const_iterator with_to);

/**
* @brief An iterator delivering all clusters (even the connectors)
*
Expand Down
13 changes: 11 additions & 2 deletions src/db/db/dbPropertiesRepository.cc
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "tlString.h"
#include "tlAssert.h"
#include "tlHash.h"
#include "tlStaticObjects.h"

namespace db
{
Expand Down Expand Up @@ -348,13 +349,21 @@ PropertiesSet::hash () const
// ----------------------------------------------------------------------------------
// PropertiesRepository implementation

static PropertiesRepository s_instance;
static PropertiesRepository *sp_global_instance = 0;
static PropertiesRepository *sp_temp_instance = 0;

PropertiesRepository &
PropertiesRepository::instance ()
{
return sp_temp_instance ? *sp_temp_instance : s_instance;
if (sp_temp_instance) {
return *sp_temp_instance;
} else {
if (! sp_global_instance) {
sp_global_instance = new PropertiesRepository ();
tl::StaticObjects::reg (&sp_global_instance);
}
return *sp_global_instance;
}
}

void
Expand Down
24 changes: 24 additions & 0 deletions src/db/db/dbReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,30 @@ class DB_PUBLIC ReaderUnknownFormatException
DB_PUBLIC void
join_layer_names (std::string &s, const std::string &n);

/**
* @brief A helper class to join two datatype layer name map members
*/
struct LNameJoinOp1
{
void operator() (std::string &a, const std::string &b)
{
join_layer_names (a, b);
}
};

/**
* @brief A helper class to join two layer map members
* This implementation basically merged the datatype maps.
*/
struct LNameJoinOp2
{
void operator() (tl::interval_map<db::ld_type, std::string> &a, const tl::interval_map<db::ld_type, std::string> &b)
{
LNameJoinOp1 op1;
a.add (b.begin (), b.end (), op1);
}
};

/**
* @brief The generic reader base class
*/
Expand Down
40 changes: 34 additions & 6 deletions src/db/db/dbRegionLocalOperations.cc
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,8 @@ check_local_operation_base<TS, TI>::compute_results (db::Layout *layout, db::Cel
bool take_all = edge_check.has_negative_edge_output () || intruders.empty ();

db::Box common_box;
bool subjects_are_fully_covered = false;

if (! take_all) {

db::Vector e (edge_check.distance (), edge_check.distance ());
Expand All @@ -241,14 +243,24 @@ check_local_operation_base<TS, TI>::compute_results (db::Layout *layout, db::Cel
subject_box += db::box_convert<TS> () (**i);
}

if (edge_check.requires_different_layers ()) {
db::Box intruder_box;
common_box = subject_box.enlarged (e);

if (edge_check.requires_different_layers () && ! common_box.empty ()) {

subjects_are_fully_covered = false;

db::Box all_intruders_box;

for (auto i = intruders.begin (); i != intruders.end (); ++i) {
intruder_box += db::box_convert<TI> () (**i);
db::Box intruder_box = db::box_convert<TI> () (**i);
if (! subjects_are_fully_covered && (*i)->is_box () && common_box.inside (intruder_box)) {
subjects_are_fully_covered = true;
}
all_intruders_box += intruder_box.enlarged (e);
}
common_box = subject_box.enlarged (e) & intruder_box.enlarged (e);
} else {
common_box = subject_box.enlarged (e);

common_box &= all_intruders_box;

}

}
Expand Down Expand Up @@ -306,6 +318,22 @@ check_local_operation_base<TS, TI>::compute_results (db::Layout *layout, db::Cel

// empty intruders

} else if (subjects_are_fully_covered) {

// optimization: can use a single box for the intruders

n = 1;

db::Point ul = common_box.upper_left ();
db::Point lr = common_box.lower_right ();

poly_check.enter (db::Edge (common_box.p1 (), ul), n);
poly_check.enter (db::Edge (ul, common_box.p2 ()), n);
poly_check.enter (db::Edge (common_box.p2 (), lr), n);
poly_check.enter (db::Edge (lr, common_box.p1 ()), n);

n += 2;

} else if (! m_other_is_merged && (intruders.size () > 1 || ! (*intruders.begin ())->is_box ())) {

// NOTE: this local merge is not necessarily giving the same results than a global merge before running
Expand Down
16 changes: 16 additions & 0 deletions src/db/unit_tests/dbPropertiesRepositoryTests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -503,3 +503,19 @@ TEST(SameValueDifferentTypes)
EXPECT_EQ (db::property_name (rp.prop_name_id ((int) 5)).to_parsable_string (), "#5");
}
}

TEST(ComplexTypes)
{
// This is also a smoke test: we intentionally register globally as the finalization code
// is critical: without the right destruction order we destroy the class object before the
// variant and trigger an assertion (pure virtual function called)

db::PropertiesSet ps;
ps.insert (tl::Variant (17), db::DBox (0, 0, 1.5, 2.5));

db::properties_id_type pid = db::properties_id (ps);

auto const &ps_out = db::properties (pid);

EXPECT_EQ (ps_out.to_dict_var ().to_string (), "{17=>(0,0;1.5,2.5)}");
}
9 changes: 6 additions & 3 deletions src/drc/drc/built-in-macros/_drc_engine.rb
Original file line number Diff line number Diff line change
Expand Up @@ -942,15 +942,18 @@ def capacitor_with_bulk(name, area_cap, cls = nil)
# Turns profiling on or off (default). In profiling mode, the
# system will collect statistics about rules executed, their execution time
# and memory information. The argument specifies how many operations to
# print at the end of the run. Without an argument, all operations are
# print at the end of the run. Without an argument or when passing "true", all operations are
# printed. Passing "false" for the argument will disable profiling. This is the
# default.

def profile(n = 0)
if !n.is_a?(1.class) && n != nil && n != false
raise("Argument to 'profile' must be either an integer number or nil")
if !n.is_a?(1.class) && n != nil && n != false && n != true
raise("Argument to 'profile' must be either an integer number, true, false or nil")
end
@profile = !!n
if n == true
n = 0
end
@profile_n = [n || 0, 0].max
end

Expand Down
Loading
Loading