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