diff --git a/src/db/db/dbAsIfFlatRegion.cc b/src/db/db/dbAsIfFlatRegion.cc index 03782957f..0bfc03df1 100644 --- a/src/db/db/dbAsIfFlatRegion.cc +++ b/src/db/db/dbAsIfFlatRegion.cc @@ -440,6 +440,14 @@ template void AsIfFlatRegion::produce_markers_for_grid_check (con EdgePairs AsIfFlatRegion::grid_check (db::Coord gx, db::Coord gy) const { + if (gx < 0 || gy < 0) { + throw tl::Exception (tl::to_string (tr ("Grid check requires a positive grid value"))); + } + + if (gx == 0 && gy == 0) { + return EdgePairs (); + } + std::auto_ptr res (new db::FlatEdgePairs ()); for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p) { @@ -567,6 +575,14 @@ AsIfFlatRegion::snapped_polygon (const db::Polygon &poly, db::Coord gx, db::Coor RegionDelegate * AsIfFlatRegion::snapped (db::Coord gx, db::Coord gy) { + if (gx < 0 || gy < 0) { + throw tl::Exception (tl::to_string (tr ("Grid check requires a positive grid value"))); + } + + if (gx == 0 && gy == 0) { + return this; + } + std::auto_ptr new_region (new FlatRegion (merged_semantics ())); gx = std::max (db::Coord (1), gx); diff --git a/src/db/db/dbDeepRegion.cc b/src/db/db/dbDeepRegion.cc index e4b6c82da..dbef515b5 100644 --- a/src/db/db/dbDeepRegion.cc +++ b/src/db/db/dbDeepRegion.cc @@ -716,7 +716,7 @@ DeepRegion::to_string (size_t nmax) const EdgePairs DeepRegion::grid_check (db::Coord gx, db::Coord gy) const { - if (gx <= 0 || gy <= 0) { + if (gx < 0 || gy < 0) { throw tl::Exception (tl::to_string (tr ("Grid check requires a positive grid value"))); } @@ -725,6 +725,10 @@ DeepRegion::grid_check (db::Coord gx, db::Coord gy) const return db::AsIfFlatRegion::grid_check (gx, gy); } + if (gx == 0) { + return EdgePairs (); + } + ensure_merged_polygons_valid (); db::Layout &layout = m_merged_polygons.layout (); @@ -796,7 +800,7 @@ DeepRegion::angle_check (double min, double max, bool inverse) const RegionDelegate * DeepRegion::snapped (db::Coord gx, db::Coord gy) { - if (gx <= 0 || gy <= 0) { + if (gx < 0 || gy < 0) { throw tl::Exception (tl::to_string (tr ("Snapping requires a positive grid value"))); } @@ -805,6 +809,10 @@ DeepRegion::snapped (db::Coord gx, db::Coord gy) return db::AsIfFlatRegion::snapped (gx, gy); } + if (! gx) { + return this; + } + ensure_merged_polygons_valid (); db::cell_variants_collector vars (gx); diff --git a/src/drc/unit_tests/drcSimpleTests.cc b/src/drc/unit_tests/drcSimpleTests.cc index b3d225ce8..197d7b4df 100644 --- a/src/drc/unit_tests/drcSimpleTests.cc +++ b/src/drc/unit_tests/drcSimpleTests.cc @@ -102,7 +102,7 @@ TEST(2) db::compare_layouts (_this, layout, au, db::NoNormalization); } -TEST(3) +TEST(3_Flat) { std::string rs = tl::testsrc (); rs += "/testdata/drc/drcSimpleTests_3.drc"; @@ -141,3 +141,43 @@ TEST(3) db::compare_layouts (_this, layout, au, db::NoNormalization); } + +TEST(4_Hierarchical) +{ + std::string rs = tl::testsrc (); + rs += "/testdata/drc/drcSimpleTests_4.drc"; + + std::string input = tl::testsrc (); + input += "/testdata/drc/drctest.gds"; + + std::string au = tl::testsrc (); + au += "/testdata/drc/drcSimpleTests_au4.oas"; + + std::string output = this->tmp_file ("tmp.gds"); + + { + // Set some variables + lym::Macro config; + config.set_text (tl::sprintf ( + "$drc_test_source = '%s'\n" + "$drc_test_target = '%s'\n" + , input, output) + ); + config.set_interpreter (lym::Macro::Ruby); + EXPECT_EQ (config.run (), 0); + } + + lym::Macro drc; + drc.load_from (rs); + EXPECT_EQ (drc.run (), 0); + + db::Layout layout; + + { + tl::InputStream stream (output); + db::Reader reader (stream); + reader.read (layout); + } + + db::compare_layouts (_this, layout, au, db::NoNormalization); +} diff --git a/src/drc/unit_tests/drcSuiteTests.cc b/src/drc/unit_tests/drcSuiteTests.cc index 94e043626..b134a853d 100644 --- a/src/drc/unit_tests/drcSuiteTests.cc +++ b/src/drc/unit_tests/drcSuiteTests.cc @@ -72,25 +72,36 @@ void runtest (tl::TestBase *_this, int mode) db::compare_layouts (_this, layout, au, db::WriteOAS); } -TEST(1) +TEST(1_Flat) { runtest (_this, 1); } -TEST(2) +TEST(2_BigFlat) { test_is_long_runner (); runtest (_this, 2); } -TEST(3) +TEST(3_Tiled) { test_is_long_runner (); runtest (_this, 3); } -TEST(4) +TEST(4_BigTiled) { test_is_long_runner (); runtest (_this, 4); } + +TEST(5_Hier) +{ + runtest (_this, 5); +} + +TEST(6_BigHier) +{ + test_is_long_runner (); + runtest (_this, 6); +} diff --git a/testdata/drc/drcSimpleTests_4.drc b/testdata/drc/drcSimpleTests_4.drc new file mode 100644 index 000000000..579156b06 --- /dev/null +++ b/testdata/drc/drcSimpleTests_4.drc @@ -0,0 +1,49 @@ + +# Foreign cell test + +source($drc_test_source, "TOPTOP_SMALL") +target($drc_test_target) + +cell("TOPTOP_SMALL") + +l1_flat = input(1) +l1_flat.is_deep? && raise("l1_flat should not be deep") + +is_deep? && raise("is_deep? is true") + +deep + +is_deep? || raise("is_deep? is false") + +l1 = input(1) +l1.is_deep? || raise("l1 should be deep") +l2 = input(2) +l2.is_deep? || raise("l2 should be deep") + +flat + +is_deep? && raise("is_deep? is true") + +l2_flat = input(2) +l2_flat.is_deep? && raise("l2_flat should not be deep") + +l1.output(1, 0) +l2.output(2, 0) + +l1_flat.output(11, 0) +l2_flat.output(12, 0) + +l1.and(l2).output(1000, 0) +l1_flat.and(l2).output(1001, 0) +l1.and(l2_flat).output(1002, 0) +l1_flat.and(l2_flat).output(1003, 0) + +l1.space(0.2).output(1010, 0) +l1_flat.space(0.2).output(1011, 0) + +l1.separation(l2, 0.3).output(1020, 0) +l1_flat.separation(l2, 0.3).output(1021, 0) +l1.separation(l2_flat, 0.3).output(1022, 0) +l1_flat.separation(l2_flat, 0.3).output(1023, 0) + + diff --git a/testdata/drc/drcSimpleTests_au4.oas b/testdata/drc/drcSimpleTests_au4.oas new file mode 100644 index 000000000..aa37d1e7d Binary files /dev/null and b/testdata/drc/drcSimpleTests_au4.oas differ diff --git a/testdata/drc/drcSuiteTests.drc b/testdata/drc/drcSuiteTests.drc index 8490b026e..88765993e 100644 --- a/testdata/drc/drcSuiteTests.drc +++ b/testdata/drc/drcSuiteTests.drc @@ -4,12 +4,16 @@ def message(m) $stdout.flush end -def run_testsuite(dm, ic, tiled = false) +def expect_eq(a, b) + a == b || raise("unexpected value #{a.to_s}, should be #{b.to_s}") +end + +def run_testsuite(dm, ic, tiled = false, hier = false) has_float_range = ((0..0.5).max != 0) lb = 100 - + a = input(RBA::LayerInfo::new(1, 0)) b = input(2) c = input(3) @@ -21,16 +25,16 @@ def run_testsuite(dm, ic, tiled = false) layers.each { |l| h[l] = true } h[RBA::LayerInfo::new(1, 0)] || raise("missing layer 1/0 in layers list") - c.is_merged? == false || raise("unexpected value") + expect_eq(c.is_merged?, false) message "--- general #{lb}" l1 = a&b l1.output(lb, dm) - l1.is_empty? && raise("must not be empty") + expect_eq(l1.is_empty?, false) a.and(b).xor(l1).is_empty? || raise("xor not empty") - tiled || (a.and(b).is_merged? == true || raise("unexpected value")) + tiled || hier || expect_eq(a.and(b).is_merged?, true) a.xor(b).output(RBA::LayerInfo::new(lb + 1, dm)) a.xor(b).xor(a ^ b).is_empty? || raise("xor not empty") @@ -43,28 +47,36 @@ def run_testsuite(dm, ic, tiled = false) a.join(b).xor(a + b).is_empty? || raise("xor not empty") if !tiled - a.join(b).data.size == 16 * ic || raise("unexpected shape count") + expect_eq(a.join(b).data.size, 16 * ic) end - c.raw.is_clean? == false || raise("unexpected value") - # c.raw switched the semantics - c.is_clean? == false || raise("unexpected value") - (c.area / ic).to_s == "10.0" || raise("unexpected value") - (c.edges.length / ic).to_s == "18.0" || raise("unexpected value") - (c.perimeter / ic).to_s == "18.0" || raise("unexpected value") - c.clean - c.is_clean? == true || raise("unexpected value") - (c.area / ic).to_s == "9.0" || raise("unexpected value") - (c.edges.length / ic).to_s == "14.0" || raise("unexpected value") - (c.perimeter / ic).to_s == "14.0" || raise("unexpected value") - (c.dup.area / ic).to_s == "9.0" || raise("unexpected value") - (c.raw.clean.area / ic).to_s == "9.0" || raise("unexpected value") - (c.area / ic).to_s == "9.0" || raise("unexpected value") - (c.raw.area / ic).to_s == "10.0" || raise("unexpected value") - c.clean + # NOTE: there is no clean/raw semantics in deep mode + if ! hier + expect_eq(c.raw.is_clean?, false) + # c.raw switched the semantics + expect_eq(c.is_clean?, false) + expect_eq((c.area / ic).to_s, "10.0") + expect_eq((c.edges.length / ic).to_s, "18.0") + expect_eq((c.perimeter / ic).to_s, "18.0") + c.clean + expect_eq(c.is_clean?, true) + end + + expect_eq((c.area / ic).to_s, "9.0") + expect_eq((c.edges.length / ic).to_s, "14.0") + expect_eq((c.perimeter / ic).to_s, "14.0") + expect_eq((c.dup.area / ic).to_s, "9.0") + + # NOTE: there is no clean/raw semantics in deep mode + if ! hier + expect_eq((c.raw.clean.area / ic).to_s, "9.0") + expect_eq((c.area / ic).to_s, "9.0") + expect_eq((c.raw.area / ic).to_s, "10.0") + c.clean + end if ic == 1 - c.bbox.to_s == "(-4,-5;0,-2)" || raise("unexpected value") + expect_eq(c.bbox.to_s, "(-4,-5;0,-2)") end lb += 10 #110 @@ -80,15 +92,15 @@ def run_testsuite(dm, ic, tiled = false) a.edges.end_segments(0, 0.5).extended_out(0.01).output(lb + 7, dm) a.edges.end_segments(0.5, 0.5).extended_out(0.01).output(lb + 8, dm) - a.polygons? == true || raise("unexpected value") - a.edges? == false || raise("unexpected value") - a.edge_pairs? == false || raise("unexpected value") - a.edges.edge_pairs? == false || raise("unexpected value") - a.edges.polygons? == false || raise("unexpected value") - a.edges.edges? == true || raise("unexpected value") - a.space(0.5).edge_pairs? == true || raise("unexpected value") - a.space(0.5).polygons? == false || raise("unexpected value") - a.space(0.5).edges? == false || raise("unexpected value") + expect_eq(a.polygons?, true) + expect_eq(a.edges?, false) + expect_eq(a.edge_pairs?, false) + expect_eq(a.edges.edge_pairs?, false) + expect_eq(a.edges.polygons?, false) + expect_eq(a.edges.edges?, true) + expect_eq(a.space(0.5).edge_pairs?, true) + expect_eq(a.space(0.5).polygons?, false) + expect_eq(a.space(0.5).edges?, false) lb += 10 #120 message "--- extended #{lb}" @@ -132,7 +144,7 @@ def run_testsuite(dm, ic, tiled = false) b.interacting(a).in(b).output(lb + 1, dm) (b|a).not_in(b).output(lb + 2, dm) x.in(b).output(lb + 3, dm) - b.sized(0.1).in(b).is_empty? == true || raise("unexpected value") + expect_eq(b.sized(0.1).in(b).is_empty?, true) lb += 10 #170 message "--- inside, outside, overlapping, interacting #{lb}" @@ -209,14 +221,18 @@ def run_testsuite(dm, ic, tiled = false) lb += 10 #180 message "--- merge #{lb}" - c.raw + if !hier + c.raw + end if !tiled - c.merged.is_merged? == true || raise("unexpected value") + expect_eq(c.merged.is_merged?, true) end c.merged.output(lb, dm) c.merged(2).output(lb + 1, dm) c.merged(3).output(lb + 2, dm) - c.clean + if !hier + c.clean + end cdup = c.dup cdup.merge.xor(c.merged).output(lb + 3, dm) cdup.xor(c.merged).output(lb + 4, dm) @@ -252,9 +268,11 @@ def run_testsuite(dm, ic, tiled = false) a.non_rectangles.output(lb + 1, dm) a.rectilinear.output(lb + 2, dm) a.non_rectilinear.output(lb + 3, dm) - c.raw - c.non_rectangles.output(lb + 4, dm) - c.clean + if !hier + c.raw + c.non_rectangles.output(lb + 4, dm) + c.clean + end c.rectangles.output(lb + 5, dm) lb += 10 #210 @@ -561,12 +579,18 @@ if $drc_test_mode == 1 source($drc_test_source, "TOP") target($drc_test_target, "TOP") + + flat + run_testsuite(0, 1) elsif $drc_test_mode == 2 target($drc_test_target, "TOPTOP") source($drc_test_source, "TOPTOP") + + flat + run_testsuite(0, 900) elsif $drc_test_mode == 3 @@ -592,5 +616,23 @@ elsif $drc_test_mode == 4 run_testsuite(0, 900, true) +elsif $drc_test_mode == 5 + + source($drc_test_source, "TOP") + target($drc_test_target, "TOP") + + deep + + run_testsuite(0, 1, false, true) + +elsif $drc_test_mode == 6 + + target($drc_test_target, "TOPTOP") + source($drc_test_source, "TOPTOP") + + deep + + run_testsuite(0, 900, false, true) + end diff --git a/testdata/drc/drcSuiteTests_au5.oas b/testdata/drc/drcSuiteTests_au5.oas new file mode 100644 index 000000000..c49c2c616 Binary files /dev/null and b/testdata/drc/drcSuiteTests_au5.oas differ diff --git a/testdata/drc/drcSuiteTests_au6.oas b/testdata/drc/drcSuiteTests_au6.oas new file mode 100644 index 000000000..bf5fabfd9 Binary files /dev/null and b/testdata/drc/drcSuiteTests_au6.oas differ diff --git a/testdata/drc/drctest.gds b/testdata/drc/drctest.gds index daa662289..f1eb87e11 100644 Binary files a/testdata/drc/drctest.gds and b/testdata/drc/drctest.gds differ