KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_drc_tuner_chain_bridging_agreement.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, you may find one here:
18 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19 */
20
21#include <boost/test/unit_test.hpp>
22
23#include <memory>
24
25#include <board.h>
26#include <footprint.h>
27#include <pad.h>
28#include <padstack.h>
29#include <pcb_generator.h>
30#include <pcb_track.h>
32#include <net_chain_bridging.h>
33#include <netinfo.h>
34
35
36// Regression coverage for the H-8 review finding: DRC's matched-length provider and the
37// tuning-pattern generator must agree on which footprints bridge a chain and by how much.
38//
39// Pre-fix the two engines diverged.
40// DRC counted chain pads and skipped only when fewer than two existed, then summed the
41// max pairwise cross-net pad span.
42// The tuner counted unique netcodes via std::map<int, PAD*>, skipped when more than two
43// distinct codes were seen, and otherwise added the distance between two arbitrary
44// "first seen" pads.
45//
46// A 3-pad / 2-net device (centre-tap ferrite bead) bridged in the tuner with the wrong
47// pad pair, and a 3-pad / 3-net device (transformer) was silently dropped by the tuner
48// while DRC still scored it. The shared helper FootprintChainBridgingLength now drives
49// both engines, so this test pins down their identical answers across the cases that
50// previously diverged.
51
52
53namespace
54{
55
56constexpr double EPS_IU = 1.0;
57constexpr int PAD_SIZE_NM = 500'000; // 0.5 mm in nm
58
59
60PAD* addPad( FOOTPRINT* aFp, NETINFO_ITEM* aNet, const VECTOR2I& aPos )
61{
62 PAD* pad = new PAD( aFp );
64 pad->SetSize( PADSTACK::ALL_LAYERS, VECTOR2I( PAD_SIZE_NM, PAD_SIZE_NM ) );
65 pad->SetPosition( aPos );
66 pad->SetNet( aNet );
67 aFp->Add( pad );
68 return pad;
69}
70
71
72NETINFO_ITEM* addNet( BOARD* aBoard, const wxString& aName, int aCode, const wxString& aChain )
73{
74 NETINFO_ITEM* n = new NETINFO_ITEM( aBoard, aName, aCode );
75 n->SetNetChain( aChain );
76 aBoard->Add( n );
77 return n;
78}
79
80
81FOOTPRINT* addFootprint( BOARD* aBoard )
82{
83 FOOTPRINT* fp = new FOOTPRINT( aBoard );
84 aBoard->Add( fp );
85 return fp;
86}
87
88
89// Drive the tuner cache through one full miss-then-hit cycle and return its bridging.
90// PCB_TUNING_PATTERN holds private cache state but exposes GetCachedBridgingLength as
91// the read path actually used by the generator.
92long long tunerBridging( BOARD* aBoard, const wxString& aChain )
93{
95 return tuner.GetCachedBridgingLength( aBoard, aChain, nullptr );
96}
97
98} // namespace
99
100
101BOOST_AUTO_TEST_SUITE( DRCTunerChainBridgingAgreement )
102
103
104// Two-pad two-net footprint. Both engines have always scored this case; included as a
105// sanity baseline for the cases that follow.
106BOOST_AUTO_TEST_CASE( TwoPadTwoNetFootprintAgrees )
107{
108 BOARD board;
109
110 NETINFO_ITEM* netA = addNet( &board, wxS( "/A" ), 1, wxS( "SIG" ) );
111 NETINFO_ITEM* netB = addNet( &board, wxS( "/B" ), 2, wxS( "SIG" ) );
112
113 FOOTPRINT* fp = addFootprint( &board );
114 addPad( fp, netA, VECTOR2I( -1'000'000, 0 ) ); // -1 mm
115 addPad( fp, netB, VECTOR2I( 1'000'000, 0 ) ); // +1 mm
116
117 double drcLen = BoardChainBridgingLength( &board, wxS( "SIG" ) );
118 long long tunerLen = tunerBridging( &board, wxS( "SIG" ) );
119
120 BOOST_CHECK_CLOSE( drcLen, 2'000'000.0, 0.001 );
121 BOOST_CHECK_LE( std::abs( drcLen - static_cast<double>( tunerLen ) ), EPS_IU );
122}
123
124
125// Three-pad two-net (centre-tap bead / split inductor): pre-fix the tuner picked the
126// first-seen pad on each net, so the reported span depended on pad iteration order
127// rather than the worst-case bridge. DRC always took the max pairwise span.
128BOOST_AUTO_TEST_CASE( ThreePadTwoNetFootprintAgrees )
129{
130 BOARD board;
131
132 NETINFO_ITEM* netA = addNet( &board, wxS( "/A" ), 1, wxS( "SIG" ) );
133 NETINFO_ITEM* netB = addNet( &board, wxS( "/B" ), 2, wxS( "SIG" ) );
134
135 FOOTPRINT* fp = addFootprint( &board );
136 addPad( fp, netA, VECTOR2I( -2'500'000, 0 ) ); // -2.5 mm net A
137 addPad( fp, netA, VECTOR2I( 0, 0 ) ); // 0 mm net A
138 addPad( fp, netB, VECTOR2I( 2'500'000, 0 ) ); // +2.5 mm net B
139
140 double drcLen = BoardChainBridgingLength( &board, wxS( "SIG" ) );
141 long long tunerLen = tunerBridging( &board, wxS( "SIG" ) );
142
143 // Max pairwise cross-net span is from -2.5 mm (A) to +2.5 mm (B) = 5 mm.
144 BOOST_CHECK_CLOSE( drcLen, 5'000'000.0, 0.001 );
145 BOOST_CHECK_LE( std::abs( drcLen - static_cast<double>( tunerLen ) ), EPS_IU );
146}
147
148
149// Three-pad three-net (transformer-style): pre-fix the tuner saw size > 2 and silently
150// dropped the footprint (returning 0), while DRC still added the worst-case cross-net
151// span. The fix makes both report the max pairwise span.
152BOOST_AUTO_TEST_CASE( ThreePadThreeNetFootprintAgrees )
153{
154 BOARD board;
155
156 NETINFO_ITEM* netA = addNet( &board, wxS( "/A" ), 1, wxS( "SIG" ) );
157 NETINFO_ITEM* netB = addNet( &board, wxS( "/B" ), 2, wxS( "SIG" ) );
158 NETINFO_ITEM* netC = addNet( &board, wxS( "/C" ), 3, wxS( "SIG" ) );
159
160 FOOTPRINT* fp = addFootprint( &board );
161 addPad( fp, netA, VECTOR2I( -2'500'000, 0 ) ); // -2.5 mm net A
162 addPad( fp, netB, VECTOR2I( 0, 0 ) ); // 0 mm net B
163 addPad( fp, netC, VECTOR2I( 2'500'000, 0 ) ); // +2.5 mm net C
164
165 double drcLen = BoardChainBridgingLength( &board, wxS( "SIG" ) );
166 long long tunerLen = tunerBridging( &board, wxS( "SIG" ) );
167
168 // Max pairwise cross-net span is -2.5 mm (A) to +2.5 mm (C) = 5 mm. Pre-fix the
169 // tuner returned 0 here; agreement is the regression we are pinning down.
170 BOOST_CHECK_CLOSE( drcLen, 5'000'000.0, 0.001 );
171 BOOST_CHECK_GT( tunerLen, 0 );
172 BOOST_CHECK_LE( std::abs( drcLen - static_cast<double>( tunerLen ) ), EPS_IU );
173}
174
175
176// Four-pad two-net: max cross-net pairwise span exceeds the "first seen on each net"
177// pair the tuner used to pick. Pads at -3, -1, +1, +3 mm with nets A, A, B, B; max
178// span is from -3 mm (A) to +3 mm (B) = 6 mm.
179BOOST_AUTO_TEST_CASE( FourPadTwoNetFootprintAgrees )
180{
181 BOARD board;
182
183 NETINFO_ITEM* netA = addNet( &board, wxS( "/A" ), 1, wxS( "SIG" ) );
184 NETINFO_ITEM* netB = addNet( &board, wxS( "/B" ), 2, wxS( "SIG" ) );
185
186 FOOTPRINT* fp = addFootprint( &board );
187 addPad( fp, netA, VECTOR2I( -3'000'000, 0 ) );
188 addPad( fp, netA, VECTOR2I( -1'000'000, 0 ) );
189 addPad( fp, netB, VECTOR2I( 1'000'000, 0 ) );
190 addPad( fp, netB, VECTOR2I( 3'000'000, 0 ) );
191
192 double drcLen = BoardChainBridgingLength( &board, wxS( "SIG" ) );
193 long long tunerLen = tunerBridging( &board, wxS( "SIG" ) );
194
195 BOOST_CHECK_CLOSE( drcLen, 6'000'000.0, 0.001 );
196 BOOST_CHECK_LE( std::abs( drcLen - static_cast<double>( tunerLen ) ), EPS_IU );
197}
198
199
200// Three-pad single-net footprint: no cross-net bridging is possible. Both engines
201// must contribute zero so a star-tied device cannot inflate chain length.
202BOOST_AUTO_TEST_CASE( ThreePadSingleNetFootprintAgreesAtZero )
203{
204 BOARD board;
205
206 NETINFO_ITEM* netA = addNet( &board, wxS( "/A" ), 1, wxS( "SIG" ) );
207
208 FOOTPRINT* fp = addFootprint( &board );
209 addPad( fp, netA, VECTOR2I( -2'000'000, 0 ) );
210 addPad( fp, netA, VECTOR2I( 0, 0 ) );
211 addPad( fp, netA, VECTOR2I( 2'000'000, 0 ) );
212
213 double drcLen = BoardChainBridgingLength( &board, wxS( "SIG" ) );
214 long long tunerLen = tunerBridging( &board, wxS( "SIG" ) );
215
216 BOOST_CHECK_EQUAL( drcLen, 0.0 );
217 BOOST_CHECK_EQUAL( tunerLen, 0 );
218}
219
220
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:323
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
Definition board.cpp:1247
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
Handle the data for a net.
Definition netinfo.h:50
void SetNetChain(const wxString &aNetChain)
Definition netinfo.h:116
static constexpr PCB_LAYER_ID ALL_LAYERS
! Temporary layer identifier to identify code that is not padstack-aware
Definition padstack.h:177
Definition pad.h:55
long long GetCachedBridgingLength(BOARD *aBoard, const wxString &aNetChain, double *aDelayIUOut)
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition eda_angle.h:400
double BoardChainBridgingLength(const BOARD *aBoard, const wxString &aNetChain)
Sum chain bridging length across every footprint on the board.
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
BOOST_AUTO_TEST_CASE(TwoPadTwoNetFootprintAgrees)
BOOST_AUTO_TEST_SUITE_END()
BOOST_CHECK_EQUAL(result, "25.4")
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:687