1 /* Author: Matt Liberty */
2 /*
3 * Copyright (c) 2020, The Regents of the University of California
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of the University nor the
14 * names of its contributors may be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS BE LIABLE FOR ANY DIRECT,
21 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #define BOOST_TEST_MODULE gc
30
31 #ifdef HAS_BOOST_UNIT_TEST_LIBRARY
32 // Shared library version
33 #define BOOST_TEST_DYN_LINK
34 #include <boost/test/unit_test.hpp>
35 #else
36 // Header only version
37 #include <boost/test/included/unit_test.hpp>
38 #endif
39
40 #include <boost/test/data/test_case.hpp>
41 #include <iostream>
42
43 #include "fixture.h"
44 #include "frDesign.h"
45 #include "gc/FlexGC.h"
46
47 using namespace fr;
48 namespace bdata = boost::unit_test::data;
49
50 // Fixture for GC tests
51 struct GCFixture : public Fixture
52 {
GCFixtureGCFixture53 GCFixture() : worker(design->getTech(), logger.get()) {}
54
testMarkerGCFixture55 void testMarker(frMarker* marker,
56 frLayerNum layer_num,
57 frConstraintTypeEnum type,
58 const frBox& expected_bbox)
59 {
60 frBox bbox;
61 marker->getBBox(bbox);
62
63 BOOST_TEST(marker->getLayerNum() == layer_num);
64 BOOST_TEST(marker->getConstraint());
65 TEST_ENUM_EQUAL(marker->getConstraint()->typeId(), type);
66 BOOST_TEST(bbox == expected_bbox);
67 }
68
runGCGCFixture69 void runGC()
70 {
71 // Needs to be run after all the objects are created but before gc
72 initRegionQuery();
73
74 // Run the GC engine
75 const frBox work(0, 0, 2000, 2000);
76 worker.setExtBox(work);
77 worker.setDrcBox(work);
78
79 worker.init(design.get());
80 worker.main();
81 worker.end();
82 }
83
84 FlexGCWorker worker;
85 };
86
87 BOOST_FIXTURE_TEST_SUITE(gc, GCFixture);
88
89 // Two touching metal shape from different nets generate a short
BOOST_AUTO_TEST_CASE(metal_short)90 BOOST_AUTO_TEST_CASE(metal_short)
91 {
92 // Setup
93 frNet* n1 = makeNet("n1");
94 frNet* n2 = makeNet("n2");
95
96 makePathseg(n1, 2, {0, 0}, {500, 0});
97 makePathseg(n2, 2, {500, 0}, {1000, 0});
98
99 runGC();
100
101 // Test the results
102 auto& markers = worker.getMarkers();
103
104 BOOST_TEST(markers.size() == 1);
105 testMarker(markers[0].get(),
106 2,
107 frConstraintTypeEnum::frcShortConstraint,
108 frBox(500, -50, 500, 50));
109 }
110
111 /*
112 *
113 * |---------------|(750,200)
114 * | |
115 * | |
116 * | i1 |
117 * | OBS |
118 * | |
119 * |****|(550,90) |
120 * | in | |
121 * --------------------|----|--(600,50)|
122 * | (450,40)|****| | |
123 * | n1 | | |
124 * --------------------|---------------|
125 * (0,-50) (450,-50)
126 */
127 // short with obs
BOOST_AUTO_TEST_CASE(metal_short_obs)128 BOOST_AUTO_TEST_CASE(metal_short_obs)
129 {
130 // Setup
131 frNet* n1 = makeNet("n1");
132
133 makePathseg(n1, 2, {0, 0}, {600, 0});
134 auto block = makeMacro("OBS");
135 makeMacroObs(block, 450, -50, 750, 200, 2);
136 auto pin = makeMacroPin(block, "in", 450, 40, 550, 90, 2);
137 auto i1 = makeInst("i1", block, 0, 0);
138 auto instTerm = i1->getInstTerms()[0].get();
139 instTerm->addToNet(n1);
140
141 n1->addInstTerm(instTerm);
142 auto instTermNode = make_unique<frNode>();
143 instTermNode->setPin(instTerm);
144 instTermNode->setType(frNodeTypeEnum::frcPin);
145 n1->addNode(instTermNode);
146 runGC();
147
148 // Test the results
149 auto& markers = worker.getMarkers();
150
151 BOOST_TEST(markers.size() == 3);
152 // short of pin+net (450,-50), (550,90)
153 // with obs 450,-50), (750,200)
154 testMarker(markers[0].get(),
155 2,
156 frConstraintTypeEnum::frcShortConstraint,
157 frBox(450, -50, 550, 40));
158
159 // shorts of net (0,-50), (600,50)
160 // with obs (450,-50), (750,200)
161 // 2 max rectangles generated
162 testMarker(markers[1].get(),
163 2,
164 frConstraintTypeEnum::frcShortConstraint,
165 frBox(550, -50, 600, 50));
166 testMarker(markers[2].get(),
167 2,
168 frConstraintTypeEnum::frcShortConstraint,
169 frBox(450, -50, 600, 40));
170 }
171
172 // Two touching metal shape from the same net must have sufficient
173 // overlap
BOOST_AUTO_TEST_CASE(metal_non_sufficient)174 BOOST_AUTO_TEST_CASE(metal_non_sufficient)
175 {
176 // Setup
177 frNet* n1 = makeNet("n1");
178
179 makePathseg(n1, 2, {0, 0}, {0, 500});
180 makePathseg(n1, 2, {0, 0}, {500, 0});
181
182 runGC();
183
184 // Test the results
185 auto& markers = worker.getMarkers();
186
187 BOOST_TEST(markers.size() == 1);
188 testMarker(markers[0].get(),
189 2,
190 frConstraintTypeEnum::frcNonSufficientMetalConstraint,
191 frBox(0, 0, 50, 50));
192 }
193
194 // Path seg less than min width flags a violation
BOOST_AUTO_TEST_CASE(min_width)195 BOOST_AUTO_TEST_CASE(min_width)
196 {
197 // Setup
198 frNet* n1 = makeNet("n1");
199
200 makePathseg(n1, 2, {0, 0}, {500, 0}, 60);
201
202 runGC();
203
204 // Test the results
205 auto& markers = worker.getMarkers();
206
207 BOOST_TEST(markers.size() == 1);
208 testMarker(markers[0].get(),
209 2,
210 frConstraintTypeEnum::frcMinWidthConstraint,
211 frBox(0, -30, 500, 30));
212 }
213
214 // Abutting Path seg less than min width don't flag a violation
215 // as their combined width is ok
BOOST_AUTO_TEST_CASE(min_width_combines_shapes)216 BOOST_AUTO_TEST_CASE(min_width_combines_shapes)
217 {
218 // Setup
219 frNet* n1 = makeNet("n1");
220
221 makePathseg(n1, 2, {0, 0}, {500, 0}, 60);
222 makePathseg(n1, 2, {0, 60}, {500, 60}, 60);
223
224 runGC();
225
226 // Test the results
227 BOOST_TEST(worker.getMarkers().size() == 0);
228 }
229
230 // Check violation for off-grid points
BOOST_AUTO_TEST_CASE(off_grid)231 BOOST_AUTO_TEST_CASE(off_grid)
232 {
233 // Setup
234 frNet* n1 = makeNet("n1");
235
236 makePathseg(n1, 2, {1, 1}, {501, 1});
237
238 runGC();
239
240 // Test the results
241 auto& markers = worker.getMarkers();
242
243 BOOST_TEST(worker.getMarkers().size() == 1);
244 testMarker(markers[0].get(),
245 2,
246 frConstraintTypeEnum::frcOffGridConstraint,
247 frBox(1, -49, 501, 51));
248 }
249
250 // Check violation for corner spacing
BOOST_AUTO_TEST_CASE(corner_basic)251 BOOST_AUTO_TEST_CASE(corner_basic)
252 {
253 // Setup
254 makeCornerConstraint(2);
255
256 frNet* n1 = makeNet("n1");
257
258 makePathseg(n1, 2, {0, 0}, {500, 0});
259 makePathseg(n1, 2, {500, 200}, {1000, 200});
260
261 runGC();
262
263 // Test the results
264 auto& markers = worker.getMarkers();
265
266 BOOST_TEST(worker.getMarkers().size() == 1);
267 testMarker(markers[0].get(),
268 2,
269 frConstraintTypeEnum::frcLef58CornerSpacingConstraint,
270 frBox(500, 50, 500, 150));
271 }
272
273 // Check no violation for corner spacing with EOL spacing
274 // (same as corner_basic but for eol)
BOOST_AUTO_TEST_CASE(corner_eol_no_violation)275 BOOST_AUTO_TEST_CASE(corner_eol_no_violation)
276 {
277 // Setup
278 makeCornerConstraint(2, 200);
279
280 frNet* n1 = makeNet("n1");
281
282 makePathseg(n1, 2, {0, 0}, {500, 0});
283 makePathseg(n1, 2, {500, 200}, {1000, 200});
284
285 runGC();
286
287 // Test the results
288 auto& markers = worker.getMarkers();
289
290 BOOST_TEST(worker.getMarkers().size() == 0);
291 }
292
293 // Check no violation for corner spacing with PRL > 0
294 // (same as corner_basic but for n2's pathseg begin pt)
BOOST_AUTO_TEST_CASE(corner_prl_no_violation)295 BOOST_AUTO_TEST_CASE(corner_prl_no_violation)
296 {
297 // Setup
298 makeCornerConstraint(2);
299
300 frNet* n1 = makeNet("n1");
301
302 makePathseg(n1, 2, {0, 0}, {500, 0});
303 makePathseg(n1, 2, {400, 200}, {1000, 200});
304
305 runGC();
306
307 // Test the results
308 auto& markers = worker.getMarkers();
309
310 BOOST_TEST(worker.getMarkers().size() == 0);
311 }
312
313 // Check violation for corner spacing on a concave corner
314 BOOST_AUTO_TEST_CASE(corner_concave, *boost::unit_test::disabled())
315 {
316 // Setup
317 makeCornerConstraint(2, /* no eol */ -1, frCornerTypeEnum::CONCAVE);
318
319 frNet* n1 = makeNet("n1");
320
321 makePathsegExt(n1, 2, {0, 0}, {500, 0});
322 makePathsegExt(n1, 2, {0, 0}, {0, 500});
323 makePathseg(n1, 2, {200, 200}, {1000, 200});
324
325 runGC();
326
327 // Test the results
328 auto& markers = worker.getMarkers();
329
330 BOOST_TEST(worker.getMarkers().size() == 1);
331 testMarker(markers[0].get(),
332 2,
333 frConstraintTypeEnum::frcLef58CornerSpacingConstraint,
334 frBox(50, 50, 200, 200));
335 }
336
337 // Check violation for parallel-run-length (PRL) spacing tables
338 // This test runs over a variety of width / prl / spacing values
339 // where the spacing is both legal or illegal.
340 BOOST_DATA_TEST_CASE(spacing_prl,
341 (bdata::make({100, 220}) * bdata::make({300, 500})
342 ^ bdata::make({100, 200, 300, 400}))
343 * bdata::make({true, false}),
344 width,
345 prl,
346 spacing,
347 legal)
348 {
349 // Setup
350 makeSpacingConstraint(2);
351
352 frNet* n1 = makeNet("n1");
353 frNet* n2 = makeNet("n2");
354
355 frCoord y = /* n2_width / 2 */ 50 + spacing + width / 2;
356 if (!legal) {
357 /* move too close making a violation */
358 y -= 10;
359 }
360 makePathseg(n1, 2, {0, y}, {prl, y}, width);
361 makePathseg(n2, 2, {0, 0}, {500, 0}, 100);
362
363 runGC();
364
365 // Test the results
366 auto& markers = worker.getMarkers();
367
368 if (legal) {
369 BOOST_TEST(worker.getMarkers().size() == 0);
370 } else {
371 BOOST_TEST(worker.getMarkers().size() == 1);
372 testMarker(markers[0].get(),
373 2,
374 frConstraintTypeEnum::frcSpacingTablePrlConstraint,
375 frBox(0, 50, prl, y - width / 2));
376 }
377 }
378
379 // Check violation for spacing two widths with design rule width on macro
380 // obstruction
381 BOOST_DATA_TEST_CASE(design_rule_width, bdata::make({true, false}), legal)
382 {
383 // Setup
384 makeSpacingTableTwConstraint(2, {90, 190}, {-1, -1}, {{0, 50}, {50, 100}});
385 /*
386 WIDTH 90 0 50
387 WIDTH 190 50 150
388 */
389 frNet* n1 = makeNet("n1");
390
391 makePathseg(n1, 2, {0, 50}, {500, 50}, 100);
392 auto block = makeMacro("DRW");
393 makeMacroObs(block, 0, 140, 500, 340, 2, legal ? 100 : -1);
394 makeInst("i1", block, 0, 0);
395 /*
396 If DESIGNRULEWIDTH is 100
397 width(n1) = 100 width(obs) = 100 : reqSpcVal = 0
398 legal
399
400 if DESIGNRULEWIDTH is -1 (undefined)
401 width(n1) = 100 width(obs) = 200 : reqSpcVal = 100
402 illegal
403 */
404 runGC();
405
406 // Test the results
407 auto& markers = worker.getMarkers();
408 if (legal)
409 BOOST_TEST(markers.size() == 0);
410 else {
411 BOOST_TEST(markers.size() == 1);
412 testMarker(markers[0].get(),
413 2,
414 frConstraintTypeEnum::frcSpacingTableTwConstraint,
415 frBox(0, 100, 500, 140));
416 }
417 }
418
419 // Check for a min step violation. The checker seems broken
420 // so this test is disabled.
421 BOOST_AUTO_TEST_CASE(min_step, *boost::unit_test::disabled())
422 {
423 // Setup
424 makeMinStepConstraint(2);
425
426 frNet* n1 = makeNet("n1");
427
428 makePathseg(n1, 2, {0, 0}, {200, 0});
429 makePathseg(n1, 2, {100, 20}, {200, 20});
430
431 runGC();
432
433 // Test the results
434 BOOST_TEST(worker.getMarkers().size() == 1);
435 }
436
437 // Check for a lef58 style min step violation. The checker is very
438 // limited and just supports NOBETWEENEOL style.
BOOST_AUTO_TEST_CASE(min_step58)439 BOOST_AUTO_TEST_CASE(min_step58)
440 {
441 // Setup
442 makeMinStep58Constraint(2);
443
444 frNet* n1 = makeNet("n1");
445
446 makePathseg(n1, 2, {0, 0}, {500, 0});
447 makePathseg(n1, 2, {200, 20}, {300, 20});
448
449 runGC();
450
451 // Test the results
452 auto& markers = worker.getMarkers();
453 BOOST_TEST(markers.size() == 1);
454 testMarker(markers[0].get(),
455 2,
456 frConstraintTypeEnum::frcLef58MinStepConstraint,
457 frBox(200, 50, 300, 70));
458 }
459
460 // Check for a lef58 rect only violation. The markers are
461 // the concave corners expanded by min-width and intersected
462 // with the metal shapes.
BOOST_AUTO_TEST_CASE(rect_only)463 BOOST_AUTO_TEST_CASE(rect_only)
464 {
465 // Setup
466 makeRectOnlyConstraint(2);
467
468 frNet* n1 = makeNet("n1");
469
470 makePathseg(n1, 2, {0, 0}, {500, 0});
471 makePathseg(n1, 2, {200, 0}, {200, 100});
472
473 runGC();
474
475 // Test the results
476 auto& markers = worker.getMarkers();
477 BOOST_TEST(markers.size() == 3);
478 testMarker(markers[0].get(),
479 2,
480 frConstraintTypeEnum::frcLef58RectOnlyConstraint,
481 frBox(150, -50, 250, 100));
482 testMarker(markers[1].get(),
483 2,
484 frConstraintTypeEnum::frcLef58RectOnlyConstraint,
485 frBox(150, -50, 350, 50));
486 testMarker(markers[2].get(),
487 2,
488 frConstraintTypeEnum::frcLef58RectOnlyConstraint,
489 frBox(50, -50, 250, 50));
490 }
491
492 // Check for a min enclosed area violation.
BOOST_AUTO_TEST_CASE(min_enclosed_area)493 BOOST_AUTO_TEST_CASE(min_enclosed_area)
494 {
495 // Setup
496 makeMinEnclosedAreaConstraint(2);
497
498 frNet* n1 = makeNet("n1");
499
500 makePathsegExt(n1, 2, {0, 0}, {200, 0});
501 makePathsegExt(n1, 2, {0, 0}, {0, 200});
502 makePathsegExt(n1, 2, {0, 200}, {200, 200});
503 makePathsegExt(n1, 2, {200, 0}, {200, 200});
504
505 runGC();
506
507 // Test the results
508 auto& markers = worker.getMarkers();
509 BOOST_TEST(markers.size() == 1);
510 testMarker(markers[0].get(),
511 2,
512 frConstraintTypeEnum::frcMinEnclosedAreaConstraint,
513 frBox(50, 50, 150, 150));
514 }
515
516 // Check for a spacing table influence violation.
BOOST_AUTO_TEST_CASE(spacing_table_infl_vertical)517 BOOST_AUTO_TEST_CASE(spacing_table_infl_vertical)
518 {
519 // Setup
520 makeSpacingTableInfluenceConstraint(2, {10}, {{200, 100}});
521
522 frNet* n1 = makeNet("n1");
523
524 makePathseg(n1, 2, {50, 0}, {50, 200});
525 makePathseg(n1, 2, {0, 100}, {350, 100});
526 makePathseg(n1, 2, {0, 250}, {350, 250});
527
528 runGC();
529
530 // Test the results
531 auto& markers = worker.getMarkers();
532
533 BOOST_TEST(markers.size() == 1);
534 testMarker(markers[0].get(),
535 2,
536 frConstraintTypeEnum::frcSpacingTableInfluenceConstraint,
537 frBox(100, 150, 300, 200));
538 }
539 // Check for a spacing table influence violation.
BOOST_AUTO_TEST_CASE(spacing_table_infl_horizontal)540 BOOST_AUTO_TEST_CASE(spacing_table_infl_horizontal)
541 {
542 // Setup
543 makeSpacingTableInfluenceConstraint(2, {10}, {{200, 150}});
544
545 frNet* n1 = makeNet("n1");
546
547 makePathseg(n1, 2, {0, 500}, {500, 500});
548 makePathseg(n1, 2, {100, 0}, {100, 500});
549 makePathseg(n1, 2, {300, 0}, {300, 500});
550 runGC();
551
552 // Test the results
553 auto& markers = worker.getMarkers();
554
555 BOOST_TEST(markers.size() == 1);
556 testMarker(markers[0].get(),
557 2,
558 frConstraintTypeEnum::frcSpacingTableInfluenceConstraint,
559 frBox(150, 250, 250, 450));
560 }
561
562 // Check for a spacing table twowidths violation.
BOOST_AUTO_TEST_CASE(spacing_table_twowidth)563 BOOST_AUTO_TEST_CASE(spacing_table_twowidth)
564 {
565 // Setup
566 makeSpacingTableTwConstraint(2, {90, 190}, {-1, -1}, {{0, 50}, {50, 100}});
567
568 frNet* n1 = makeNet("n1");
569
570 makePathseg(n1, 2, {0, 50}, {500, 50}, 100);
571 makePathseg(n1, 2, {0, 240}, {500, 240}, 200);
572
573 runGC();
574
575 // Test the results
576 auto& markers = worker.getMarkers();
577
578 BOOST_TEST(markers.size() == 1);
579 testMarker(markers[0].get(),
580 2,
581 frConstraintTypeEnum::frcSpacingTableTwConstraint,
582 frBox(0, 100, 500, 140));
583 }
584
585 // Check for a basic end-of-line (EOL) spacing violation.
586 BOOST_DATA_TEST_CASE(eol_basic, (bdata::make({true, false})), lef58)
587 {
588 // Setup
589 if (lef58)
590 makeLef58SpacingEolConstraint(2);
591 else
592 makeSpacingEndOfLineConstraint(2);
593
594 frNet* n1 = makeNet("n1");
595
596 makePathseg(n1, 2, {500, 0}, {500, 500});
597 makePathseg(n1, 2, {0, 700}, {1000, 700});
598
599 runGC();
600
601 // Test the results
602 auto& markers = worker.getMarkers();
603 BOOST_TEST(markers.size() == 1);
604 testMarker(markers[0].get(),
605 2,
606 lef58 ? frConstraintTypeEnum::frcLef58SpacingEndOfLineConstraint
607 : frConstraintTypeEnum::frcSpacingEndOfLineConstraint,
608 frBox(450, 500, 550, 650));
609 }
610 BOOST_DATA_TEST_CASE(eol_ext_basic,
611 (bdata::make({30, 50})) ^ (bdata::make({true, false})),
612 ext,
613 legal)
614 {
615 // Setup
616 makeEolExtensionConstraint(2, 100, {51, 101}, {20, ext}, false);
617
618 frNet* n1 = makeNet("n1");
619
620 makePathseg(n1, 2, {0, 100}, {500, 100});
621 makePathseg(n1, 2, {690, 100}, {1000, 100});
622
623 runGC();
624
625 // Test the results
626 auto& markers = worker.getMarkers();
627 if (legal)
628 BOOST_TEST(markers.size() == 0);
629 else {
630 BOOST_TEST(markers.size() == 1);
631 if (markers.size() == 1)
632 testMarker(markers[0].get(),
633 2,
634 frConstraintTypeEnum::frcLef58EolExtensionConstraint,
635 frBox(500, 50, 690, 150));
636 }
637 }
638
639 BOOST_DATA_TEST_CASE(eol_ext_paronly, (bdata::make({true, false})), parOnly)
640 {
641 // Setup
642 makeEolExtensionConstraint(2, 100, {101}, {50}, parOnly);
643
644 frNet* n1 = makeNet("n1");
645
646 makePathseg(n1, 2, {0, 100}, {500, 100});
647 makePathseg(n1, 2, {520, 290}, {910, 290});
648 runGC();
649
650 // Test the results
651 auto& markers = worker.getMarkers();
652 if (parOnly)
653 BOOST_TEST(markers.size() == 0);
654 else {
655 BOOST_TEST(markers.size() == 1);
656 testMarker(markers[0].get(),
657 2,
658 frConstraintTypeEnum::frcLef58EolExtensionConstraint,
659 frBox(500, 150, 520, 240));
660 }
661 }
662 // Check for eol keepout violation.
663 BOOST_DATA_TEST_CASE(eol_keepout, (bdata::make({true, false})), legal)
664 {
665 // Setup
666 makeLef58EolKeepOutConstraint(2);
667
668 frNet* n1 = makeNet("n1");
669
670 makePathseg(n1, 2, {500, 0}, {500, 500});
671 frCoord x_extra = 0;
672 if (legal)
673 x_extra = 200;
674 makePathseg(n1, 2, {400 + x_extra, 700}, {700 + x_extra, 700});
675
676 runGC();
677
678 // Test the results
679 auto& markers = worker.getMarkers();
680 if (legal)
681 BOOST_TEST(markers.size() == 0);
682 else {
683 BOOST_TEST(markers.size() == 1);
684 testMarker(markers[0].get(),
685 2,
686 frConstraintTypeEnum::frcLef58EolKeepOutConstraint,
687 frBox(450, 500, 550, 650));
688 }
689 }
690
BOOST_AUTO_TEST_CASE(eol_keepout_except_within)691 BOOST_AUTO_TEST_CASE(eol_keepout_except_within)
692 {
693 // Setup
694 makeLef58EolKeepOutConstraint(2, false, true);
695
696 frNet* n1 = makeNet("n1");
697
698 makePathseg(n1, 2, {500, 0}, {500, 500});
699 makePathseg(n1, 2, {400, 700}, {700, 700});
700
701 runGC();
702
703 auto& markers = worker.getMarkers();
704 BOOST_TEST(markers.size() == 0);
705 }
706
707 // Check for eol keepout violation CORNERONLY.
708 BOOST_DATA_TEST_CASE(eol_keepout_corner,
709 (bdata::make({true, false}) * bdata::make({true, false})),
710 concave,
711 legal)
712 {
713 // Setup
714 makeLef58EolKeepOutConstraint(2, true);
715
716 frNet* n1 = makeNet("n1");
717
718 makePathseg(n1, 2, {500, 0}, {500, 500});
719 frCoord x_extra = 0;
720 if (concave && !legal)
721 makePathseg(n1, 2, {360, 400}, {360, 750});
722 if (!concave && !legal)
723 x_extra = 10;
724 makePathseg(n1, 2, {400 + x_extra, 700}, {600 + x_extra, 700});
725
726 runGC();
727
728 // Test the results
729 auto& markers = worker.getMarkers();
730 if (legal)
731 BOOST_TEST(markers.size() == 0);
732 else {
733 BOOST_TEST(markers.size() == 1);
734 testMarker(markers[0].get(),
735 2,
736 frConstraintTypeEnum::frcLef58EolKeepOutConstraint,
737 frBox(410, 500, 450, 650));
738 }
739 }
740
741 // Check for an end-of-line (EOL) spacing violation involving one
742 // parallel edge
743 BOOST_DATA_TEST_CASE(eol_parallel_edge, (bdata::make({true, false})), lef58)
744 {
745 // Setup
746 if (lef58)
747 makeLef58SpacingEolParEdgeConstraint(
748 makeLef58SpacingEolConstraint(2), 200, 200);
749 else
750 makeSpacingEndOfLineConstraint(
751 2, /* par_space */ 200, /* par_within */ 200);
752
753 frNet* n1 = makeNet("n1");
754
755 makePathseg(n1, 2, {500, 0}, {500, 500});
756 makePathseg(n1, 2, {0, 700}, {1000, 700});
757 makePathseg(n1, 2, {300, 0}, {300, 450});
758
759 runGC();
760
761 // Test the results
762 auto& markers = worker.getMarkers();
763 BOOST_TEST(markers.size() == 1);
764 testMarker(markers[0].get(),
765 2,
766 lef58 ? frConstraintTypeEnum::frcLef58SpacingEndOfLineConstraint
767 : frConstraintTypeEnum::frcSpacingEndOfLineConstraint,
768 frBox(450, 500, 550, 650));
769 }
770
771 // Check for an end-of-line (EOL) spacing violation involving two
772 // parallel edges
773 BOOST_DATA_TEST_CASE(eol_parallel_two_edge, (bdata::make({true, false})), lef58)
774 {
775 // Setup
776 if (lef58)
777 makeLef58SpacingEolParEdgeConstraint(
778 makeLef58SpacingEolConstraint(2), 200, 200, true);
779 else
780 makeSpacingEndOfLineConstraint(2,
781 /* par_space */ 200,
782 /* par_within */ 200,
783 /* two_edges */ true);
784
785 frNet* n1 = makeNet("n1");
786
787 makePathseg(n1, 2, {500, 0}, {500, 500});
788 makePathseg(n1, 2, {0, 700}, {1000, 700});
789 makePathseg(n1, 2, {300, 0}, {300, 450});
790 makePathseg(n1, 2, {700, 0}, {700, 450});
791
792 runGC();
793
794 // Test the results
795 auto& markers = worker.getMarkers();
796 BOOST_TEST(markers.size() == 1);
797 testMarker(markers[0].get(),
798 2,
799 lef58 ? frConstraintTypeEnum::frcLef58SpacingEndOfLineConstraint
800 : frConstraintTypeEnum::frcSpacingEndOfLineConstraint,
801 frBox(450, 500, 550, 650));
802 }
803
804 BOOST_DATA_TEST_CASE(eol_min_max,
805 (bdata::make({true, false}) * bdata::make({true, false})
806 * bdata::make({true, false})),
807 max,
808 twoSides,
809 legal)
810 {
811 makeLef58SpacingEolMinMaxLenConstraint(
812 makeLef58SpacingEolConstraint(2), 500, max, twoSides);
813 frNet* n1 = makeNet("n1");
814 frCoord y = 500;
815 if (twoSides) // both sides need to meet minMax for eolSpacing to be
816 // triggered and one of them need to violate minMax for
817 // eolSpacing to be neglected
818 {
819 if (max && legal)
820 y += 10; // right(510) > max(500) --> minMax violated --> legal
821 else if (!max && !legal)
822 y += 100; // right(600) & left(500) >= min(500) --> minMax is met
823 // --> illegal
824 } else if (legal) // both sides need to violate minMax to have no
825 // eolSpacing violations
826 {
827 if (max)
828 y += 110; // right(610) & left(510) > max(500)
829 else
830 y -= 10; // right(490) & left(390) < min(500)
831 }
832 makePathseg(n1, 2, {500, 0}, {500, y});
833 makePathseg(n1, 2, {0, 700}, {1000, 700});
834
835 makePathseg(n1, 2, {0, 50}, {450, 50});
836 runGC();
837
838 // Test the results
839 auto& markers = worker.getMarkers();
840 if (legal)
841 BOOST_TEST(markers.size() == 0);
842 else {
843 BOOST_TEST(markers.size() == 1);
844 if (markers.size() == 1)
845 testMarker(markers[0].get(),
846 2,
847 frConstraintTypeEnum::frcLef58SpacingEndOfLineConstraint,
848 frBox(450, y, 550, 650));
849 }
850 }
851 BOOST_DATA_TEST_CASE(eol_enclose_cut,
852 (bdata::make({0, 350})) ^ (bdata::make({true, false})),
853 y,
854 legal)
855 {
856 addLayer(design->getTech(), "v2", frLayerTypeEnum::CUT);
857 addLayer(design->getTech(), "m2", frLayerTypeEnum::ROUTING);
858 makeLef58SpacingEolCutEncloseConstraint(makeLef58SpacingEolConstraint(4));
859 frNet* n1 = makeNet("n1");
860 frViaDef* vd = makeViaDef("v", 3, {0, 0}, {100, 100});
861
862 makePathseg(n1, 4, {500, 0}, {500, 500});
863 makePathseg(n1, 4, {0, 700}, {1000, 700});
864 auto v = makeVia(vd, n1, {400, y});
865 runGC();
866 auto& markers = worker.getMarkers();
867 if (legal)
868 BOOST_TEST(markers.size() == 0);
869 else {
870 BOOST_TEST(markers.size() == 1);
871 if (markers.size() == 1)
872 testMarker(markers[0].get(),
873 4,
874 frConstraintTypeEnum::frcLef58SpacingEndOfLineConstraint,
875 frBox(450, 500, 550, 650));
876 }
877 }
878 BOOST_AUTO_TEST_SUITE_END();
879