Merge branch 'master' into wip

This commit is contained in:
Matthias Koefferlein 2023-02-19 20:30:49 +01:00
commit 432b542f3c
24 changed files with 564 additions and 162 deletions

View File

@ -2143,6 +2143,10 @@ ms_extraction (db::EdgeProcessor &ep, bool resolve_holes)
static db::Polygon
do_minkowski_sum (const db::Polygon &a, const db::Edge &b, bool resolve_holes)
{
if (a.begin_hull () == a.end_hull ()) {
return db::Polygon ();
}
db::EdgeProcessor ep;
db::ms_production (a, b.p1 (), b.p2 (), ep);
return db::ms_extraction (ep, resolve_holes);
@ -2161,7 +2165,9 @@ minkowski_sum (const db::Polygon &a, const db::Edge &b, bool rh)
static db::Polygon
do_minkowski_sum (const db::Polygon &a, const db::Polygon &b, bool resolve_holes)
{
tl_assert (a.begin_hull () != a.end_hull ());
if (a.begin_hull () == a.end_hull () || b.begin_hull () == b.end_hull ()) {
return db::Polygon ();
}
db::Vector p0 = *a.begin_hull () - db::Point ();

View File

@ -1189,6 +1189,16 @@ Class<lay::LayerPropertiesNode> decl_LayerPropertiesNode (
"Unlike the name suggests, this node will still contain a hierarchy of nodes below if the original "
"node did so."
) +
method ("is_expanded?", &lay::LayerPropertiesNode::expanded,
"@brief Gets a value indicating whether the layer tree node is expanded.\n"
"This predicate has been introduced in version 0.28.6."
) +
method ("expanded=", &lay::LayerPropertiesNode::set_expanded, gsi::arg ("ex"),
"@brief Set a value indicating whether the layer tree node is expanded.\n"
"Setting this value to 'true' will expand (open) the tree node. Setting it to 'false' will collapse the node.\n"
"\n"
"This predicate has been introduced in version 0.28.6."
) +
method_ext ("add_child", &add_child0,
"@brief Add a child entry\n"
"@return A reference to the node created\n"

View File

@ -591,6 +591,12 @@ LayerProperties::need_realize (unsigned int flags, bool /*force*/)
}
}
void
LayerProperties::expanded_state_changed ()
{
// .. no effect ..
}
void
LayerProperties::do_realize (const LayoutViewBase *view) const
{
@ -651,7 +657,7 @@ static unsigned int s_unique_id = 0;
LayerPropertiesNode::LayerPropertiesNode ()
: LayerProperties (),
m_list_index (0)
m_list_index (0), m_expanded (false)
{
m_id = ++s_unique_id;
}
@ -663,7 +669,7 @@ LayerPropertiesNode::~LayerPropertiesNode ()
LayerPropertiesNode::LayerPropertiesNode (const LayerProperties &d)
: LayerProperties (d),
m_list_index (0)
m_list_index (0), m_expanded (false)
{
m_id = ++s_unique_id;
}
@ -671,6 +677,7 @@ LayerPropertiesNode::LayerPropertiesNode (const LayerProperties &d)
LayerPropertiesNode::LayerPropertiesNode (const LayerPropertiesNode &d)
: LayerProperties (d), tl::Object (),
m_list_index (0),
m_expanded (d.m_expanded),
m_children (d.m_children),
m_id (d.m_id)
{
@ -687,6 +694,7 @@ LayerPropertiesNode::operator= (const LayerPropertiesNode &d)
LayerProperties::operator= (d);
m_children = d.m_children;
m_expanded = d.m_expanded;
m_id = d.m_id;
for (iterator c = m_children.begin (); c != m_children.end (); ++c) {
@ -705,7 +713,7 @@ LayerPropertiesNode::operator== (const LayerPropertiesNode &d) const
if (! LayerProperties::operator== (d)) {
return false;
}
return m_children == d.m_children;
return m_children == d.m_children && m_expanded == d.m_expanded;
}
LayoutViewBase *LayerPropertiesNode::view() const
@ -713,6 +721,15 @@ LayoutViewBase *LayerPropertiesNode::view() const
return const_cast<lay::LayoutViewBase *> (mp_view.get ());
}
void
LayerPropertiesNode::set_expanded (bool ex)
{
if (expanded () != ex) {
m_expanded = ex;
expanded_state_changed ();
}
}
unsigned int
LayerPropertiesNode::list_index () const
{
@ -740,6 +757,12 @@ LayerPropertiesNode::realize_source () const
do_realize (mp_view.get ());
}
void
LayerPropertiesNode::expanded_state_changed ()
{
touch ();
}
void
LayerPropertiesNode::need_realize (unsigned int flags, bool force)
{
@ -1763,8 +1786,9 @@ struct LineStyleIndexConverter
static const tl::XMLElementList layer_element = tl::XMLElementList (
// HINT: these make_member calls want to be qualified: otherwise an internal error
// was observed ..
tl::make_member<tl::color_t, LayerPropertiesNode> (&LayerPropertiesNode::frame_color_loc, &LayerPropertiesNode::set_frame_color_code, "frame-color", UIntColorConverter ()) +
tl::make_member<tl::color_t, LayerPropertiesNode> (&LayerPropertiesNode::fill_color_loc, &LayerPropertiesNode::set_fill_color_code, "fill-color", UIntColorConverter ()) +
tl::make_member<bool, LayerPropertiesNode> (&LayerPropertiesNode::expanded, &LayerPropertiesNode::set_expanded, "expanded") +
tl::make_member<tl::color_t, LayerPropertiesNode> (&LayerPropertiesNode::frame_color_loc, &LayerPropertiesNode::set_frame_color_code, "frame-color", UIntColorConverter ()) +
tl::make_member<tl::color_t, LayerPropertiesNode> (&LayerPropertiesNode::fill_color_loc, &LayerPropertiesNode::set_fill_color_code, "fill-color", UIntColorConverter ()) +
tl::make_member<int, LayerPropertiesNode> (&LayerPropertiesNode::frame_brightness_loc, &LayerPropertiesNode::set_frame_brightness, "frame-brightness") +
tl::make_member<int, LayerPropertiesNode> (&LayerPropertiesNode::fill_brightness_loc, &LayerPropertiesNode::set_fill_brightness, "fill-brightness") +
tl::make_member<int, LayerPropertiesNode> (&LayerPropertiesNode::dither_pattern_loc, &LayerPropertiesNode::set_dither_pattern, "dither-pattern", DitherPatternIndexConverter ()) +
@ -2061,6 +2085,16 @@ LayerPropertiesNodeRef::need_realize (unsigned int flags, bool force)
}
}
void
LayerPropertiesNodeRef::expanded_state_changed ()
{
LayerPropertiesNode::expanded_state_changed ();
if (is_valid ()) {
view ()->set_layer_node_expanded (m_iter, expanded ());
}
}
void
LayerPropertiesNodeRef::refresh () const
{

View File

@ -919,6 +919,11 @@ protected:
*/
virtual void need_realize (unsigned int flags, bool force = false);
/**
* @brief indicates a change of the collapsed/expanded state
*/
virtual void expanded_state_changed ();
/**
* @brief Fetches the current status from the original properties for the LayerPropertiesNodeRef implementation
*/
@ -1069,6 +1074,20 @@ public:
return r;
}
/**
* @brief Sets the expanded state of the layer properties tree node
*/
void set_expanded (bool ex);
/**
* @brief Gets the expanded state of the layer properties node
*/
bool expanded () const
{
refresh ();
return m_expanded;
}
/**
* @brief Child layers: begin iterator
*/
@ -1207,14 +1226,21 @@ public:
virtual void realize_source () const;
virtual void realize_visual () const;
void set_expanded_silent (bool ex)
{
m_expanded = ex;
}
protected:
virtual void need_realize (unsigned int flags, bool force);
virtual void expanded_state_changed ();
void set_parent (const LayerPropertiesNode *);
private:
// A reference to the view
tl::weak_ptr<lay::LayoutViewBase> mp_view;
unsigned int m_list_index;
bool m_expanded;
// the parent node
tl::weak_ptr<LayerPropertiesNode> mp_parent;
// the list of children
@ -2009,8 +2035,9 @@ private:
tl::weak_ptr<LayerPropertiesNode> mp_node;
size_t m_synched_gen_id;
void need_realize (unsigned int flags, bool force);
void refresh () const;
virtual void need_realize (unsigned int flags, bool force);
virtual void expanded_state_changed ();
virtual void refresh () const;
};
}

View File

@ -1880,6 +1880,21 @@ LayoutViewBase::replace_layer_node (unsigned int index, const LayerPropertiesCon
}
}
void
LayoutViewBase::set_layer_node_expanded (unsigned int index, const LayerPropertiesConstIterator &iter, bool ex)
{
if (ex != iter->expanded ()) {
LayerPropertiesIterator non_const_iter (get_properties (index), iter.uint ());
non_const_iter->set_expanded (ex);
if (index == current_layer_list ()) {
layer_list_changed_event (8 /*expanded state needs update*/);
}
}
}
void
LayoutViewBase::set_properties (unsigned int index, const LayerPropertiesConstIterator &iter, const LayerProperties &props)
{

View File

@ -335,6 +335,17 @@ public:
set_properties (current_layer_list (), iter, props);
}
/**
* @brief Sets a value indicating whether the given node is expanded in the layer tree
*
* @param iter Points to the layer node to be modified
* @param ex True if the layer node shall be expanded, false if it shall be collapsed
*/
void set_layer_node_expanded (const LayerPropertiesConstIterator &iter, bool ex)
{
set_layer_node_expanded (current_layer_list (), iter, ex);
}
/**
* @brief Set the layer properties of a layer with the given position (by iterator) for the layer list with the given index
*
@ -344,6 +355,15 @@ public:
*/
void set_properties (unsigned int index, const LayerPropertiesConstIterator &iter, const LayerProperties &props);
/**
* @brief Sets a value indicating whether the given node is expanded in the layer tree
*
* @param index The layer list's index
* @param iter Points to the layer node to be modified
* @param ex True if the layer node shall be expanded, false if it shall be collapsed
*/
void set_layer_node_expanded (unsigned int index, const LayerPropertiesConstIterator &iter, bool ex);
/**
* @brief Expand the layer properties of all tabs
*

View File

@ -135,6 +135,7 @@ TEST (1)
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
"<layer-properties>\n"
" <properties>\n"
" <expanded>false</expanded>\n"
" <frame-color/>\n"
" <fill-color/>\n"
" <frame-brightness>0</frame-brightness>\n"

View File

@ -205,6 +205,7 @@ LayerControlPanel::LayerControlPanel (lay::LayoutViewBase *view, db::Manager *ma
db::Object (manager),
mp_view (view),
m_needs_update (true),
m_expanded_state_needs_update (false),
m_tabs_need_update (true),
m_hidden_flags_need_update (true),
m_in_update (false),
@ -1696,6 +1697,7 @@ LayerControlPanel::cancel_updates ()
{
m_in_update = false;
m_needs_update = false;
m_expanded_state_needs_update = false;
m_hidden_flags_need_update = false;
m_tabs_need_update = false;
}
@ -1874,11 +1876,13 @@ LayerControlPanel::do_update_content ()
}
if (m_hidden_flags_need_update) {
do_update_hidden_flags ();
m_hidden_flags_need_update = false;
}
if (m_expanded_state_needs_update) {
restore_expanded ();
m_expanded_state_needs_update = false;
}
}
@ -1993,6 +1997,11 @@ LayerControlPanel::signal_li_changed (int)
void
LayerControlPanel::update_required (int f)
{
// the name of a layer list has changed
if ((f & 8) != 0) {
m_expanded_state_needs_update = true;
}
// the name of a layer list has changed
if ((f & 4) != 0) {
m_tabs_need_update = true;
@ -2032,18 +2041,18 @@ LayerControlPanel::current_index_changed (const QModelIndex &index)
void
LayerControlPanel::group_collapsed (const QModelIndex &index)
{
lay::LayerPropertiesConstIterator iter = mp_model->iterator (index);
auto iter = mp_model->iterator_nc (index);
if (! iter.is_null () && ! iter.at_end ()) {
m_expanded.erase (iter->id ());
iter->set_expanded_silent (false);
}
}
void
LayerControlPanel::group_expanded (const QModelIndex &index)
{
lay::LayerPropertiesConstIterator iter = mp_model->iterator (index);
auto iter = mp_model->iterator_nc (index);
if (! iter.is_null () && ! iter.at_end ()) {
m_expanded.insert (iter->id ());
iter->set_expanded_silent (true);
}
}
@ -2052,33 +2061,16 @@ LayerControlPanel::restore_expanded ()
{
mp_layer_list->blockSignals (true);
#if 1
// By keeping m_expanded, we can preserve the expansion state of different tabs.
// However we will always continue filling m_expanded.
lay::LayerPropertiesConstIterator l = mp_view->begin_layers ();
while (! l.at_end ()) {
if (m_expanded.find (l->id ()) != m_expanded.end ()) {
QModelIndex index = mp_model->index (l, 0);
QModelIndex index = mp_model->index (l, 0);
if (l->expanded ()) {
mp_layer_list->expand (index);
} else {
mp_layer_list->collapse (index);
}
++l;
}
#else
// this solution will forget the other tab's expansion flags.
std::set<unsigned int> new_expanded;
lay::LayerPropertiesConstIterator l = mp_view->begin_layers ();
while (! l.at_end ()) {
if (m_expanded.find (l->id ()) != m_expanded.end ()) {
new_expanded.insert (l->id ());
QModelIndex index = mp_model->index (l, 0);
mp_layer_list->expand (index);
}
++l;
}
m_expanded.swap (new_expanded);
#endif
mp_layer_list->blockSignals (false);
}
@ -2287,7 +2279,7 @@ public:
menu_entries.push_back (lay::menu_item ("cm_lv_select_all", "select_all", at, tl::to_string (QObject::tr ("Select All"))));
// It is not sure, whether "expandAll" destabilizes the tree widget:
// menu_entries.push_back (lay::menu_item ("cm_lv_expand_all", "expand_all", at, tl::to_string (QObject::tr ("Expand All")));
// menu_entries.push_back (lay::menu_item ("cm_lv_expand_all", "expand_all", at, tl::to_string (QObject::tr ("Expand All"))));
menu_entries.push_back (lay::separator ("tab_group", at));
menu_entries.push_back (lay::submenu ("tab_menu", at, tl::to_string (QObject::tr ("Tabs"))));

View File

@ -352,6 +352,7 @@ private:
LayerTreeModel *mp_model;
lay::LayoutViewBase *mp_view;
bool m_needs_update;
bool m_expanded_state_needs_update;
bool m_tabs_need_update;
bool m_hidden_flags_need_update;
bool m_in_update;
@ -360,7 +361,6 @@ private:
int m_oversampling;
bool m_hrm;
tl::DeferredMethod<LayerControlPanel> m_do_update_content_dm;
std::set<unsigned int> m_expanded;
bool m_no_stipples;
QLabel *m_no_stipples_label;
lay::DecoratedLineEdit *mp_search_edit_box;

View File

@ -756,7 +756,20 @@ LayerTreeModel::iterator (const QModelIndex &index) const
return lay::LayerPropertiesConstIterator ();
}
QModelIndex
lay::LayerPropertiesIterator
LayerTreeModel::iterator_nc (const QModelIndex &index)
{
if (index.isValid ()) {
size_t iter_index = size_t (index.internalPointer ());
if (mp_view->layer_lists () > 0 && iter_index >= m_id_start && iter_index < m_id_end) {
return lay::LayerPropertiesIterator (mp_view->get_properties (), iter_index - m_id_start);
}
}
return lay::LayerPropertiesIterator ();
}
QModelIndex
LayerTreeModel::index (lay::LayerPropertiesConstIterator iter, int column) const
{
try {

View File

@ -51,6 +51,7 @@ namespace lay
class LayoutViewBase;
class LayerPropertiesConstIterator;
class LayerPropertiesIterator;
/**
* @brief A helper class implementing a cache for the "test shapes in view" feature
@ -107,6 +108,16 @@ public:
virtual QModelIndex index (int row, int column, const QModelIndex &parent) const;
virtual QModelIndex parent (const QModelIndex &index) const;
/**
* @brief Sets the expanded state for a given model index
*/
void set_expanded (const QModelIndex &index, bool ex);
/**
* @brief Gets the expanded state for a given model index
*/
bool expanded (const QModelIndex &index) const;
/**
* @brief Provides an icon for a given layer style
*/
@ -127,6 +138,11 @@ public:
*/
lay::LayerPropertiesConstIterator iterator (const QModelIndex &index) const;
/**
* @brief Converts a QModelIndex to an iterator (non-const)
*/
lay::LayerPropertiesIterator iterator_nc (const QModelIndex &index);
/**
* @brief Gets a flag indicating that an entry is hidden
*/

View File

@ -782,7 +782,7 @@ DEFImporter::read_nets (db::Layout &layout, db::Cell &design, double scale, bool
}
}
while (test ("+")) {
while ((in_subnet && ! at_end ()) || test ("+")) {
bool was_shield = false;
unsigned int mask = 0;
@ -820,6 +820,8 @@ DEFImporter::read_nets (db::Layout &layout, db::Cell &design, double scale, bool
} else {
bool any = false;
bool prefixed = false;
bool can_have_rect_polygon_or_via = true;
@ -831,8 +833,6 @@ DEFImporter::read_nets (db::Layout &layout, db::Cell &design, double scale, bool
can_have_rect_polygon_or_via = test ("+");
}
bool any = false;
if (can_have_rect_polygon_or_via) {
if (test ("SHAPE")) {
take ();
@ -882,22 +882,29 @@ DEFImporter::read_nets (db::Layout &layout, db::Cell &design, double scale, bool
} else if (can_have_rect_polygon_or_via && test ("VIA")) {
// For the via, the masks are encoded in a three-digit number (<mask-top> <mask-cut> <mask_bottom>)
unsigned int mask_top = (mask / 100) % 10;
unsigned int mask_cut = (mask / 10) % 10;
unsigned int mask_bottom = mask % 10;
std::string vn = get ();
db::FTrans ft = get_orient (true /*optional*/);
test ("(");
db::Vector pt = get_vector (scale);
test (")");
while (test ("(")) {
std::map<std::string, ViaDesc>::const_iterator vd = m_via_desc.find (vn);
if (vd != m_via_desc.end ()) {
// TODO: no mask specification here?
db::Cell *cell = reader_state ()->via_cell (vn, nondefaultrule, layout, 0, 0, 0, &m_lef_importer);
if (cell) {
design.insert (db::CellInstArray (db::CellInst (cell->cell_index ()), db::Trans (ft.rot (), pt)));
db::Vector pt = get_vector (scale);
test (")");
std::map<std::string, ViaDesc>::const_iterator vd = m_via_desc.find (vn);
if (vd != m_via_desc.end ()) {
db::Cell *cell = reader_state ()->via_cell (vn, nondefaultrule, layout, mask_bottom, mask_cut, mask_top, &m_lef_importer);
if (cell) {
design.insert (db::CellInstArray (db::CellInst (cell->cell_index ()), db::Trans (ft.rot (), pt)));
}
} else {
warn (tl::to_string (tr ("Invalid via name: ")) + vn);
}
} else {
error (tl::to_string (tr ("Invalid via name: ")) + vn);
}
any = true;
@ -1120,9 +1127,9 @@ DEFImporter::read_vias (db::Layout &layout, db::Cell & /*design*/, double scale)
if (vd.m1.empty () && vd.m2.empty ()) {
// analyze the layers to find the metals
if (routing_layers.size () == 2) {
vd.m1 = routing_layers[0];
vd.m2 = routing_layers[1];
if (routing_layers.size () == 2 || routing_layers.size () == 1) {
vd.m1 = routing_layers.front ();
vd.m2 = routing_layers.back ();
} else {
warn (tl::to_string (tr ("Cannot determine routing layers for via: ")) + n);
}
@ -1204,7 +1211,7 @@ DEFImporter::read_pins (db::Layout &layout, db::Cell &design, double scale)
double x = 0.0, y = 0.0;
while (! at_end () && ! test ("+") && ! test (";")) {
while (! at_end () && ! peek ("+") && ! peek (";")) {
test ("(");
if (! test ("*")) {
@ -1237,8 +1244,36 @@ DEFImporter::read_pins (db::Layout &layout, db::Cell &design, double scale)
} else if (test ("VIA")) {
// TODO: implement
error (tl::to_string (tr ("VIA not supported on pins currently")));
// TODO: clarify - VIA on pins is regarded VIA purpose, not PIN and gives a separate cell
std::string vn = get ();
unsigned int mask = 0;
if (test ("MASK")) {
mask = get_mask (get_long ());
}
while (test ("(")) {
db::Vector pt = get_vector (scale);
test (")");
unsigned int mask_top = (mask / 100) % 10;
unsigned int mask_cut = (mask / 10) % 10;
unsigned int mask_bottom = mask % 10;
std::map<std::string, ViaDesc>::const_iterator vd = m_via_desc.find (vn);
if (vd != m_via_desc.end ()) {
std::string nondefaultrule;
db::Cell *cell = reader_state ()->via_cell (vn, nondefaultrule, layout, mask_bottom, mask_cut, mask_top, &m_lef_importer);
if (cell) {
design.insert (db::CellInstArray (db::CellInst (cell->cell_index ()), db::Trans (pt)));
}
} else {
warn (tl::to_string (tr ("Invalid via name: ")) + vn);
}
}
} else {
while (! peek ("+") && ! peek ("-") && ! peek (";")) {
@ -1391,13 +1426,49 @@ DEFImporter::read_fills (db::Layout &layout, db::Cell &design, double scale)
} else if (test ("VIA")) {
// TODO: implement
warn (tl::to_string (tr ("VIA not supported on fills currently")));
// TODO: clarify - VIA on fill is regarded VIA purpose, not PIN and gives a separate cell
while (! at_end () && ! test (";")) {
take ();
std::string vn = get ();
unsigned int mask = 0;
while (test ("+")) {
if (test ("MASK")) {
mask = get_mask (get_long ());
} else if (test ("OPC")) {
// ignore
} else {
error (tl::to_string (tr ("Expected 'MASK' or 'OPC' inside fill/VIA definition")));
}
}
if (peek ("+") && test ("MASK")) {
mask = get_mask (get_long ());
}
unsigned int mask_top = (mask / 100) % 10;
unsigned int mask_cut = (mask / 10) % 10;
unsigned int mask_bottom = mask % 10;
while (test ("(")) {
db::Vector pt = get_vector (scale);
test (")");
std::map<std::string, ViaDesc>::const_iterator vd = m_via_desc.find (vn);
if (vd != m_via_desc.end ()) {
std::string nondefaultrule;
db::Cell *cell = reader_state ()->via_cell (vn, nondefaultrule, layout, mask_bottom, mask_cut, mask_top, &m_lef_importer);
if (cell) {
design.insert (db::CellInstArray (db::CellInst (cell->cell_index ()), db::Trans (pt)));
}
} else {
warn (tl::to_string (tr ("Invalid via name: ")) + vn);
}
}
test (";");
} else {
error (tl::to_string (tr ("'LAYER' or 'VIA' keyword expected")));
}
@ -1432,7 +1503,7 @@ DEFImporter::read_styles (double scale)
}
m_styles.insert (std::make_pair (sn, db::Polygon ())).first->second.assign_hull (points.begin (), points.end ());
m_styles.insert (std::make_pair (sn, db::Polygon ())).first->second.assign_hull (points.begin (), points.end (), false /*don't compress*/);
}
}

View File

@ -1990,7 +1990,11 @@ LEFDEFImporter::read (tl::InputStream &stream, db::Layout &layout, LEFDEFReaderS
void
LEFDEFImporter::error (const std::string &msg)
{
throw LEFDEFReaderException (msg, int (mp_stream->line_number ()), m_cellname, m_fn);
if (m_sections.empty ()) {
throw LEFDEFReaderException (msg, int (mp_stream->line_number ()), m_cellname, m_fn);
} else {
throw LEFDEFReaderException (msg + tl::sprintf (tl::to_string (tr (" (inside %s)")), tl::join (m_sections, "/")), int (mp_stream->line_number ()), m_cellname, m_fn);
}
}
void
@ -2140,6 +2144,18 @@ LEFDEFImporter::get ()
return r;
}
void
LEFDEFImporter::enter_section (const std::string &name)
{
m_sections.push_back (name);
}
void
LEFDEFImporter::leave_section ()
{
m_sections.pop_back ();
}
const std::string &
LEFDEFImporter::next ()
{

View File

@ -1706,8 +1706,31 @@ private:
db::property_names_id_type m_pin_prop_name_id;
db::LEFDEFReaderOptions m_options;
int m_warn_level;
std::vector<std::string> m_sections;
friend class LEFDEFSection;
const std::string &next ();
void enter_section (const std::string &name);
void leave_section ();
};
class DB_PLUGIN_PUBLIC LEFDEFSection
{
public:
LEFDEFSection (LEFDEFImporter *importer, const std::string &name)
: mp_importer (importer)
{
mp_importer->enter_section (name);
}
~LEFDEFSection ()
{
mp_importer->leave_section ();
}
private:
LEFDEFImporter *mp_importer;
};
class DB_PLUGIN_PUBLIC LEFDEFReader

View File

@ -388,9 +388,7 @@ LEFImporter::read_geometries (GeometryBasedLayoutGenerator *lg, double dbu, Laye
} else if (test ("PROPERTY")) {
// skip properties
while (! at_end () && ! test (";")) {
take ();
}
skip_entry ();
} else {
// stop at unknown token
@ -406,22 +404,20 @@ LEFImporter::read_nondefaultrule (db::Layout &layout)
// read NONDEFAULTRULE sections
std::string n = get ();
while (! test ("END") || ! test (n)) {
while (! at_end () && ! test ("END")) {
if (test ("LAYER")) {
std::string l = get ();
// read the width for the layer
while (! test ("END")) {
while (! at_end () && ! test ("END")) {
if (test ("WIDTH")) {
double w = get_double ();
test (";");
m_nondefault_widths[n][l] = std::make_pair (w, w);
} else {
while (! at_end () && ! test (";")) {
take ();
}
skip_entry ();
}
}
@ -432,18 +428,31 @@ LEFImporter::read_nondefaultrule (db::Layout &layout)
read_viadef (layout, n);
} else {
while (! at_end () && ! test (";")) {
take ();
std::string token = get ();
if (token == "SPACING") {
// read over sections we do not need
while (! at_end () && ! test ("END")) {
skip_entry ();
}
test (token);
} else if (token != ";") {
// read over lines we do not need
skip_entry ();
}
}
}
test (n);
}
void
LEFImporter::read_viadef_by_rule (RuleBasedViaGenerator *vg, ViaDesc &via_desc, const std::string & /*n*/, double dbu)
{
while (! test ("END")) {
while (! at_end () && ! test ("END")) {
double x, y;
@ -557,6 +566,13 @@ LEFImporter::read_viadef_by_geometry (GeometryBasedLayoutGenerator *lg, ViaDesc
get_double ();
test (";");
} else if (test ("FOREIGN")) {
// undocumented
while (! at_end () && ! test (";")) {
take ();
}
} else if (test ("LAYER")) {
layer_name = get ();
@ -631,9 +647,7 @@ LEFImporter::read_viadef_by_geometry (GeometryBasedLayoutGenerator *lg, ViaDesc
} else if (test ("PROPERTY")) {
// skip properties
while (! at_end () && ! test (";")) {
take ();
}
skip_entry ();
} else {
// stop at unknown token
@ -663,7 +677,7 @@ LEFImporter::read_viadef (Layout &layout, const std::string &nondefaultrule)
ViaDesc &via_desc = m_vias[n];
while (test ("DEFAULT") || test ("TOPOFSTACKONLY"))
while (test ("DEFAULT") || test ("TOPOFSTACKONLY") || test("GENERATED"))
;
test (";");
@ -746,55 +760,51 @@ LEFImporter::read_layer (Layout & /*layout*/)
// blocks following a semicolon
take ();
if (test ("FREQUENCY")) {
while (! test ("TABLEENTRIES")) {
while (! at_end () && ! test ("TABLEENTRIES")) {
take ();
}
}
while (! at_end () && ! test (";")) {
take ();
}
skip_entry ();
} else if (test ("PROPERTY")) {
std::string name = get ();
tl::Variant value = get ();
while (! test (";") && ! at_end ()) {
if (name == "LEF58_MINWIDTH") {
std::string name = get ();
tl::Variant value = get ();
// Cadence extension
tl::Extractor ex (value.to_string ());
double v = 0.0;
if (ex.test ("MINWIDTH") && ex.try_read (v)) {
if (ex.test ("WRONGDIRECTION")) {
wmin_wrongdir = v;
} else {
wmin = v;
if (name == "LEF58_MINWIDTH") {
// Cadence extension
tl::Extractor ex (value.to_string ());
double v = 0.0;
if (ex.test ("MINWIDTH") && ex.try_read (v)) {
if (ex.test ("WRONGDIRECTION")) {
wmin_wrongdir = v;
} else {
wmin = v;
}
}
}
} else if (name == "LEF58_WIDTH") {
} else if (name == "LEF58_WIDTH") {
// Cadence extension
tl::Extractor ex (value.to_string ());
double v = 0.0;
if (ex.test ("WIDTH") && ex.try_read (v)) {
if (ex.test ("WRONGDIRECTION")) {
w_wrongdir = v;
} else {
w = v;
// Cadence extension
tl::Extractor ex (value.to_string ());
double v = 0.0;
if (ex.test ("WIDTH") && ex.try_read (v)) {
if (ex.test ("WRONGDIRECTION")) {
w_wrongdir = v;
} else {
w = v;
}
}
}
}
expect (";");
} else {
while (! at_end () && ! test (";")) {
take ();
}
skip_entry ();
}
}
@ -865,6 +875,8 @@ LEFImporter::read_macro (Layout &layout)
} else if (test ("PIN")) {
LEFDEFSection section (this, "PIN");
std::string pn = get ();
std::string dir;
@ -881,6 +893,8 @@ LEFImporter::read_macro (Layout &layout)
} else if (test ("PORT")) {
LEFDEFSection section (this, "PORT");
// produce pin labels
// TODO: put a label on every single object?
std::string label = pn;
@ -916,9 +930,7 @@ LEFImporter::read_macro (Layout &layout)
expect ("END");
} else {
while (! at_end () && ! test (";")) {
take ();
}
skip_entry ();
}
}
@ -926,12 +938,19 @@ LEFImporter::read_macro (Layout &layout)
} else if (test ("FOREIGN")) {
LEFDEFSection section (this, "FOREIGN");
std::string cn = get ();
db::Point vec;
db::FTrans ft;
if (! peek (";")) {
vec = get_point (1.0 / layout.dbu ());
if (test ("(")) {
vec = get_point (1.0 / layout.dbu ());
expect (")");
} else {
vec = get_point (1.0 / layout.dbu ());
}
ft = get_orient (true);
}
@ -940,7 +959,7 @@ LEFImporter::read_macro (Layout &layout)
if (options ().macro_resolution_mode () != 1) {
if (! foreign_name.empty ()) {
error (tl::to_string (tr ("Duplicate FOREIGN definition")));
warn (tl::to_string (tr ("Duplicate FOREIGN definition")));
}
// What is the definition of the FOREIGN transformation?
@ -956,6 +975,8 @@ LEFImporter::read_macro (Layout &layout)
} else if (test ("OBS")) {
LEFDEFSection section (this, "OBS");
if (reader_state ()->tech_comp ()->produce_obstructions ()) {
read_geometries (mg, layout.dbu (), Obstructions);
} else {
@ -966,8 +987,10 @@ LEFImporter::read_macro (Layout &layout)
} else if (test ("DENSITY")) {
LEFDEFSection section (this, "DENSITY");
// read over DENSITY statements
while (! test ("END")) {
while (! at_end () && ! test ("END")) {
if (test ("LAYER")) {
get ();
expect (";");
@ -980,17 +1003,27 @@ LEFImporter::read_macro (Layout &layout)
}
}
expect ("END");
} else if (test ("FIXEDMASK")) {
mg->set_fixedmask (true);
expect (";");
} else {
while (! at_end () && ! test (";")) {
take ();
std::string token = get ();
LEFDEFSection section (this, token);
if (token == "TIMING") {
// read over sections we do not need
while (! at_end () && ! test ("END")) {
skip_entry ();
}
test (token);
} else if (token != ";") {
// read over lines we do not need
skip_entry ();
}
}
}
@ -1031,17 +1064,16 @@ LEFImporter::do_read (db::Layout &layout)
} else if (test ("UNITS")) {
// read over SPACING sections
while (! test ("END")) {
LEFDEFSection section (this, "UNITS");
while (! at_end () && ! test ("END")) {
if (test ("DATABASE")) {
expect ("MICRONS");
// TODO: what to do with that value
/* dbu_mic = */ get_double ();
expect (";");
} else {
while (! at_end () && ! test (";")) {
take ();
}
skip_entry ();
}
}
@ -1049,66 +1081,138 @@ LEFImporter::do_read (db::Layout &layout)
} else if (test ("SPACING")) {
LEFDEFSection section (this, "SPACING");
// read over SPACING sections
while (! test ("END") || ! test ("SPACING")) {
take ();
while (! at_end () && ! test ("END")) {
skip_entry ();
}
test ("SPACING");
} else if (test ("PROPERTYDEFINITIONS")) {
LEFDEFSection section (this, "PROPERTYDEFINITIONS");
// read over PROPERTYDEFINITIONS sections
while (! test ("END") || ! test ("PROPERTYDEFINITIONS")) {
take ();
while (! at_end () && ! test ("END")) {
skip_entry ();
}
test ("PROPERTYDEFINITIONS");
} else if (test ("NONDEFAULTRULE")) {
LEFDEFSection section (this, "NONDEFAULTRULE");
read_nondefaultrule (layout);
} else if (test ("SITE")) {
// read over SITE sections
LEFDEFSection section (this, "NONDEFAULTRULE");
// read over SITE or VIARULE sections
std::string n = get ();
while (! test ("END") || ! test (n)) {
take ();
while (! at_end () && ! test ("END")) {
skip_entry ();
}
test (n);
} else if (test ("VIARULE")) {
// read over VIARULE sections
LEFDEFSection section (this, "VIARULE");
// read over SITE or VIARULE sections
std::string n = get ();
while (! test ("END") || ! test (n)) {
take ();
while (! at_end () && ! test ("END")) {
skip_entry ();
}
test (n);
} else if (test ("NOISETABLE")) {
LEFDEFSection section (this, "NOISETABLE");
// read over NOISETABLE sections
while (! at_end () && ! test ("END")) {
skip_entry ();
}
test ("NOISETABLE");
} else if (test ("IRDROP")) {
LEFDEFSection section (this, "IRDROP");
// read over IRDROP sections
while (! at_end () && ! test ("END")) {
skip_entry ();
}
test ("IRDROP");
} else if (test ("ARRAY")) {
LEFDEFSection section (this, "ARRAY");
// read over ARRAY sections
std::string n = get ();
while (! at_end () && ! test ("END")) {
if (test ("FLOORPLAN")) {
while (! at_end () && ! test ("END")) {
skip_entry ();
}
} else {
skip_entry ();
}
}
test (n);
} else if (test ("VIA")) {
LEFDEFSection section (this, "VIA");
read_viadef (layout, std::string ());
} else if (test ("BEGINEXT")) {
LEFDEFSection section (this, "BEGINEXT");
// read over BEGINEXT sections
while (! test ("ENDEXT")) {
while (! at_end () && ! test ("ENDEXT")) {
take ();
}
} else if (test ("LAYER")) {
LEFDEFSection section (this, "LAYER");
read_layer (layout);
} else if (test ("MACRO")) {
LEFDEFSection section (this, "MACRO");
read_macro (layout);
} else {
while (! at_end () && ! test (";")) {
take ();
}
// read over entries we do not need
skip_entry ();
}
}
}
void
LEFImporter::skip_entry ()
{
while (! at_end () && ! test (";")) {
take ();
}
}
void
LEFImporter::finish_lef (db::Layout &layout)
{

View File

@ -152,6 +152,7 @@ private:
void read_viadef_by_geometry (GeometryBasedLayoutGenerator *lg, ViaDesc &desc, const std::string &n, double dbu);
void read_layer (Layout &layout);
void read_macro (Layout &layout);
void skip_entry ();
};
}

View File

@ -277,81 +277,88 @@ static void run_test2 (tl::TestBase *_this, const char *lef_dir, const char *fil
}
}
TEST(1)
TEST(lef1)
{
run_test (_this, "lef1", "lef:in.lef", 0, default_options ());
}
TEST(2)
TEST(lef2)
{
// Also tests ability of plugin to properly read LEF
run_test (_this, "lef2", "read:in.lef", "au.oas.gz", default_options ());
}
TEST(3)
TEST(lef3)
{
db::LEFDEFReaderOptions options = default_options ();
options.set_cell_outline_layer ("OUTLINE (2/0)");
run_test (_this, "lef3", "lef:in.lef", "au.oas.gz", options);
}
TEST(4)
TEST(lef4)
{
run_test (_this, "lef4", "lef:in.lef", 0, default_options ());
}
TEST(5)
TEST(lef5)
{
run_test (_this, "lef5", "lef:in.lef", 0, default_options ());
}
TEST(6)
TEST(lef6)
{
run_test (_this, "lef6", "lef:in.lef", 0, default_options ());
}
TEST(7)
TEST(lef7)
{
db::LEFDEFReaderOptions options = default_options ();
options.set_cell_outline_layer ("OUTLINE (8/0)");
run_test (_this, "lef7", "lef:in_tech.lef+lef:in.lef", "au.oas.gz", options);
}
TEST(10)
TEST(lef8)
{
// this is rather a smoke test and throws a number of warnings
// (complete example)
run_test (_this, "lef8", "lef:tech.lef+lef:a.lef", "au.oas.gz", default_options ());
}
TEST(def1)
{
run_test (_this, "def1", "lef:in.lef+def:in.def", "au2.oas.gz", default_options ());
}
TEST(11)
TEST(def2)
{
db::LEFDEFReaderOptions options = default_options ();
options.set_cell_outline_layer ("OUTLINE (10/0)");
run_test (_this, "def2", "lef:0.lef+lef:1.lef+def:in.def.gz", "au.oas.gz", options);
}
TEST(12)
TEST(def3)
{
db::LEFDEFReaderOptions options = default_options ();
options.set_cell_outline_layer ("OUTLINE (13/0)");
run_test (_this, "def3", "lef:in.lef+def:in.def", "au.oas.gz", options);
}
TEST(13)
TEST(def4)
{
run_test (_this, "def4", "lef:in.lef+def:in.def", "au2.oas.gz", default_options ());
}
TEST(14)
TEST(def5)
{
run_test (_this, "def5", "lef:in.lef+def:in.def", "au.oas.gz", default_options ());
}
TEST(15)
TEST(def6)
{
run_test (_this, "def6", "lef:cells.lef+lef:tech.lef+def:in.def.gz", "au-new.oas.gz", default_options ());
}
TEST(16)
TEST(def7)
{
db::LEFDEFReaderOptions options = default_options ();
options.set_placement_blockage_layer ("PLACEMENT_BLK (11/0)");
@ -361,12 +368,12 @@ TEST(16)
run_test (_this, "def7", "map:in.map+lef:cells.lef+lef:tech.lef+def:in.def.gz", "au2_with_map_file-new.oas.gz", options);
}
TEST(17)
TEST(def8)
{
run_test (_this, "def8", "lef:tech.lef+def:in.def", "au.oas.gz", default_options ());
}
TEST(18)
TEST(def9)
{
db::LEFDEFReaderOptions options = default_options ();
options.set_separate_groups (true);
@ -375,47 +382,56 @@ TEST(18)
run_test (_this, "def9", "lef:tech.lef+lef:cells_modified.lef+def:in.def", "au_nogroups-new.oas.gz", default_options ());
}
TEST(19)
TEST(def10)
{
db::LEFDEFReaderOptions opt = default_options ();
opt.set_cell_outline_layer ("OUTLINE (2/0)");
run_test (_this, "def10", "def:in.def", "au.oas.gz", opt);
}
TEST(20)
TEST(def11)
{
db::LEFDEFReaderOptions opt = default_options ();
opt.set_cell_outline_layer ("OUTLINE (12/0)");
run_test (_this, "def11", "lef:test.lef+def:test.def", "au.oas.gz", opt);
}
TEST(21)
TEST(def12)
{
db::LEFDEFReaderOptions opt = default_options ();
opt.set_cell_outline_layer ("OUTLINE (20/0)");
run_test (_this, "def12", "lef:test.lef+def:test.def", "au-new.oas.gz", opt);
}
TEST(22)
TEST(def13)
{
db::LEFDEFReaderOptions opt = default_options ();
run_test (_this, "def13", "map:test.map+lef:test.lef_5.8+def:top.def.gz", "au2.oas.gz", opt);
}
TEST(23)
TEST(def14)
{
db::LEFDEFReaderOptions opt = default_options ();
opt.set_macro_resolution_mode (1);
run_test (_this, "def14", "map:test.map+lef:tech.lef+lef:stdlib.lef+def:test.def", "au.oas.gz", opt);
}
TEST(24)
TEST(def15)
{
db::LEFDEFReaderOptions opt = default_options ();
opt.set_macro_resolution_mode (1);
run_test (_this, "def15", "map:test.map+lef:tech.lef+def:test.def", "au2.oas.gz", opt);
}
TEST(def16)
{
// this is rather a smoke test
// (complete example)
db::LEFDEFReaderOptions opt = default_options ();
opt.set_macro_resolution_mode (1);
run_test (_this, "def16", "lef:a.lef+lef:tech.lef+def:a.def", "au.oas.gz", opt);
}
TEST(100)
{
run_test (_this, "issue-172", "lef:in.lef+def:in.def", "au.oas.gz", default_options (), false);
@ -954,3 +970,9 @@ TEST(205_lef_resistance)
run_test (_this, "issue-1214", "read:merged.nom.lef", "au.oas.gz", lefdef_opt, false);
}
// issue 1282
TEST(206_lef_spacing)
{
run_test (_this, "issue-1282", "read:a.lef", 0, default_options (), false);
}

25
testdata/lefdef/issue-1282/a.lef vendored Normal file
View File

@ -0,0 +1,25 @@
VERSION 5.4 ;
NAMESCASESENSITIVE ON ;
BUSBITCHARS "[]" ;
DIVIDERCHAR "/" ;
NOWIREEXTENSIONATPIN OFF ;
UNITS
DATABASE MICRONS 1000 ;
END UNITS
NONDEFAULTRULE DOUBLESPACE
LAYER M1
WIDTH 0.16 ;
SPACING 0.36 ;
END M1
# klayout 0.28.5 lef reader get's confused by the SPACING in NONDEFAULTRULE
SPACING
SAMENET M1 M1 0.36 ;
END SPACING
END DOUBLESPACE
END LIBRARY

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -667,12 +667,18 @@ class LAYLayers_TestClass < TestBase
p.clear_line_style
assert_equal( p.has_line_style?, false )
assert_equal( p.is_expanded?, false )
p.expanded = true
assert_equal( p.is_expanded?, true )
pp = RBA::LayerPropertiesNode::new
assert_equal( pp == p, false )
assert_equal( pp != p, true )
assert_equal( pp.is_expanded?, false )
pp = p.dup
assert_equal( pp == p, true )
assert_equal( pp != p, false )
assert_equal( pp.is_expanded?, true )
end