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 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:157
void SetFailureReason(const wxString &aReason)
Definition pns_router.h:256
void CommitRouting()
NODE * GetWorld() const
Definition pns_router.h:207
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