KiCad PCB EDA Suite
Loading...
Searching...
No Matches
pns_meander_placer.cpp
Go to the documentation of this file.
1/*
2 * KiRouter - a push-and-(sometimes-)shove PCB router
3 *
4 * Copyright (C) 2013-2015 CERN
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 * Author: Tomasz Wlostowski <[email protected]>
7 *
8 * This program is free software: you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation, either version 3 of the License, or (at your
11 * option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 */
21
22#include "pns_debug_decorator.h"
23#include "pns_itemset.h"
24#include "pns_meander_placer.h"
25
26#include "pns_helpers.h"
27#include "pns_node.h"
28#include "pns_router.h"
29#include "pns_solid.h"
30#include "pns_topology.h"
31
33#include <algorithm>
34
36
37namespace PNS {
38
40 MEANDER_PLACER_BASE( aRouter )
41{
42 m_currentNode = nullptr;
43
44 // Init temporary variables (do not leave uninitialized members)
45 m_initialSegment = nullptr;
46 m_lastLength = 0;
47 m_lastDelay = 0;
51 m_netClass = nullptr;
52}
53
54
58
59
60NODE* MEANDER_PLACER::CurrentNode( bool aLoopsRemoved ) const
61{
62 if( !m_currentNode )
63 return m_world;
64
65 return m_currentNode;
66}
67
68
69bool MEANDER_PLACER::Start( const VECTOR2I& aP, ITEM* aStartItem )
70{
71 if( !aStartItem || !aStartItem->OfKind( ITEM::SEGMENT_T | ITEM::ARC_T ) )
72 {
73 Router()->SetFailureReason( _( "Please select a track whose length you want to tune." ) );
74 return false;
75 }
76
77 m_initialSegment = static_cast<LINKED_ITEM*>( aStartItem );
78 m_currentNode = nullptr;
80
81 m_world = Router()->GetWorld()->Branch();
82 m_originLine = m_world->AssembleLine( m_initialSegment );
83
84 TOPOLOGY topo( m_world );
86
89
90 if( m_startPad_n )
91 {
92 m_padToDieLength += m_startPad_n->GetPadToDie();
93 m_padToDieDelay += m_startPad_n->GetPadToDieDelay();
94 }
95
96 if( m_endPad_n )
97 {
98 m_padToDieLength += m_endPad_n->GetPadToDie();
99 m_padToDieDelay += m_endPad_n->GetPadToDieDelay();
100 }
101
102 m_world->Remove( m_originLine );
103
105 m_currentEnd = VECTOR2I( 0, 0 );
106
107 const BOARD_CONNECTED_ITEM* conItem = static_cast<BOARD_CONNECTED_ITEM*>( aStartItem->GetSourceItem() );
108 m_netClass = conItem->GetEffectiveNetClass();
109
112 m_baselineDelay = m_settings.m_isTimeDomain ? origPathDelay() : 0;
113 m_hasBaseline = true;
114
116
118
119 return true;
120}
121
122
124{
125 return m_padToDieLength + m_settings.m_signalExtraLength
127}
128
129
131{
132 return m_padToDieDelay + m_settings.m_signalExtraDelay
134}
135
136
138{
139 // If this is a time domain tuning, calculate the target length for the desired total delay
140 if( m_settings.m_isTimeDomain )
141 {
142 // curDelayChain includes other nets (chain aggregate). curDelayNet excludes extras.
143 const int64_t curDelayChain = origPathDelay();
144 const int64_t curDelayNet = curDelayChain - m_settings.m_signalExtraDelay;
145
146 // Prefer chain-level target if explicitly set (i.e. not unconstrained and differs from net target)
147 bool useSignalTarget = ( m_settings.m_targetSignalLengthDelay.Opt() != MEANDER_SETTINGS::DELAY_UNCONSTRAINED );
148
149 const MINOPTMAX<long long int>& targetDelaySet = useSignalTarget ? m_settings.m_targetSignalLengthDelay
150 : m_settings.m_targetLengthDelay;
151
152 // Desired overall chain delay values
153 int64_t desiredDelayMin = targetDelaySet.Min();
154 int64_t desiredDelayOpt = targetDelaySet.Opt();
155 int64_t desiredDelayMax = targetDelaySet.Max();
156
157 // If using chain target, convert desired overall chain delay into desired per-net contribution
158 if( useSignalTarget )
159 {
160 desiredDelayMin = std::max<int64_t>( 0, desiredDelayMin - m_settings.m_signalExtraDelay );
161 desiredDelayOpt = std::max<int64_t>( 0, desiredDelayOpt - m_settings.m_signalExtraDelay );
162 desiredDelayMax = std::max<int64_t>( desiredDelayOpt, desiredDelayMax - m_settings.m_signalExtraDelay );
163 }
164
165 // Current delay basis for comparison (per-net when using chain target else aggregate)
166 const int64_t curDelay = useSignalTarget ? curDelayNet : curDelayChain;
167
168 const int64_t delayDifferenceOpt = desiredDelayOpt - curDelay;
169
170 const int64_t curLength = origPathLength();
171 const int64_t lengthDiffMin = m_router->GetInterface()->CalculateLengthForDelay(
172 desiredDelayOpt - desiredDelayMin, m_currentWidth, false, m_router->Sizes().DiffPairGap(),
173 m_router->GetCurrentLayer(), m_netClass );
174 int64_t lengthDiffOpt = m_router->GetInterface()->CalculateLengthForDelay(
175 std::abs( delayDifferenceOpt ), m_currentWidth, false, m_router->Sizes().DiffPairGap(),
176 m_router->GetCurrentLayer(), m_netClass );
177 const int64_t lengthDiffMax = m_router->GetInterface()->CalculateLengthForDelay(
178 desiredDelayMax - desiredDelayOpt, m_currentWidth, false, m_router->Sizes().DiffPairGap(),
179 m_router->GetCurrentLayer(), m_netClass );
180
181 lengthDiffOpt = delayDifferenceOpt > 0 ? lengthDiffOpt : -lengthDiffOpt;
182
183 m_settings.m_targetLength.SetMin( curLength + lengthDiffOpt - lengthDiffMin );
184 m_settings.m_targetLength.SetOpt( curLength + lengthDiffOpt );
185 m_settings.m_targetLength.SetMax( curLength + lengthDiffOpt + lengthDiffMax );
186 }
187}
188
189
190bool MEANDER_PLACER::Move( const VECTOR2I& aP, ITEM* aEndItem )
191{
192 // Reuse the chain-extras aggregate captured at Start(). Other nets in the chain are
193 // not edited during a tuning session, so we don't need to walk the BOARD again.
194 const long long extraDelay = m_chainExtrasValid ? m_chainExtrasDelay : 0;
195
196 // m_signalExtraDelay is needed for calculateTimeDomainTargets().
197 m_settings.m_signalExtraDelay = extraDelay;
198
199 // Derive per-net budget from chain target, accounting for stubs not in the PNS path.
200 // Take the tighter of chain budget and existing per-net constraint (from EditStart).
201 if( m_settings.m_targetSignalLength.Opt() != MEANDER_SETTINGS::LENGTH_UNCONSTRAINED )
202 {
203 const long long otherLen = chainNarrowingOffset();
204
205 long long budgetMin = std::max( 0LL, m_settings.m_targetSignalLength.Min() - otherLen );
206 long long budgetOpt = std::max( 0LL, m_settings.m_targetSignalLength.Opt() - otherLen );
207 long long budgetMax = std::max( budgetOpt, m_settings.m_targetSignalLength.Max() - otherLen );
208
209 if( m_settings.m_targetLength.Opt() == MEANDER_SETTINGS::LENGTH_UNCONSTRAINED )
210 {
211 m_settings.m_targetLength.SetMin( budgetMin );
212 m_settings.m_targetLength.SetOpt( budgetOpt );
213 m_settings.m_targetLength.SetMax( budgetMax );
214 }
215 else
216 {
217 m_settings.m_targetLength.SetMin( std::max( m_settings.m_targetLength.Min(), budgetMin ) );
218 m_settings.m_targetLength.SetOpt( std::min( m_settings.m_targetLength.Opt(), budgetOpt ) );
219 m_settings.m_targetLength.SetMax( std::min( m_settings.m_targetLength.Max(), budgetMax ) );
220 }
221 }
222
224
225 return doMove( aP, aEndItem, m_settings.m_targetLength.Opt(), m_settings.m_targetLength.Min(),
226 m_settings.m_targetLength.Max() );
227}
228
229
230bool MEANDER_PLACER::doMove( const VECTOR2I& aP, ITEM* aEndItem, long long int aTargetLength,
231 long long int aTargetMin, long long int aTargetMax )
232{
233 if( m_currentStart == aP )
234 return false;
235
236 if( m_currentNode )
237 delete m_currentNode;
238
239 m_currentNode = m_world->Branch();
240
241 SHAPE_LINE_CHAIN pre, tuned, post;
242
243 m_originLine.CLine().Split( m_currentStart, aP, pre, tuned, post );
244
245 m_result = MEANDERED_LINE( this, false );
246 m_result.SetWidth( m_originLine.Width() );
247 m_result.SetBaselineOffset( 0 );
248
249 for( int i = 0; i < tuned.SegmentCount(); i++ )
250 {
251 if( tuned.IsArcSegment( i ) )
252 {
253 ssize_t arcIndex = tuned.ArcIndex( i );
254 m_result.AddArc( tuned.Arc( arcIndex ) );
255 i = tuned.NextShape( i );
256
257 // NextShape will return -1 if last shape
258 if( i < 0 )
259 i = tuned.SegmentCount();
260
261 continue;
262 }
263
264 bool side = false;
265 const SEG s = tuned.CSegment( i );
266
267 if( m_settings.m_initialSide == 0 )
268 side = s.Side( aP ) < 0;
269 else
270 side = m_settings.m_initialSide < 0;
271
272 m_result.AddCorner( s.A );
273 m_result.MeanderSegment( s, side );
274 m_result.AddCorner( s.B );
275 }
276
277 long long int lineLen = origPathLength();
278 int64_t lineDelay = origPathDelay();
279
280 m_lastLength = lineLen;
283
284 if( lineLen > m_settings.m_targetLength.Max() )
285 {
287 }
288 else
289 {
290 m_lastLength = lineLen - tuned.Length();
291
292 if( m_settings.m_isTimeDomain )
293 {
295 - m_router->GetInterface()->CalculateDelayForShapeLineChain(
296 tuned, m_currentWidth, false, m_router->Sizes().DiffPairGap(),
297 m_router->GetCurrentLayer(), m_netClass );
298 }
299
300 tuneLineLength( m_result, aTargetLength - lineLen );
301 }
302
303 for( const ITEM* item : m_tunedPath.CItems() )
304 {
305 if( const LINE* l = dyn_cast<const LINE*>( item ) )
306 {
307 PNS_DBG( Dbg(), AddItem, l, BLUE, 30000, wxT( "tuned-line" ) );
308
309 m_router->GetInterface()->DisplayPathLine( l->CLine(), 1 );
310 }
311 }
312
313 if( m_lastStatus != TOO_LONG )
314 {
315 tuned.Clear();
316
317 for( MEANDER_SHAPE* m : m_result.Meanders() )
318 {
319 if( m->Type() != MT_EMPTY )
320 {
321 tuned.Append ( m->CLine( 0 ) );
322 }
323 }
324
325 m_lastLength += tuned.Length();
326
327 if( m_settings.m_isTimeDomain )
328 {
329 m_lastDelay += m_router->GetInterface()->CalculateDelayForShapeLineChain(
330 tuned, m_currentWidth, false, m_router->Sizes().DiffPairGap(), m_router->GetCurrentLayer(),
331 m_netClass );
332 }
333
334 if( m_lastLength > aTargetMax )
336 else if( m_lastLength < aTargetMin )
338 else
340 }
341
342 m_finalShape.Clear();
343
344 if( m_settings.m_keepEndpoints )
345 {
346 pre.Simplify();
347 tuned.Simplify();
348 post.Simplify();
349
350 m_finalShape.Append( pre );
351 m_finalShape.Append( tuned );
352 m_finalShape.Append( post );
353 }
354 else
355 {
356 m_finalShape.Append( pre );
357 m_finalShape.Append( tuned );
358 m_finalShape.Append( post );
359 m_finalShape.Simplify();
360 }
361
362 return true;
363}
364
365
366bool MEANDER_PLACER::FixRoute( const VECTOR2I& aP, ITEM* aEndItem, bool aForceFinish )
367{
368 if( !m_currentNode )
369 return false;
370
374
375 return true;
376}
377
378
380{
381 m_world->KillChildren();
382 return true;
383}
384
385
387{
388 return m_currentTrace.SegmentCount() > 0;
389}
390
391
393{
394 if( m_currentNode )
396
397 m_currentNode = nullptr;
398 return true;
399}
400
401
403{
404 LINE l( m_originLine, aShape->CLine( 0 ) );
405
406 if( m_currentNode->CheckColliding( &l ) )
407 return false;
408
409 int w = aShape->Width();
410 int clearance = w + m_settings.m_spacing;
411
412 return m_result.CheckSelfIntersections( aShape, clearance );
413}
414
415
421
423{
424 return m_tunedPath;
425}
426
428{
429 return m_currentStart;
430}
431
433{
434 return m_currentEnd;
435}
436
438{
439 return m_initialSegment->Layers().Start();
440}
441
442
444{
445 if( m_lastLength )
446 return m_lastLength;
447 else
448 return origPathLength();
449}
450
451
453{
454 if( m_lastDelay )
455 return m_lastDelay;
456 else
457 return origPathDelay();
458}
459
460
465
466}
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
virtual NETCLASS * GetEffectiveNetClass() const
Return the NETCLASS for this item.
T Min() const
Definition minoptmax.h:29
T Max() const
Definition minoptmax.h:30
T Opt() const
Definition minoptmax.h:31
ROUTER * Router() const
Return current router settings.
ROUTER * m_router
DEBUG_DECORATOR * Dbg() const
Base class for PNS router board items.
Definition pns_item.h:98
BOARD_ITEM * GetSourceItem() const
Definition pns_item.h:202
bool OfKind(int aKindMask) const
Definition pns_item.h:181
Represents a track on a PCB, connecting two non-trivial joints (that is, vias, pads,...
Definition pns_line.h:62
Represent a set of meanders fitted over a single or two lines.
long long int chainNarrowingOffset() const
Return the length offset to subtract when converting a user-facing total signal length target into a ...
void tuneLineLength(MEANDERED_LINE &aTuned, long long int aElongation)
Take a set of meanders in aTuned and tunes their length to extend the original line length by aElonga...
TUNING_STATUS
< Result of the length tuning operation
int m_currentWidth
Meander settings.
bool m_hasBaseline
Active path length at Start().
bool m_chainExtrasValid
Pointer to world to search colliding items.
long long int m_startPathLength
Aggregate length/delay of other nets in the same chain, cached at Start().
void initChainExtras()
Cache the per-session chain-extras length/delay (other nets in the same chain) so per-Move use does n...
MEANDER_SETTINGS m_settings
The current end point.
int64_t lineDelay(const ITEM_SET &aLine, const SOLID *aStartPad, const SOLID *aEndPad) const
Calculate the total delay of the line represented by an item set (tracks and vias)
NODE * m_world
Width of the meandered trace(s).
long long int lineLength(const ITEM_SET &aLine, const SOLID *aStartPad, const SOLID *aEndPad) const
Calculate the total length of the line represented by an item set (tracks and vias)
virtual bool FixRoute(const VECTOR2I &aP, ITEM *aEndItem, bool aForceFinish=false) override
Function FixRoute()
bool doMove(const VECTOR2I &aP, ITEM *aEndItem, long long int aTargetLength, long long int aTargetMin, long long int aTargetMax)
virtual bool Move(const VECTOR2I &aP, ITEM *aEndItem) override
Function Move()
virtual long long int origPathLength() const
int CurrentLayer() const override
Function CurrentLayer()
virtual void calculateTimeDomainTargets()
current routing start point (end of tail, beginning of head)
int m_padToDieDelay
The netclass for the placed segments.
const VECTOR2I & CurrentEnd() const override
Function CurrentEnd()
const VECTOR2I & CurrentStart() const override
Function CurrentStart()
long long int TuningLengthResult() const override
Return the resultant length or skew of the tuned traces.
bool AbortPlacement() override
int64_t TuningDelayResult() const override
Return the resultant delay or skew of the tuned traces.
bool HasPlacedAnything() const override
NODE * CurrentNode(bool aLoopsRemoved=false) const override
Function CurrentNode()
LINKED_ITEM * m_initialSegment
Total length added by pad to die size.
SHAPE_LINE_CHAIN m_finalShape
const ITEM_SET TunedPath() override
const ITEM_SET Traces() override
Function Traces()
MEANDER_PLACER(ROUTER *aRouter)
virtual int64_t origPathDelay() const
bool CheckFit(MEANDER_SHAPE *aShape) override
Checks if it's OK to place the shape aShape (i.e.
VECTOR2I m_currentStart
Current world state.
TUNING_STATUS TuningStatus() const override
Return the tuning status (too short, too long, etc.) of the trace(s) being tuned.
virtual bool Start(const VECTOR2I &aP, ITEM *aStartItem) override
Function Start()
int m_padToDieLength
Total length added by pad to die size.
bool CommitPlacement() override
static const long long int LENGTH_UNCONSTRAINED
Definition pns_meander.h:73
static const long long int DELAY_UNCONSTRAINED
Definition pns_meander.h:76
The geometry of a single meander.
int Width() const
const SHAPE_LINE_CHAIN & CLine(int aShape) const
Keep the router "world" - i.e.
Definition pns_node.h:243
NODE * Branch()
Create a lightweight copy (called branch) of self that tracks the changes (added/removed items) wrs t...
Definition pns_node.cpp:157
void SetFailureReason(const wxString &aReason)
Definition pns_router.h:249
void CommitRouting()
NODE * GetWorld() const
Definition pns_router.h:200
const ITEM_SET AssembleTuningPath(ROUTER_IFACE *aRouterIface, ITEM *aStart, SOLID **aStartPad=nullptr, SOLID **aEndPad=nullptr)
Like AssembleTrivialPath, but follows the track length algorithm, which discards segments that are fu...
Definition seg.h:38
VECTOR2I A
Definition seg.h:45
VECTOR2I B
Definition seg.h:46
int Side(const VECTOR2I &aP) const
Determine on which side of directed line passing via segment ends point aP lies.
Definition seg.h:139
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
const SHAPE_ARC & Arc(size_t aArc) const
ssize_t ArcIndex(size_t aSegment) const
Return the arc index for the given segment index.
void Clear()
Remove all points from the line chain.
void Simplify(int aTolerance=0)
Simplify the line chain by removing colinear adjacent segments and duplicate vertices.
int NextShape(int aPointIndex) const
Return the vertex index of the next shape in the chain, or -1 if aPointIndex is the last shape.
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
int SegmentCount() const
Return the number of segments in this line chain.
const SEG CSegment(int aIndex) const
Return a constant copy of the aIndex segment in the line chain.
bool IsArcSegment(size_t aSegment) const
long long int Length() const
Return length of the line chain in Euclidean metric.
@ BLUE
Definition color4d.h:52
#define _(s)
Push and Shove diff pair dimensions (gap) settings dialog.
@ MT_EMPTY
Definition pns_meander.h:49
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition eda_angle.h:411
#define PNS_DBG(dbg, method,...)
static VECTOR2I GetSnappedStartPoint(LINKED_ITEM *aStartItem, VECTOR2I aStartPoint)
int clearance
Casted dyn_cast(From aObject)
A lightweight dynamic downcast.
Definition typeinfo.h:55
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683