From 999c0652620b839cd1655eb9176a14df099ce899 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Thu, 4 Jun 2020 12:17:34 +0200 Subject: [PATCH] Introducing iterated arrays for instances Iterated instances are created for OASIS files using irregular repetitions in viewer mode. Reason: this way, the same drawing optimization than for iterated shape arrays can be applied. As this is a new API feature, some adjustments had to be made to incorporate them into the code. --- src/db/db/dbArray.h | 26 +++ src/db/db/dbHash.h | 6 + src/db/db/dbInstances.cc | 24 ++- src/db/db/dbLayoutDiff.cc | 4 + src/db/db/dbTextWriter.cc | 65 +++--- src/db/db/gsiDeclDbCell.cc | 103 +++------- src/db/unit_tests/dbLayoutDiffTests.cc | 4 + .../laybasic/layBrowseInstancesForm.cc | 10 +- src/laybasic/laybasic/layBrowseShapesForm.cc | 10 +- .../laybasic/layRedrawThreadWorker.cc | 42 +++- .../gds2/db_plugin/dbGDS2WriterBase.cc | 188 +++++++++--------- .../oasis/db_plugin/dbOASISReader.cc | 38 ++++ .../oasis/db_plugin/dbOASISWriter.cc | 28 ++- .../diff/lay_plugin/layDiffToolDialog.cc | 4 + src/tl/tl/tlUnitTest.cc | 1 + 15 files changed, 342 insertions(+), 211 deletions(-) diff --git a/src/db/db/dbArray.h b/src/db/db/dbArray.h index 7def9fe86..78e7fd402 100644 --- a/src/db/db/dbArray.h +++ b/src/db/db/dbArray.h @@ -1641,6 +1641,32 @@ struct array // .. nothing yet .. } + /** + * @brief The iterated array constructor + * + * This is basically a convenience function that creates + * an appropriate basic_array object. + */ + template + array (const Obj &obj, const trans_type &trans, Iter from, Iter to) + : m_obj (obj), m_trans (trans), mp_base (new iterated_array (from, to)) + { + // .. nothing yet .. + } + + /** + * @brief The complex iterated array constructor + * + * This is basically a convenience function that creates + * an appropriate basic_array object. + */ + template + array (const Obj &obj, const complex_trans_type &ct, Iter from, Iter to) + : m_obj (obj), m_trans (ct), mp_base (new iterated_complex_array (ct.rcos (), ct.mag (), from, to)) + { + // .. nothing yet .. + } + /** * @brief The singular complex instance constructor * diff --git a/src/db/db/dbHash.h b/src/db/db/dbHash.h index 91c950468..d816a667e 100644 --- a/src/db/db/dbHash.h +++ b/src/db/db/dbHash.h @@ -283,6 +283,12 @@ namespace std h = hfunc (b, h); h = hfunc (na, h); h = hfunc (nb, h); + } else if (o.size () > 1) { + // iterated array + typename db::array >::iterator i = o.begin (); + while (! (++i).at_end ()) { + h = hfunc (*i, h); + } } if (o.is_complex ()) { diff --git a/src/db/db/dbInstances.cc b/src/db/db/dbInstances.cc index 488b86a92..4d9a0e6ab 100644 --- a/src/db/db/dbInstances.cc +++ b/src/db/db/dbInstances.cc @@ -241,16 +241,28 @@ Instance::to_string (bool resolve_cell_name) const r = "cell_index=" + tl::to_string (ci.object ().cell_index ()); } - if (ci.is_complex ()) { - r += " " + ci.complex_trans ().to_string (); - } else { - r += " " + (*ci.begin ()).to_string (); - } - db::vector a, b; unsigned long amax, bmax; if (ci.is_regular_array (a, b, amax, bmax)) { + + if (ci.is_complex ()) { + r += " " + ci.complex_trans ().to_string (); + } else { + r += " " + (*ci.begin ()).to_string (); + } + r += " array=(" + a.to_string () + "," + b.to_string () + " " + tl::to_string (amax) + "x" + tl::to_string (bmax) + ")"; + + } else { + + for (db::CellInstArray::iterator i = ci.begin (); ! i.at_end (); ++i) { + if (ci.is_complex ()) { + r += " " + ci.complex_trans (*i).to_string (); + } else { + r += " " + (*i).to_string (); + } + } + } if (has_prop_id ()) { diff --git a/src/db/db/dbLayoutDiff.cc b/src/db/db/dbLayoutDiff.cc index c3b778abc..f9c29bbce 100644 --- a/src/db/db/dbLayoutDiff.cc +++ b/src/db/db/dbLayoutDiff.cc @@ -1189,6 +1189,8 @@ PrintingDifferenceReceiver::print_cell_inst (const db::CellInstArrayWithProperti unsigned long amax, bmax; if (ci.is_regular_array (a, b, amax, bmax)) { enough (tl::info) << "[a=" << a.to_string () << ", b=" << b.to_string () << ", na=" << amax << ", nb=" << bmax << "]" << tl::noendl; + } else if (ci.size () > 1) { + enough (tl::info) << " (+" << (ci.size () - 1) << " irregular locations)" << tl::noendl; } else { enough (tl::info) << "" << tl::noendl; } @@ -1208,6 +1210,8 @@ PrintingDifferenceReceiver::print_cell_inst (const db::CellInstArrayWithProperti unsigned long amax, bmax; if (ci.is_regular_array (a, b, amax, bmax)) { enough (tl::info) << "[a=" << a.to_string () << ", b=" << b.to_string () << ", na=" << amax << ", nb=" << bmax << "]" << tl::noendl; + } else if (ci.size () > 1) { + enough (tl::info) << " (+" << (ci.size () - 1) << " irregular locations)" << tl::noendl; } else { enough (tl::info) << "" << tl::noendl; } diff --git a/src/db/db/dbTextWriter.cc b/src/db/db/dbTextWriter.cc index 2dc06d0d3..d484a7a11 100644 --- a/src/db/db/dbTextWriter.cc +++ b/src/db/db/dbTextWriter.cc @@ -198,43 +198,52 @@ TextWriter::write (const db::Layout &layout) for (db::Cell::const_iterator inst = cref.begin (); ! inst.at_end (); ++inst) { - std::string pfx = ""; - - if (inst->has_prop_id () && inst->prop_id () != 0) { - pfx = "p $props"; - write_props (layout, inst->prop_id ()); - } - db::Vector a, b; unsigned long amax, bmax; bool is_reg = inst->is_regular_array (a, b, amax, bmax); - *this << (is_reg ? "aref" : "sref") << pfx << " {" << layout.cell_name (inst->cell_index ()) << "}"; + for (db::CellInstArray::iterator i = inst->begin (); ! i.at_end (); ++i) { - db::Trans t = inst->front (); + std::string pfx = ""; + + if (inst->has_prop_id () && inst->prop_id () != 0) { + pfx = "p $props"; + write_props (layout, inst->prop_id ()); + } + + *this << (is_reg ? "aref" : "sref") << pfx << " {" << layout.cell_name (inst->cell_index ()) << "}"; + + db::Trans t = *i; + + if (inst->is_complex ()) { + db::CellInstArray::complex_trans_type ct = inst->complex_trans (t); + *this << " " << ct.angle (); + *this << " " << (ct.is_mirror () ? 1 : 0); + *this << " " << ct.mag (); + } else { + *this << " " << (t.rot () % 4) * 90.0; + *this << " " << (t.is_mirror () ? 1 : 0); + *this << " " << 1.0; + } + + if (is_reg) { + *this << " " << int (std::max ((unsigned long) 1, amax)); + *this << " " << int (std::max ((unsigned long) 1, bmax)); + } + *this << " " << t.disp (); + if (is_reg) { + *this << " " << (t.disp () + a * (long) amax); + *this << " " << (t.disp () + b * (long) bmax); + } + *this << endl (); + + if (is_reg) { + break; + } - if (inst->is_complex ()) { - *this << " " << inst->complex_trans ().angle (); - *this << " " << (inst->complex_trans ().is_mirror () ? 1 : 0); - *this << " " << inst->complex_trans ().mag (); - } else { - *this << " " << (t.rot () % 4) * 90.0; - *this << " " << (t.is_mirror () ? 1 : 0); - *this << " " << 1.0; } - if (is_reg) { - *this << " " << int (std::max ((unsigned long) 1, amax)); - *this << " " << int (std::max ((unsigned long) 1, bmax)); - } - *this << " " << t.disp (); - if (is_reg) { - *this << " " << (t.disp () + a * (long) amax); - *this << " " << (t.disp () + b * (long) bmax); - } - *this << endl (); - } end_sorted_section (); diff --git a/src/db/db/gsiDeclDbCell.cc b/src/db/db/gsiDeclDbCell.cc index bf4000a24..d6f2bef9d 100644 --- a/src/db/db/gsiDeclDbCell.cc +++ b/src/db/db/gsiDeclDbCell.cc @@ -251,6 +251,8 @@ struct cell_inst_array_defs unsigned long na = 1, nb = 1; if (arr->is_regular_array (a, b, na, nb)) { *arr = C (arr->object (), t, a, b, na, nb); + } else if (arr->is_iterated_array ()) { + throw tl::Exception (tl::to_string (tr ("Can't set the transformation on an iterated array (layout not editable?)"))); } else { *arr = C (arr->object (), t); } @@ -262,6 +264,8 @@ struct cell_inst_array_defs unsigned long na = 1, nb = 1; if (arr->is_regular_array (a, b, na, nb)) { *arr = C (arr->object (), t, a, b, na, nb); + } else if (arr->is_iterated_array ()) { + throw tl::Exception (tl::to_string (tr ("Can't set the transformation on an iterated array (layout not editable?)"))); } else { *arr = C (arr->object (), t); } @@ -292,6 +296,8 @@ struct cell_inst_array_defs s += "*"; s += tl::to_string (nb); s += "]"; + } else if (arr->size () > 1) { + s += std::string (" (+") + tl::to_string (arr->size () - 1) + " irregular locations)"; } return s; @@ -303,14 +309,27 @@ struct cell_inst_array_defs { typedef db::array > target_array; + std::vector iterated; + std::vector iterated_transformed; typename C::vector_type a, b; unsigned long amax = 0, bmax = 0; + if (arr.is_regular_array (a, b, amax, bmax)) { if (arr.is_complex ()) { return target_array (arr.object (), t * arr.complex_trans () * t.inverted (), t * a, t * b, amax, bmax); } else { return target_array (arr.object (), typename target_array::trans_type (t * typename C::complex_trans_type (arr.front ()) * t.inverted ()), t * a, t * b, amax, bmax); } + } else if (arr.is_iterated_array (&iterated)) { + iterated_transformed.reserve (iterated.size ()); + for (typename std::vector::const_iterator i = iterated.begin (); i != iterated.end (); ++i) { + iterated_transformed.push_back (t * *i); + } + if (arr.is_complex ()) { + return target_array (arr.object (), t * arr.complex_trans () * t.inverted (), iterated_transformed.begin (), iterated_transformed.end ()); + } else { + return target_array (arr.object (), typename target_array::trans_type (t * typename C::complex_trans_type (arr.front ()) * t.inverted ()), iterated_transformed.begin (), iterated_transformed.end ()); + } } else if (arr.is_complex ()) { return target_array (arr.object (), t * arr.complex_trans () * t.inverted ()); } else { @@ -352,88 +371,12 @@ struct cell_inst_array_defs static bool less (const C *i, const C &other) { - if (i->object ().cell_index () != other.object ().cell_index ()) { - return i->object ().cell_index () < other.object ().cell_index (); - } - - db::vector a, b; - unsigned long na = 1, nb = 1; - bool r = i->is_regular_array (a, b, na, nb); - - db::vector aother, bother; - unsigned long naother = 1, nbother = 1; - bool rother = other.is_regular_array (aother, bother, naother, nbother); - - if (r != rother) { - return r < rother; - } else if (r) { - if (a.not_equal (aother)) { - return a.less (aother); - } - if (b.not_equal (bother)) { - return b.less (bother); - } - if (na != naother) { - return na < naother; - } - if (nb != nbother) { - return nb < nbother; - } - } - - bool c = i->is_complex (); - bool cother = other.is_complex (); - - if (c != cother) { - return c < cother; - } else if (c) { - return i->complex_trans ().less (other.complex_trans ()); - } else { - return i->front ().less (other.front ()); - } + return *i < other; } static bool equal (const C *i, const C &other) { - if (i->object ().cell_index () != other.object ().cell_index ()) { - return false; - } - - db::vector a, b; - unsigned long na = 1, nb = 1; - bool r = i->is_regular_array (a, b, na, nb); - - db::vector aother, bother; - unsigned long naother = 1, nbother = 1; - bool rother = other.is_regular_array (aother, bother, naother, nbother); - - if (r != rother) { - return false; - } else if (r) { - if (a.not_equal (aother)) { - return false; - } - if (b.not_equal (bother)) { - return false; - } - if (na != naother) { - return false; - } - if (nb != nbother) { - return false; - } - } - - bool c = i->is_complex (); - bool cother = other.is_complex (); - - if (c != cother) { - return false; - } else if (c) { - return i->complex_trans ().equal (other.complex_trans ()); - } else { - return i->front ().equal (other.front ()); - } + return *i == other; } static bool not_equal (const C *i, const C &other) @@ -508,7 +451,9 @@ struct cell_inst_array_defs ) + gsi::method ("size", &C::size, "@brief Gets the number of single instances in the array\n" - "If the instance represents a single instance, the count is 1. Otherwise it is na*nb." + "If the instance represents a single instance, the count is 1. Otherwise it is na*nb. " + "Starting with version 0.27, there may be iterated instances for which the size is larger than 1, but \\is_regular_array? will return false. " + "In this case, use \\each_trans or \\each_cplx_trans to retrieve the individual placements of the iterated instance." ) + gsi::method_ext ("cell_index", &cell_index, "@brief Gets the cell index of the cell instantiated \n" diff --git a/src/db/unit_tests/dbLayoutDiffTests.cc b/src/db/unit_tests/dbLayoutDiffTests.cc index e4b533a2b..5dadccfd2 100644 --- a/src/db/unit_tests/dbLayoutDiffTests.cc +++ b/src/db/unit_tests/dbLayoutDiffTests.cc @@ -97,6 +97,8 @@ TestDifferenceReceiver::print_cell_inst (const db::CellInstArrayWithProperties & unsigned long amax, bmax; if (ci.is_regular_array (a, b, amax, bmax)) { m_os << "[a=" << a.to_string () << ", b=" << b.to_string () << ", na=" << amax << ", nb=" << bmax << "]"; + } else if (ci.size () > 1) { + m_os << " (+" << (ci.size () - 1) << " irregular placements)"; } if (ci.properties_id () != 0) { m_os << " [" << ci.properties_id () << "]" << std::endl; @@ -112,6 +114,8 @@ TestDifferenceReceiver::print_cell_inst (const db::CellInstArrayWithProperties & unsigned long amax, bmax; if (ci.is_regular_array (a, b, amax, bmax)) { m_os << "[a=" << a.to_string () << ", b=" << b.to_string () << ", na=" << amax << ", nb=" << bmax << "]"; + } else if (ci.size () > 1) { + m_os << " (+" << (ci.size () - 1) << " irregular placements)"; } if (ci.properties_id () != 0) { m_os << " [" << ci.properties_id () << "]" << std::endl; diff --git a/src/laybasic/laybasic/layBrowseInstancesForm.cc b/src/laybasic/laybasic/layBrowseInstancesForm.cc index a4149cf95..82c08848c 100644 --- a/src/laybasic/laybasic/layBrowseInstancesForm.cc +++ b/src/laybasic/laybasic/layBrowseInstancesForm.cc @@ -702,7 +702,15 @@ BrowseInstancesForm::fill_cell_instances (const db::ICplxTrans &t, const db::Lay std::string aref; if (r > 1 || c > 1) { - aref = tl::sprintf ("[%ld,%ld]", c, r); + aref = "["; + aref += tl::to_string (c); + aref += ","; + aref += tl::to_string (r); + aref += "]"; + } else if (parent_inst.size () > 1) { + aref = "(+"; + aref += tl::to_string (parent_inst.size () - 1); + aref += "x)"; } std::string new_path; diff --git a/src/laybasic/laybasic/layBrowseShapesForm.cc b/src/laybasic/laybasic/layBrowseShapesForm.cc index 24c26737c..fc29b8761 100644 --- a/src/laybasic/laybasic/layBrowseShapesForm.cc +++ b/src/laybasic/laybasic/layBrowseShapesForm.cc @@ -868,7 +868,15 @@ BrowseShapesForm::fill_cell_instances (const db::ICplxTrans &t, const db::Layout std::string aref; if (r > 1 || c > 1) { - aref = tl::sprintf ("[%ld,%ld]", c, r); + aref = "["; + aref += tl::to_string (c); + aref += ","; + aref += tl::to_string (r); + aref += "]"; + } else if (parent_inst.size () > 1) { + aref = "(+"; + aref += tl::to_string (parent_inst.size () - 1); + aref += "x)"; } std::string new_path; diff --git a/src/laybasic/laybasic/layRedrawThreadWorker.cc b/src/laybasic/laybasic/layRedrawThreadWorker.cc index 87dedc4ce..0aae08e5a 100644 --- a/src/laybasic/laybasic/layRedrawThreadWorker.cc +++ b/src/laybasic/laybasic/layRedrawThreadWorker.cc @@ -809,15 +809,31 @@ RedrawThreadWorker::draw_boxes (bool drawing_context, db::cell_index_type ci, co } else { - // The array (or single instance) must be iterated instance - // by instance - for (db::CellInstArray::iterator p = cell_inst.begin_touching (*v, bc); ! p.at_end (); ++p) { + size_t qid = 0; + + // The array (or single instance) must be iterated instance by instance + for (db::CellInstArray::iterator p = cell_inst.begin_touching (*v, bc); ! p.at_end (); ) { test_snapshot (0); db::ICplxTrans t (cell_inst.complex_trans (*p)); db::Box new_vp = db::Box (t.inverted () * *v); draw_boxes (drawing_context, new_ci, trans * t, new_vp, level + 1); + if (p.quad_id () > 0 && p.quad_id () != qid) { + + qid = p.quad_id (); + + // if the quad is very small we don't gain anything from looking further into the quad - skip this one + db::DBox qb = trans * cell_inst.quad_box (p, bc); + if (qb.width () < 1.0 && qb.height () < 1.0) { + p.skip_quad (); + continue; + } + + } + + ++p; + } } @@ -986,7 +1002,6 @@ RedrawThreadWorker::draw_box_properties (bool drawing_context, db::cell_index_ty ++inst; } - } } @@ -1756,7 +1771,9 @@ RedrawThreadWorker::draw_layer_wo_cache (int from_level, int to_level, db::cell_ } else if (anything) { - for (db::CellInstArray::iterator p = cell_inst.begin_touching (*v, bc); ! p.at_end (); ++p) { + size_t qid = 0; + + for (db::CellInstArray::iterator p = cell_inst.begin_touching (*v, bc); ! p.at_end (); ) { if (! m_draw_array_border_instances || p.index_a () <= 0 || (unsigned long)p.index_a () == amax - 1 || p.index_b () <= 0 || (unsigned long)p.index_b () == bmax - 1) { @@ -1765,6 +1782,21 @@ RedrawThreadWorker::draw_layer_wo_cache (int from_level, int to_level, db::cell_ db::Box new_vp = db::Box (t.inverted () * *v); draw_layer (from_level, to_level, new_ci, trans * t, new_vp, level + 1, fill, frame, vertex, text, update_snapshot); + if (p.quad_id () > 0 && p.quad_id () != qid) { + + qid = p.quad_id (); + + // if the quad is very small we don't gain anything from looking further into the quad - skip this one + db::DBox qb = trans * cell_inst.quad_box (p, bc); + if (qb.width () < 1.0 && qb.height () < 1.0) { + p.skip_quad (); + continue; + } + + } + + ++p; + } } diff --git a/src/plugins/streamers/gds2/db_plugin/dbGDS2WriterBase.cc b/src/plugins/streamers/gds2/db_plugin/dbGDS2WriterBase.cc index 0ba72cd21..55b82c1aa 100644 --- a/src/plugins/streamers/gds2/db_plugin/dbGDS2WriterBase.cc +++ b/src/plugins/streamers/gds2/db_plugin/dbGDS2WriterBase.cc @@ -354,120 +354,130 @@ GDS2WriterBase::write_inst (double sf, const db::Instance &instance, bool normal bool is_reg = instance.is_regular_array (a, b, amax, bmax); - db::Trans t = instance.front (); + for (db::CellInstArray::iterator ii = instance.begin (); ! ii.at_end (); ++ii) { - if (normalize) { + db::Trans t = *ii; - // try to normalize orthogonal arrays into "Cadence notation", that is - // column and row vectors are positive in the coordinate system of the - // rotated array. - - if (is_reg) { + if (normalize) { - if (amax < 2) { - a = db::Vector (); - } - if (bmax < 2) { - b = db::Vector (); - } + // try to normalize orthogonal arrays into "Cadence notation", that is + // column and row vectors are positive in the coordinate system of the + // rotated array. - // normalisation only works for orthogonal vectors, parallel to x or y axis, which are not parallel - if ((a.x () == 0 || a.y () == 0) && (b.x () == 0 || b.y () == 0) && !((a.x () != 0 && b.x () != 0) || (a.y () != 0 && b.y () != 0))) { - - db::FTrans fp = db::FTrans(t.rot ()).inverted (); - - a.transform (fp); - b.transform (fp); + if (is_reg) { - db::Vector p; - for (int i = 0; i < 2; ++i) { + if (amax < 2) { + a = db::Vector (); + } + if (bmax < 2) { + b = db::Vector (); + } - db::Vector *q = (i == 0) ? &a : &b; - unsigned long n = (i == 0) ? amax : bmax; + // normalisation only works for orthogonal vectors, parallel to x or y axis, which are not parallel + if ((a.x () == 0 || a.y () == 0) && (b.x () == 0 || b.y () == 0) && !((a.x () != 0 && b.x () != 0) || (a.y () != 0 && b.y () != 0))) { + + db::FTrans fp = db::FTrans(t.rot ()).inverted (); + + a.transform (fp); + b.transform (fp); + + db::Vector p; + for (int i = 0; i < 2; ++i) { + + db::Vector *q = (i == 0) ? &a : &b; + unsigned long n = (i == 0) ? amax : bmax; + + if (n == 0) { + *q = db::Vector (); + } else { + if (q->x () < 0) { + p += db::Vector ((n - 1) * q->x (), 0); + q->set_x (-q->x ()); + } + if (q->y () < 0) { + p += db::Vector (0, (n - 1) * q->y ()); + q->set_y (-q->y ()); + } + } - if (n == 0) { - *q = db::Vector (); - } else { - if (q->x () < 0) { - p += db::Vector ((n - 1) * q->x (), 0); - q->set_x (-q->x ()); - } - if (q->y () < 0) { - p += db::Vector (0, (n - 1) * q->y ()); - q->set_y (-q->y ()); - } } + if (a.x () != 0 || b.y () != 0) { + std::swap (a, b); + std::swap (amax, bmax); + } + + fp = db::FTrans (t.rot ()); + a.transform (fp); + b.transform (fp); + + t = t * db::Trans (p); + } - if (a.x () != 0 || b.y () != 0) { - std::swap (a, b); - std::swap (amax, bmax); - } - - fp = db::FTrans (t.rot ()); - a.transform (fp); - b.transform (fp); - - t = t * db::Trans (p); - } } - } + write_record_size (4); + write_record (is_reg ? sAREF : sSREF); - write_record_size (4); - write_record (is_reg ? sAREF : sSREF); + write_string_record (sSNAME, m_cell_name_map.cell_name (instance.cell_index ())); - write_string_record (sSNAME, m_cell_name_map.cell_name (instance.cell_index ())); + if (t.rot () != 0 || instance.is_complex ()) { - if (t.rot () != 0 || instance.is_complex ()) { + write_record_size (6); + write_record (sSTRANS); + write_short (t.is_mirror () ? 0x8000 : 0); - write_record_size (6); - write_record (sSTRANS); - write_short (t.is_mirror () ? 0x8000 : 0); - - if (instance.is_complex ()) { - write_record_size (4 + 8); - write_record (sMAG); - write_double (instance.complex_trans ().mag ()); - write_record_size (4 + 8); - write_record (sANGLE); - write_double (instance.complex_trans ().angle ()); - } else { - if ((t.rot () % 4) != 0) { + if (instance.is_complex ()) { + db::CellInstArray::complex_trans_type ct = instance.complex_trans (t); + write_record_size (4 + 8); + write_record (sMAG); + write_double (ct.mag ()); write_record_size (4 + 8); write_record (sANGLE); - write_double ((t.rot () % 4) * 90.0); + write_double (ct.angle ()); + } else { + if ((t.rot () % 4) != 0) { + write_record_size (4 + 8); + write_record (sANGLE); + write_double ((t.rot () % 4) * 90.0); + } } + + } + + if (is_reg) { + write_record_size (4 + 2 * 2); + write_record (sCOLROW); + if (amax > 32767 || bmax > 32767) { + throw tl::Exception (tl::to_string (tr ("Cannot write array references with more than 32767 columns or rows to GDS2 streams"))); + } + write_short (std::max ((unsigned long) 1, bmax)); + write_short (std::max ((unsigned long) 1, amax)); + } + + write_record_size (4 + (is_reg ? 3 : 1) * 2 * 4); + write_record (sXY); + write_int (scale (sf, t.disp ().x ())); + write_int (scale (sf, t.disp ().y ())); + + if (is_reg) { + write_int (scale (sf, t.disp ().x () + b.x () * bmax)); + write_int (scale (sf, t.disp ().y () + b.y () * bmax)); + write_int (scale (sf, t.disp ().x () + a.x () * amax)); + write_int (scale (sf, t.disp ().y () + a.y () * amax)); + } + + finish (layout, prop_id); + + if (is_reg) { + // we have already written all instances + break; } } - - if (is_reg) { - write_record_size (4 + 2 * 2); - write_record (sCOLROW); - if (amax > 32767 || bmax > 32767) { - throw tl::Exception (tl::to_string (tr ("Cannot write array references with more than 32767 columns or rows to GDS2 streams"))); - } - write_short (std::max ((unsigned long) 1, bmax)); - write_short (std::max ((unsigned long) 1, amax)); - } - - write_record_size (4 + (is_reg ? 3 : 1) * 2 * 4); - write_record (sXY); - write_int (scale (sf, t.disp ().x ())); - write_int (scale (sf, t.disp ().y ())); - - if (is_reg) { - write_int (scale (sf, t.disp ().x () + b.x () * bmax)); - write_int (scale (sf, t.disp ().y () + b.y () * bmax)); - write_int (scale (sf, t.disp ().x () + a.x () * amax)); - write_int (scale (sf, t.disp ().y () + a.y () * amax)); - } - - finish (layout, prop_id); } void diff --git a/src/plugins/streamers/oasis/db_plugin/dbOASISReader.cc b/src/plugins/streamers/oasis/db_plugin/dbOASISReader.cc index 029dc7f5a..30c87b8c2 100644 --- a/src/plugins/streamers/oasis/db_plugin/dbOASISReader.cc +++ b/src/plugins/streamers/oasis/db_plugin/dbOASISReader.cc @@ -2018,6 +2018,8 @@ OASISReader::do_read_placement (unsigned char r, db::Vector pos (mm_placement_x.get (), mm_placement_y.get ()); + const std::vector *points = 0; + if ((m & 0x8) && read_repetition ()) { std::pair pp = read_element_properties (layout.properties_repository (), false); @@ -2042,6 +2044,42 @@ OASISReader::do_read_placement (unsigned char r, instances.push_back (inst); } + } else if (! layout.is_editable () && (points = mm_repetition.get ().is_iterated ()) != 0) { + + db::CellInstArray inst; + + if (mag_set || angle < 0) { + + db::ICplxTrans ct (mag, angle_deg, mirror, pos); + + db::CellInstArray::iterated_complex_array_type array (ct.rcos (), ct.mag ()); + array.reserve (points->size () + 1); + array.insert (db::Vector ()); + array.insert (points->begin (), points->end ()); + array.sort (); + + inst = db::CellInstArray (db::CellInst (mm_placement_cell.get ()), + db::Trans (ct), layout.array_repository ().insert (array)); + + } else { + + db::CellInstArray::iterated_array_type array; + array.reserve (points->size () + 1); + array.insert (db::Vector ()); + array.insert (points->begin (), points->end ()); + array.sort (); + + inst = db::CellInstArray (db::CellInst (mm_placement_cell.get ()), + db::Trans (angle, mirror, pos), layout.array_repository ().insert (array)); + + } + + if (pp.first) { + instances_with_props.push_back (db::CellInstArrayWithProperties (inst, pp.second)); + } else { + instances.push_back (inst); + } + } else { RepetitionIterator p = mm_repetition.get ().begin (); diff --git a/src/plugins/streamers/oasis/db_plugin/dbOASISWriter.cc b/src/plugins/streamers/oasis/db_plugin/dbOASISWriter.cc index d7d54a313..7791b9e98 100644 --- a/src/plugins/streamers/oasis/db_plugin/dbOASISWriter.cc +++ b/src/plugins/streamers/oasis/db_plugin/dbOASISWriter.cc @@ -1965,11 +1965,35 @@ OASISWriter::write (const db::CellInstArray &inst, db::properties_id_type prop_i { m_progress.set (mp_stream->pos ()); + std::vector pts; db::Vector a, b; unsigned long amax, bmax; - bool is_reg = inst.is_regular_array (a, b, amax, bmax); - if (is_reg && (amax > 1 || bmax > 1)) { + if (inst.is_iterated_array (&pts) && pts.size () > 1) { + + // Remove the first point which is implicitly contained in the repetition + // Note: we can do so because below we instantiate the shape at the front of the array which includes + // the first transformation already. + db::Vector po = pts.front (); + std::vector::iterator pw = pts.begin(); + for (std::vector::iterator p = pw + 1; p != pts.end (); ++p) { + *pw++ = *p - po; + } + pts.erase (pw, pts.end ()); + + db::IrregularRepetition *rep_base = new db::IrregularRepetition (); + rep_base->points ().swap (pts); + db::Repetition array_rep (rep_base); + + if (rep != db::Repetition ()) { + for (db::RepetitionIterator r = rep.begin (); ! r.at_end (); ++r) { + write_inst_with_rep (inst, prop_id, *r, array_rep); + } + } else { + write_inst_with_rep (inst, prop_id, db::Vector (), array_rep); + } + + } else if (inst.is_regular_array (a, b, amax, bmax) && (amax > 1 || bmax > 1)) { // we cannot use the repetition - instead we write every single instance and use the repetition // for the array information diff --git a/src/plugins/tools/diff/lay_plugin/layDiffToolDialog.cc b/src/plugins/tools/diff/lay_plugin/layDiffToolDialog.cc index 208856ef2..173383945 100644 --- a/src/plugins/tools/diff/lay_plugin/layDiffToolDialog.cc +++ b/src/plugins/tools/diff/lay_plugin/layDiffToolDialog.cc @@ -224,6 +224,10 @@ RdbDifferenceReceiver::produce_cell_inst (const db::CellInstArrayWithProperties unsigned long amax, bmax; if (ci.is_regular_array (a, b, amax, bmax)) { r += tl::sprintf (" [a=%s, b=%s, na=%ld, nb=%ld]", a.to_string (), b.to_string (), amax, bmax); + } else if (ci.size () > 1) { + r += " (+"; + r += tl::to_string (ci.size () - 1); + r += " irregular placements)"; } item->add_value (r); diff --git a/src/tl/tl/tlUnitTest.cc b/src/tl/tl/tlUnitTest.cc index ecebd781f..649d12d04 100644 --- a/src/tl/tl/tlUnitTest.cc +++ b/src/tl/tl/tlUnitTest.cc @@ -232,6 +232,7 @@ bool TestBase::do_test (bool editable, bool slow) { m_editable = editable; m_slow = slow; + m_any_failed = false; // Ensures the test temp directory is present std::string tmpdir = tl::combine_path (tl::absolute_file_path (testtmp ()), m_testdir);