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 m_hasMeanders = false;
234
235 if( m_currentStart == aP )
236 return false;
237
238 if( m_currentNode )
239 delete m_currentNode;
240
241 m_currentNode = m_world->Branch();
242
243 SHAPE_LINE_CHAIN pre, tuned, post;
244
245 m_originLine.CLine().Split( m_currentStart, aP, pre, tuned, post );
246
247 m_result = MEANDERED_LINE( this, false );
248 m_result.SetWidth( m_originLine.Width() );
249 m_result.SetBaselineOffset( 0 );
250
251 for( int i = 0; i < tuned.SegmentCount(); i++ )
252 {
253 if( tuned.IsArcSegment( i ) )
254 {
255 ssize_t arcIndex = tuned.ArcIndex( i );
256 m_result.AddArc( tuned.Arc( arcIndex ) );
257 i = tuned.NextShape( i );
258
259 // NextShape will return -1 if last shape
260 if( i < 0 )
261 i = tuned.SegmentCount();
262
263 continue;
264 }
265
266 bool side = false;
267 const SEG s = tuned.CSegment( i );
268
269 if( m_settings.m_initialSide == 0 )
270 side = s.Side( aP ) < 0;
271 else
272 side = m_settings.m_initialSide < 0;
273
274 m_result.AddCorner( s.A );
275 m_result.MeanderSegment( s, side );
276 m_result.AddCorner( s.B );
277 }
278
279 long long int lineLen = origPathLength();
280 int64_t lineDelay = origPathDelay();
281
282 m_lastLength = lineLen;
285
286 if( lineLen > m_settings.m_targetLength.Max() )
287 {
289 }
290 else
291 {
292 m_lastLength = lineLen - tuned.Length();
293
294 if( m_settings.m_isTimeDomain )
295 {
297 - m_router->GetInterface()->CalculateDelayForShapeLineChain(
298 tuned, m_currentWidth, false, m_router->Sizes().DiffPairGap(),
299 m_router->GetCurrentLayer(), m_netClass );
300 }
301
302 tuneLineLength( m_result, aTargetLength - lineLen );
303 }
304
305 for( const ITEM* item : m_tunedPath.CItems() )
306 {
307 if( const LINE* l = dyn_cast<const LINE*>( item ) )
308 {
309 PNS_DBG( Dbg(), AddItem, l, BLUE, 30000, wxT( "tuned-line" ) );
310
311 m_router->GetInterface()->DisplayPathLine( l->CLine(), 1 );
312 }
313 }
314
315 if( m_lastStatus != TOO_LONG )
316 {
317 tuned.Clear();
318
319 for( MEANDER_SHAPE* m : m_result.Meanders() )
320 {
321 if( m->Type() != MT_EMPTY )
322 {
323 tuned.Append ( m->CLine( 0 ) );
324 m_hasMeanders |= m->IsMeander();
325 }
326 }
327
328 m_lastLength += tuned.Length();
329
330 if( m_settings.m_isTimeDomain )
331 {
332 m_lastDelay += m_router->GetInterface()->CalculateDelayForShapeLineChain(
333 tuned, m_currentWidth, false, m_router->Sizes().DiffPairGap(), m_router->GetCurrentLayer(),
334 m_netClass );
335 }
336
337 if( m_lastLength > aTargetMax )
339 else if( m_lastLength < aTargetMin )
341 else
343 }
344
345 m_finalShape.Clear();
346
347 if( m_settings.m_keepEndpoints )
348 {
349 pre.Simplify();
350 tuned.Simplify();
351 post.Simplify();
352
353 m_finalShape.Append( pre );
354 m_finalShape.Append( tuned );
355 m_finalShape.Append( post );
356 }
357 else
358 {
359 m_finalShape.Append( pre );
360 m_finalShape.Append( tuned );
361 m_finalShape.Append( post );
362 m_finalShape.Simplify();
363 }
364
365 return true;
366}
367
368
369bool MEANDER_PLACER::FixRoute( const VECTOR2I& aP, ITEM* aEndItem, bool aForceFinish )
370{
371 if( !m_currentNode )
372 return false;
373
377
378 return true;
379}
380
381
383{
384 m_world->KillChildren();
385 return true;
386}
387
388
390{
391 return m_currentTrace.SegmentCount() > 0;
392}
393
394
396{
397 if( m_currentNode )
399
400 m_currentNode = nullptr;
401 return true;
402}
403
404
406{
407 LINE l( m_originLine, aShape->CLine( 0 ) );
408
409 if( m_currentNode->CheckColliding( &l ) )
410 return false;
411
412 int w = aShape->Width();
413 int clearance = w + m_settings.m_spacing;
414
415 return m_result.CheckSelfIntersections( aShape, clearance );
416}
417
418
424
426{
427 return m_tunedPath;
428}
429
431{
432 return m_currentStart;
433}
434
436{
437 return m_currentEnd;
438}
439
441{
442 return m_initialSegment->Layers().Start();
443}
444
445
447{
448 if( m_lastLength )
449 return m_lastLength;
450 else
451 return origPathLength();
452}
453
454
456{
457 if( m_lastDelay )
458 return m_lastDelay;
459 else
460 return origPathDelay();
461}
462
463
468
469}
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 the instance of our router.
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
Width of the meandered trace(s).
long long int m_startPathLength
Active path length at Start().
VECTOR2I m_currentEnd
The current end point.
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
Meander settings.
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
Pointer to world to search colliding items.
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)
long long int m_baselineLength
The tuning results as they were at Start(). The deltas measure change from these.
NODE * m_currentNode
Current world state.
virtual bool FixRoute(const VECTOR2I &aP, ITEM *aEndItem, bool aForceFinish=false) override
Commit the currently routed items to the parent node, taking aP as the final end point and aEndItem a...
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
Move the end of the currently routed primtive(s) to the point aP, taking aEndItem as the anchor (if n...
virtual long long int origPathLength() const
int CurrentLayer() const override
Return the layer of currently routed track.
virtual void calculateTimeDomainTargets()
int m_padToDieDelay
Total length added by pad to die size.
const VECTOR2I & CurrentEnd() const override
Return the current end of the line(s) being placed/tuned.
const VECTOR2I & CurrentStart() const override
Return the current start of the line(s) being placed/tuned.
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
Return the most recent board state.
LINKED_ITEM * m_initialSegment
SHAPE_LINE_CHAIN m_finalShape
const ITEM_SET TunedPath() override
const ITEM_SET Traces() override
Return all routed/tuned 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 routing start point (end of tail, beginning of head)
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
Start placement/drag operation at point aP, taking item aStartItem as anchor (unless NULL).
int m_padToDieLength
Total length added by pad to die size.
bool CommitPlacement() override
NETCLASS * m_netClass
The netclass for the placed segments.
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:244
NODE * Branch()
Create a lightweight copy (called branch) of self that tracks the changes (added/removed items) wrs t...
Definition pns_node.cpp:163
void SetFailureReason(const wxString &aReason)
Definition pns_router.h:260
void CommitRouting()
NODE * GetWorld() const
Definition pns_router.h:211
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:437
#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:708