KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_drc_via_stack.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
20#include <fstream>
21#include <memory>
22
23#include <wx/filename.h>
24
25#include <qa_utils/file_utils.h>
28
29#include <board.h>
33#include <common.h>
34#include <lset.h>
35#include <padstack.h>
36#include <pcb_track.h>
38#include <drc/drc_engine.h>
39#include <drc/drc_item.h>
40#include <drc/drc_rule_parser.h>
42#include <reporter.h>
45
46
48{
50 std::unique_ptr<BOARD> m_board;
51
53 int m_notFilled = 0;
54 int m_depth = 0;
55 int m_aspect = 0;
57
58 std::vector<int> m_ignored;
59
60 wxFileName m_rulePath;
61
62 // The temp dir has to outlive run(), so it is kept here rather than in each test.
63 std::unique_ptr<KI_TEST::SCOPED_TEMP_DIR> m_ruleDir;
64
65 // The limits these checks read come from rules, so a test states them the way a user would.
66 void setRule( const std::string& aConstraint, const std::string& aCondition = "" )
67 {
68 m_ruleDir = std::make_unique<KI_TEST::SCOPED_TEMP_DIR>( "microvia_rule" );
69
70 wxFileName rulePath( m_ruleDir->PathStr(), "test.kicad_dru" );
71
72 {
73 std::ofstream dru( rulePath.GetFullPath().ToStdString() );
74 dru << "(version 1)\n"
75 << "(rule \"via stack limits\"\n";
76
77 if( !aCondition.empty() )
78 dru << " (condition \"" << aCondition << "\")\n";
79
80 dru << " (constraint " << aConstraint << ")\n"
81 << ")\n";
82 }
83
84 m_rulePath = rulePath;
85 }
86
87 // Cases whose subject is the stackup still build their board here: a
88 // synthesized stackup is not written to the board file, so a fixture would
89 // come back with no thicknesses and quietly test something else.
90 //
91 // Each case's board is stored under drc_via_stack/ named after the test case,
92 // so a renamed case fails loudly here rather than silently reading the wrong
93 // board. Via stacks do not exist in v10, so these fixtures are written by
94 // the development build.
95 void loadBoard()
96 {
98 KI_TEST::GetPcbnewTestDataDir() + "drc_via_stack/"
99 + boost::unit_test::framework::current_test_case().p_name.get()
100 + ".kicad_pcb" );
101
103 }
104
105
106 void run()
107 {
108 BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
109
110 if( !bds.m_DRCEngine )
111 bds.m_DRCEngine = std::make_shared<DRC_ENGINE>( m_board.get(), &bds );
112
114
115 for( int code = DRCE_FIRST; code <= DRCE_LAST; ++code )
117
123
124 for( int code : m_ignored )
126
128 [&]( const std::shared_ptr<DRC_ITEM>& aItem, const VECTOR2I&, int,
129 const std::function<void( PCB_MARKER* )>& )
130 {
131 switch( aItem->GetErrorCode() )
132 {
135 case DRCE_MICROVIA_STACK_DEPTH: m_depth++; break;
138 default: break;
139 }
140 } );
141
142 bds.m_DRCEngine->RunTests( EDA_UNITS::MM, true, false );
144 }
145};
146
147
148static PCB_VIA* makeMicrovia( BOARD* aBoard, const VECTOR2I& aPos, PCB_LAYER_ID aTop, PCB_LAYER_ID aBottom,
149 bool aFilled )
150{
151 PCB_VIA* via = new PCB_VIA( aBoard );
152 via->SetViaType( VIATYPE::MICROVIA );
153 via->SetLayerPair( aTop, aBottom );
154 via->SetWidth( PADSTACK::ALL_LAYERS, pcbIUScale.mmToIU( 0.3 ) );
155 via->SetDrill( pcbIUScale.mmToIU( 0.15 ) );
156 via->SetPosition( aPos );
157 via->Padstack().Drill().is_filled = aFilled;
158 aBoard->Add( via );
159
160 return via;
161}
162
163
164static PCB_VIA_STACK* makeStack( BOARD* aBoard, PCB_LAYER_ID aStart, PCB_LAYER_ID aEnd )
165{
166 PCB_VIA_STACK* stack = new PCB_VIA_STACK( aBoard, F_Cu );
167 stack->SetStartLayer( aStart );
168 stack->SetEndLayer( aEnd );
170 aBoard->Add( stack );
171
172 return stack;
173}
174
175
176BOOST_AUTO_TEST_SUITE( DRCViaStack )
177
178
180{
181 m_board = std::make_unique<BOARD>();
182 m_board->SetCopperLayerCount( 4 );
183 m_board->SetEnabledLayers( LSET::AllCuMask( 4 ) | LSET::AllTechMask() );
184
185 BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
186 bds.SetCopperLayerCount( 4 );
188 setRule( "microvia_aspect_ratio (max 1.0)" );
189
190 for( BOARD_STACKUP_ITEM* item : bds.GetStackupDescriptor().GetList() )
191 {
192 if( item->GetType() != BS_ITEM_TYPE_DIELECTRIC )
193 continue;
194
195 item->SetThickness( pcbIUScale.mmToIU( 0.1 ) );
196 item->SetTypeName( KEY_PREPREG );
197 }
198
199 PCB_VIA_STACK* stack = makeStack( m_board.get(), F_Cu, In2_Cu );
200 stack->SetViaSize( pcbIUScale.mmToIU( 0.3 ) );
201 stack->SetViaDrill( pcbIUScale.mmToIU( 0.15 ) );
202 stack->SetPosition( VECTOR2I( pcbIUScale.mmToIU( 10 ), pcbIUScale.mmToIU( 10 ) ) );
203 stack->Regenerate( m_board.get(), nullptr );
204
205 run();
206
207 BOOST_CHECK_EQUAL( m_malformedSpans, 0 );
208 BOOST_CHECK_EQUAL( m_notFilled, 0 );
209 BOOST_CHECK_EQUAL( m_depth, 0 );
210 BOOST_CHECK_EQUAL( m_aspect, 0 );
211 BOOST_CHECK_EQUAL( m_crossesCore, 0 );
212}
213
214
215BOOST_FIXTURE_TEST_CASE( StackNotTilingItsSpanReported, VIA_STACK_DRC_FIXTURE )
216{
217 loadBoard();
218
219 run();
220
221 BOOST_CHECK_EQUAL( m_malformedSpans, 1 );
222}
223
224
226{
227 loadBoard();
228
229 run();
230
231 BOOST_CHECK_EQUAL( m_malformedSpans, 0 );
232 BOOST_CHECK_EQUAL( m_notFilled, 1 );
233}
234
235
237{
238 loadBoard();
239
240 setRule( "microvia_stack_depth (max 1)" );
241
242 run();
243
244 BOOST_CHECK_EQUAL( m_malformedSpans, 0 );
245 BOOST_CHECK_EQUAL( m_depth, 1 );
246}
247
248
249BOOST_FIXTURE_TEST_CASE( LooseStackedMicroviasReportNotFilled, VIA_STACK_DRC_FIXTURE )
250{
251 loadBoard();
252
253 run();
254
255 BOOST_CHECK_EQUAL( m_notFilled, 1 );
256}
257
258
259BOOST_FIXTURE_TEST_CASE( LooseStackedMicroviasReportDepth, VIA_STACK_DRC_FIXTURE )
260{
261 loadBoard();
262
263 setRule( "microvia_stack_depth (max 2)" );
264
265 run();
266
267 BOOST_CHECK_EQUAL( m_depth, 1 );
268}
269
270
271// Two microvias sharing an x,y but not touching are two structures, not one three deep.
272BOOST_FIXTURE_TEST_CASE( CoaxialButSeparatedMicroviasAreNotOneStack, VIA_STACK_DRC_FIXTURE )
273{
274 loadBoard();
275
276 setRule( "microvia_stack_depth (max 1)" );
277
278 run();
279
280 BOOST_CHECK_EQUAL( m_depth, 0 );
281 BOOST_CHECK_EQUAL( m_notFilled, 0 );
282}
283
284
285// A generator stack must be judged once, not once as a generator and again as loose geometry.
286BOOST_FIXTURE_TEST_CASE( GeneratorStackIsNotReportedTwice, VIA_STACK_DRC_FIXTURE )
287{
288 loadBoard();
289
290 run();
291
292 BOOST_CHECK_EQUAL( m_notFilled, 2 );
293}
294
295
296// A hair of offset must not split one structure into two. The upper via still lands on the one
297// below, so both rules still apply.
298BOOST_FIXTURE_TEST_CASE( OverlappingButOffsetMicroviasAreOneStructure, VIA_STACK_DRC_FIXTURE )
299{
300 loadBoard();
301
302 run();
303
304 BOOST_CHECK_EQUAL( m_notFilled, 1 );
305}
306
307
308// A real stagger clears the via below, so the fill rule does not apply to it.
309BOOST_FIXTURE_TEST_CASE( ClearOfTheViaBelowIsAStaggerNotAStack, VIA_STACK_DRC_FIXTURE )
310{
311 loadBoard();
312
313 run();
314
315 BOOST_CHECK_EQUAL( m_notFilled, 0 );
316 BOOST_CHECK_EQUAL( m_depth, 0 );
317}
318
319
320// IPC-6012 requires the hops of a stacked microvia to be filled. That applies to the whole
321// structure and not only to the ones carrying another hop.
322BOOST_FIXTURE_TEST_CASE( EveryHopOfAStackMustBeFilled, VIA_STACK_DRC_FIXTURE )
323{
324 loadBoard();
325
326 run();
327
328 BOOST_CHECK_EQUAL( m_notFilled, 2 );
329}
330
331
332// A lone microvia carries nothing, so it may be unfilled.
333BOOST_FIXTURE_TEST_CASE( ALoneMicroviaMayBeUnfilled, VIA_STACK_DRC_FIXTURE )
334{
335 loadBoard();
336
337 run();
338
339 BOOST_CHECK_EQUAL( m_notFilled, 0 );
340}
341
342
343// IPC-2226 caps a microvia at 1:1. A default 6 layer stackup has dielectrics far thicker than a
344// 0.1 mm hole, so a microvia across one is well outside that.
345BOOST_FIXTURE_TEST_CASE( MicroviaTooDeepForItsDiameterIsReported, VIA_STACK_DRC_FIXTURE )
346{
347 m_board = std::make_unique<BOARD>();
348 m_board->SetCopperLayerCount( 6 );
349 m_board->SetEnabledLayers( LSET::AllCuMask( 6 ) | LSET::AllTechMask() );
350
351 BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
352 bds.SetCopperLayerCount( 6 );
354 setRule( "microvia_aspect_ratio (max 1.0)" );
355
356 makeMicrovia( m_board.get(), VECTOR2I( pcbIUScale.mmToIU( 10 ), pcbIUScale.mmToIU( 10 ) ), F_Cu, In1_Cu, true );
357
358 run();
359
360 BOOST_CHECK_EQUAL( m_aspect, 1 );
361}
362
363
364// With no limit set the check says nothing, however thick the dielectric.
365BOOST_FIXTURE_TEST_CASE( AspectRatioIsSilentWithoutALimit, VIA_STACK_DRC_FIXTURE )
366{
367 m_board = std::make_unique<BOARD>();
368 m_board->SetCopperLayerCount( 6 );
369 m_board->SetEnabledLayers( LSET::AllCuMask( 6 ) | LSET::AllTechMask() );
370
371 BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
372 bds.SetCopperLayerCount( 6 );
374
375
376 makeMicrovia( m_board.get(), VECTOR2I( pcbIUScale.mmToIU( 10 ), pcbIUScale.mmToIU( 10 ) ), F_Cu, In1_Cu, true );
377
378 run();
379
380 BOOST_CHECK_EQUAL( m_aspect, 0 );
381
382 // The same via violates once a limit exists, so the silence came from the missing limit.
383 m_aspect = 0;
384 setRule( "microvia_aspect_ratio (max 1.0)" );
385
386 run();
387
388 BOOST_CHECK_EQUAL( m_aspect, 1 );
389}
390
391
392// The aspect ratio check is independent of the other three, so silencing them must not
393// silence it.
394BOOST_FIXTURE_TEST_CASE( AspectRatioSurvivesTheOtherChecksBeingIgnored, VIA_STACK_DRC_FIXTURE )
395{
396 m_board = std::make_unique<BOARD>();
397 m_board->SetCopperLayerCount( 6 );
398 m_board->SetEnabledLayers( LSET::AllCuMask( 6 ) | LSET::AllTechMask() );
399
400 BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
401 bds.SetCopperLayerCount( 6 );
403 setRule( "microvia_aspect_ratio (max 1.0)" );
404
406
407 makeMicrovia( m_board.get(), VECTOR2I( pcbIUScale.mmToIU( 10 ), pcbIUScale.mmToIU( 10 ) ), F_Cu, In1_Cu, true );
408
409 run();
410
411 BOOST_CHECK_EQUAL( m_aspect, 1 );
412}
413
414
415// Without a stackup there are no thicknesses to divide, so the check stands down.
416// With stackup thicknesses to divide, the limit applies; with none, the check stands down.
417BOOST_FIXTURE_TEST_CASE( AspectRatioNeedsStackupThicknesses, VIA_STACK_DRC_FIXTURE )
418{
419 m_board = std::make_unique<BOARD>();
420 m_board->SetCopperLayerCount( 4 );
421 m_board->SetEnabledLayers( LSET::AllCuMask( 4 ) | LSET::AllTechMask() );
422
423 BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
424 setRule( "microvia_aspect_ratio (max 0.5)" );
425
426 VECTOR2I at( pcbIUScale.mmToIU( 10 ), pcbIUScale.mmToIU( 10 ) );
427 makeMicrovia( m_board.get(), at, F_Cu, In1_Cu, true );
428
429 // No stackup list at all, so there is nothing to measure.
430 run();
431 BOOST_CHECK_EQUAL( m_aspect, 0 );
432
433 // The same via against a real stackup exceeds the same limit.
434 m_aspect = 0;
435 bds.SetCopperLayerCount( 4 );
437 run();
438 BOOST_CHECK_MESSAGE( m_aspect == 1, "with thicknesses present the limit must apply" );
439}
440
441
442BOOST_FIXTURE_TEST_CASE( MicroviaStackDepthRuleIsHonoured, VIA_STACK_DRC_FIXTURE )
443{
444 loadBoard();
445
446 setRule( "microvia_stack_depth (max 2)" );
447
448 run();
449 BOOST_CHECK_EQUAL( m_depth, 1 );
450
451 m_depth = 0;
452 setRule( "microvia_stack_depth (max 4)" );
453
454 // A rule that allows four leaves the same three hops alone.
455 run();
456 BOOST_CHECK_EQUAL( m_depth, 0 );
457
458 // With a condition the rule still has to match, so a limit of two bites again.
459 m_depth = 0;
460 setRule( "microvia_stack_depth (max 2)", "A.isStackedVia()" );
461
462 run();
463 BOOST_CHECK_MESSAGE( m_depth == 1, "the rule condition did not select the stack" );
464}
465
466
467// A microvia whose two layers are the same spans no dielectric. Such vias point at each other
468// in the chain walk, so a handful of them must not multiply into a pile of violations.
469BOOST_FIXTURE_TEST_CASE( ZeroSpanMicroviasDoNotMultiplyViolations, VIA_STACK_DRC_FIXTURE )
470{
471 loadBoard();
472
473 run();
474
475 // A via spanning one layer forms no column, so there is nothing to report at all.
476 BOOST_CHECK_MESSAGE( m_notFilled == 0, "3 vias produced " << m_notFilled << " violations" );
477}
478
479
480// A dielectric built from several sublayers is as deep as all of them together.
481BOOST_FIXTURE_TEST_CASE( AspectRatioCountsEveryDielectricSublayer, VIA_STACK_DRC_FIXTURE )
482{
483 m_board = std::make_unique<BOARD>();
484 m_board->SetCopperLayerCount( 6 );
485 m_board->SetEnabledLayers( LSET::AllCuMask( 6 ) | LSET::AllTechMask() );
486
487 BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
488 bds.SetCopperLayerCount( 6 );
490
491 // Split the dielectric under F.Cu into two 0.1 mm sublayers.
492 for( BOARD_STACKUP_ITEM* item : bds.GetStackupDescriptor().GetList() )
493 {
494 if( item->GetType() != BS_ITEM_TYPE_DIELECTRIC )
495 continue;
496
497 item->AddDielectricPrms( 1 );
498 item->SetThickness( pcbIUScale.mmToIU( 0.1 ), 0 );
499 item->SetThickness( pcbIUScale.mmToIU( 0.1 ), 1 );
500 break;
501 }
502
503 // 0.2 mm of dielectric over a 0.15 mm drill is a ratio above 1, one sublayer alone is not.
504 setRule( "microvia_aspect_ratio (max 1.2)" );
505
506 makeMicrovia( m_board.get(), VECTOR2I( pcbIUScale.mmToIU( 10 ), pcbIUScale.mmToIU( 10 ) ), F_Cu, In1_Cu, true );
507
508 run();
509
510 BOOST_CHECK_MESSAGE( m_aspect == 1, "both sublayers must count toward the via depth" );
511}
512
513
514// A microvia reaching B.Cu is drilled from the back, so it passes through the B.Cu foil.
515BOOST_FIXTURE_TEST_CASE( AspectRatioUsesTheFoilTheLaserEnters, VIA_STACK_DRC_FIXTURE )
516{
517 m_board = std::make_unique<BOARD>();
518 m_board->SetCopperLayerCount( 6 );
519 m_board->SetEnabledLayers( LSET::AllCuMask( 6 ) | LSET::AllTechMask() );
520
521 BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
522 bds.SetCopperLayerCount( 6 );
524
525 const std::vector<BOARD_STACKUP_ITEM*>& stack = bds.GetStackupDescriptor().GetList();
526
527 // 1 oz outer foil, half that inside, and a known dielectric between In4.Cu and B.Cu.
528 for( BOARD_STACKUP_ITEM* item : stack )
529 {
530 if( item->GetType() != BS_ITEM_TYPE_COPPER )
531 continue;
532
533 bool outer = item->GetBrdLayerId() == F_Cu || item->GetBrdLayerId() == B_Cu;
534 item->SetThickness( pcbIUScale.mmToIU( outer ? 0.035 : 0.0175 ) );
535 }
536
537 for( int i = (int) stack.size() - 1; i >= 0; --i )
538 {
539 if( stack[i]->GetType() == BS_ITEM_TYPE_DIELECTRIC )
540 {
541 stack[i]->SetThickness( pcbIUScale.mmToIU( 0.1 ) );
542 break;
543 }
544 }
545
546 // Through the B.Cu foil the depth is 0.135 mm over a 0.1 mm drill, a ratio of 1.35.
547 // Through the In4.Cu foil it would read 1.175 and slip under the limit.
548 setRule( "microvia_aspect_ratio (max 1.25)" );
549
550 PCB_VIA* via = makeMicrovia( m_board.get(), VECTOR2I( pcbIUScale.mmToIU( 10 ), pcbIUScale.mmToIU( 10 ) ), In4_Cu,
551 B_Cu, true );
552 via->SetDrill( pcbIUScale.mmToIU( 0.1 ) );
553
554 run();
555
556 BOOST_CHECK_MESSAGE( m_aspect == 1, "a back-side microvia must be measured through the B.Cu foil" );
557}
558
559
560// An unset fill means "use the board default", not "unfilled".
561BOOST_FIXTURE_TEST_CASE( FillFromBoardHonoursTheBoardDefault, VIA_STACK_DRC_FIXTURE )
562{
563 loadBoard();
564
565 run();
566
567 BOOST_CHECK_MESSAGE( m_notFilled == 0, "board default is filled, but got " << m_notFilled << " not-filled errors" );
568}
569
570
571// Two overlapping hops can both land on the one below them, and it must not be reported once
572// for each.
573BOOST_FIXTURE_TEST_CASE( AViaCarriedTwiceIsReportedOnce, VIA_STACK_DRC_FIXTURE )
574{
575 loadBoard();
576
577 run();
578
579 BOOST_CHECK_EQUAL( m_notFilled, 1 );
580}
581
582
583// Holes a drill diameter apart touch, leaving no wall between them.
585{
586 loadBoard();
587
588 run();
589
590 BOOST_CHECK_EQUAL( m_notFilled, 1 );
591}
592
593
594// Laser drilling needs the resin to ablate, so a microvia belongs in the build-up layers
595// rather than through the glass reinforced core.
596BOOST_FIXTURE_TEST_CASE( MicroviaThroughCoreIsReported, VIA_STACK_DRC_FIXTURE )
597{
598 m_board = std::make_unique<BOARD>();
599 m_board->SetCopperLayerCount( 6 );
600 m_board->SetEnabledLayers( LSET::AllCuMask( 6 ) | LSET::AllTechMask() );
601
602 BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
603 bds.SetCopperLayerCount( 6 );
605
606 const std::vector<BOARD_STACKUP_ITEM*>& stack = bds.GetStackupDescriptor().GetList();
607
608 // Name the copper layers either side of the first core, and of the first prepreg.
609 PCB_LAYER_ID coreTop = UNDEFINED_LAYER, coreBot = UNDEFINED_LAYER;
610 PCB_LAYER_ID pregTop = UNDEFINED_LAYER, pregBot = UNDEFINED_LAYER;
611 PCB_LAYER_ID lastCopper = UNDEFINED_LAYER;
612
613 for( size_t i = 0; i < stack.size(); ++i )
614 {
615 if( stack[i]->GetType() == BS_ITEM_TYPE_COPPER )
616 {
617 lastCopper = stack[i]->GetBrdLayerId();
618 continue;
619 }
620
621 if( stack[i]->GetType() != BS_ITEM_TYPE_DIELECTRIC )
622 continue;
623
625
626 for( size_t j = i + 1; j < stack.size(); ++j )
627 {
628 if( stack[j]->GetType() == BS_ITEM_TYPE_COPPER )
629 {
630 below = stack[j]->GetBrdLayerId();
631 break;
632 }
633 }
634
635 if( stack[i]->GetTypeName() == KEY_CORE && coreTop == UNDEFINED_LAYER )
636 {
637 coreTop = lastCopper;
638 coreBot = below;
639 }
640 else if( stack[i]->GetTypeName() == KEY_PREPREG && pregTop == UNDEFINED_LAYER )
641 {
642 pregTop = lastCopper;
643 pregBot = below;
644 }
645 }
646
647 BOOST_REQUIRE( coreTop != UNDEFINED_LAYER && coreBot != UNDEFINED_LAYER );
648 BOOST_REQUIRE( pregTop != UNDEFINED_LAYER && pregBot != UNDEFINED_LAYER );
649
650 VECTOR2I overCore( pcbIUScale.mmToIU( 10 ), pcbIUScale.mmToIU( 10 ) );
651 VECTOR2I overPrepreg( pcbIUScale.mmToIU( 30 ), pcbIUScale.mmToIU( 10 ) );
652
653 makeMicrovia( m_board.get(), overCore, coreTop, coreBot, true );
654 makeMicrovia( m_board.get(), overPrepreg, pregTop, pregBot, true );
655
656 run();
657
658 // Only the one crossing core is reported, and it does not need an aspect ratio limit set.
659 BOOST_CHECK_EQUAL( m_crossesCore, 1 );
660}
661
662
663// Two hops landing on one shared via below are two structures. The second must still be
664// fill checked rather than dropped for sharing.
665BOOST_FIXTURE_TEST_CASE( ASecondHopSharingALandingViaIsStillChecked, VIA_STACK_DRC_FIXTURE )
666{
667 loadBoard();
668
669 run();
670
671 BOOST_CHECK_EQUAL( m_notFilled, 2 );
672}
673
674
675// The core check shares the aspect ratio walk, so an exhausted aspect limit must not end it.
676BOOST_FIXTURE_TEST_CASE( AnIgnoredAspectRatioDoesNotStopTheCoreCheck, VIA_STACK_DRC_FIXTURE )
677{
678 m_board = std::make_unique<BOARD>();
679 m_board->SetCopperLayerCount( 6 );
680 m_board->SetEnabledLayers( LSET::AllCuMask( 6 ) | LSET::AllTechMask() );
681
682 BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
683 bds.SetCopperLayerCount( 6 );
685
686 // A limit is set, but its severity is off. The first via would otherwise end the walk.
687 setRule( "microvia_aspect_ratio (max 0.1)" );
688 m_ignored = { DRCE_MICROVIA_ASPECT_RATIO };
689
690 const std::vector<BOARD_STACKUP_ITEM*>& stack = bds.GetStackupDescriptor().GetList();
691 PCB_LAYER_ID coreTop = UNDEFINED_LAYER, coreBot = UNDEFINED_LAYER, lastCopper = UNDEFINED_LAYER;
692
693 for( size_t i = 0; i < stack.size(); ++i )
694 {
695 if( stack[i]->GetType() == BS_ITEM_TYPE_COPPER )
696 {
697 lastCopper = stack[i]->GetBrdLayerId();
698 continue;
699 }
700
701 if( stack[i]->GetType() == BS_ITEM_TYPE_DIELECTRIC && stack[i]->GetTypeName() == KEY_CORE
702 && coreTop == UNDEFINED_LAYER )
703 {
704 coreTop = lastCopper;
705
706 for( size_t j = i + 1; j < stack.size(); ++j )
707 {
708 if( stack[j]->GetType() == BS_ITEM_TYPE_COPPER )
709 {
710 coreBot = stack[j]->GetBrdLayerId();
711 break;
712 }
713 }
714 }
715 }
716
717 BOOST_REQUIRE( coreTop != UNDEFINED_LAYER && coreBot != UNDEFINED_LAYER );
718
719 makeMicrovia( m_board.get(), VECTOR2I( pcbIUScale.mmToIU( 10 ), pcbIUScale.mmToIU( 10 ) ), coreTop, coreBot, true );
720 makeMicrovia( m_board.get(), VECTOR2I( pcbIUScale.mmToIU( 30 ), pcbIUScale.mmToIU( 10 ) ), coreTop, coreBot, true );
721
722 run();
723
724 BOOST_CHECK_EQUAL( m_aspect, 0 );
725 BOOST_CHECK_MESSAGE( m_crossesCore == 2, "the walk stopped early, only " << m_crossesCore << " reported" );
726}
727
728
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:121
General utilities for PCB file IO for QA programs.
@ BS_ITEM_TYPE_COPPER
@ BS_ITEM_TYPE_DIELECTRIC
Container for design settings for a BOARD object.
std::map< int, SEVERITY > m_DRCSeverities
std::shared_ptr< DRC_ENGINE > m_DRCEngine
BOARD_STACKUP & GetStackupDescriptor()
void SetCopperLayerCount(int aNewLayerCount)
Set the copper layer count to aNewLayerCount.
Manage one layer needed to make a physical board.
const std::vector< BOARD_STACKUP_ITEM * > & GetList() const
void BuildDefaultStackupList(const BOARD_DESIGN_SETTINGS *aSettings, int aActiveCopperLayersCount=0)
Create a default stackup, according to the current BOARD_DESIGN_SETTINGS settings.
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:409
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
Definition board.cpp:1497
void RunTests(EDA_UNITS aUnits, bool aReportAllTrackErrors, bool aTestFootprints, BOARD_COMMIT *aCommit=nullptr)
Run the DRC tests.
void SetViolationHandler(DRC_VIOLATION_HANDLER aHandler)
Set an optional DRC violation handler (receives DRC_ITEMs and positions).
Definition drc_engine.h:164
void ClearViolationHandler()
Definition drc_engine.h:169
void InitEngine(const wxFileName &aRulePath)
Initialize the DRC engine.
static const LSET & AllTechMask()
Return a mask holding all technical layers (no CU layer) on both side.
Definition lset.cpp:672
static LSET AllCuMask(int aCuLayerCount)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition lset.cpp:595
static constexpr PCB_LAYER_ID ALL_LAYERS
! The layer identifier to use for the single defintion on normal padstacks
Definition padstack.h:179
void SetPosition(const VECTOR2I &aPos) override
A microvia stack: several single hop microvias, plus connecting traces for staggered stacks,...
void Regenerate(BOARD *aBoard, BOARD_COMMIT *aCommit)
Rebuild the member vias (and, for a staggered stack, the connecting traces) from the current stack se...
void SetStartLayer(PCB_LAYER_ID aLayer)
void SetViaSize(int aSize)
void SetViaDrill(int aDrill)
void SetStyle(VIA_STACK_STYLE aStyle)
void SetEndLayer(PCB_LAYER_ID aLayer)
@ DRCE_MICROVIA_STACK_DEPTH
Definition drc_item.h:65
@ DRCE_MICROVIA_CROSSES_CORE
Definition drc_item.h:67
@ DRCE_MALFORMED_MICROVIA_STACK_SPAN
Definition drc_item.h:63
@ DRCE_MICROVIA_ASPECT_RATIO
Definition drc_item.h:66
@ DRCE_MICROVIA_STACK_NOT_FILLED
Definition drc_item.h:64
@ DRCE_FIRST
Definition drc_item.h:36
@ DRCE_LAST
Definition drc_item.h:131
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:56
@ B_Cu
Definition layer_ids.h:61
@ In2_Cu
Definition layer_ids.h:63
@ In4_Cu
Definition layer_ids.h:65
@ UNDEFINED_LAYER
Definition layer_ids.h:57
@ In1_Cu
Definition layer_ids.h:62
@ F_Cu
Definition layer_ids.h:60
std::string GetPcbnewTestDataDir()
Utility which returns a path to the data directory where the test board files are stored.
std::unique_ptr< BOARD > ReadBoardFromFileOrStream(const std::string &aFilename, std::istream &aFallback)
Read a board from a file, or another stream, as appropriate.
@ RPT_SEVERITY_WARNING
@ RPT_SEVERITY_ERROR
@ RPT_SEVERITY_IGNORE
#define KEY_PREPREG
#define KEY_CORE
std::unique_ptr< BOARD > m_board
SETTINGS_MANAGER m_settingsManager
std::vector< int > m_ignored
void setRule(const std::string &aConstraint, const std::string &aCondition="")
std::unique_ptr< KI_TEST::SCOPED_TEMP_DIR > m_ruleDir
BOOST_FIXTURE_TEST_CASE(ServerStartsAndResponds, API_SERVER_E2E_FIXTURE)
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
static PCB_VIA_STACK * makeStack(BOARD *aBoard, PCB_LAYER_ID aStart, PCB_LAYER_ID aEnd)
static PCB_VIA * makeMicrovia(BOARD *aBoard, const VECTOR2I &aPos, PCB_LAYER_ID aTop, PCB_LAYER_ID aBottom, bool aFilled)
BOOST_FIXTURE_TEST_CASE(GoodStackNoViolations, VIA_STACK_DRC_FIXTURE)
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_AUTO_TEST_SUITE_END()
BOOST_CHECK_EQUAL(result, "25.4")
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683