KiCad PCB EDA Suite
Loading...
Searching...
No Matches
pns_meander_skew_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
23
24#include <core/typeinfo.h>
26
27#include "pns_node.h"
28#include "pns_itemset.h"
29#include "pns_topology.h"
30#include "pns_solid.h"
31
32#include "pns_router.h"
33#include "pns_debug_decorator.h"
34#include "pns_helpers.h"
35
36#include <board.h>
37#include <netinfo.h>
38
39namespace PNS {
40
42 MEANDER_PLACER ( aRouter )
43{
44 // Init temporary variables (do not leave uninitialized members)
51}
52
53
57
58
59bool MEANDER_SKEW_PLACER::Start( const VECTOR2I& aP, ITEM* aStartItem )
60{
61 if( !aStartItem || !aStartItem->OfKind( ITEM::SEGMENT_T | ITEM::ARC_T) )
62 {
63 Router()->SetFailureReason( _( "Please select a differential pair track you want to tune." ) );
64 return false;
65 }
66
67 m_initialSegment = static_cast<LINKED_ITEM*>( aStartItem );
68 m_currentNode = nullptr;
70
71 m_world = Router()->GetWorld( )->Branch();
72 m_originLine = m_world->AssembleLine( m_initialSegment );
73
74 TOPOLOGY topo( m_world );
75 m_tunedPath = topo.AssembleTrivialPath( m_initialSegment, nullptr, true );
76
78 {
79 Router()->SetFailureReason( _( "Unable to find complementary differential pair "
80 "net for skew tuning. Make sure the names of the nets belonging "
81 "to a differential pair end with either _N/_P or +/-." ) );
82 return false;
83 }
84
85 if( m_originPair.Dimensions().Gap() < 0 )
86 m_originPair.SetGap( Router()->Sizes().DiffPairGap() );
87
88 if( !m_originPair.PLine().SegmentCount() ||
89 !m_originPair.NLine().SegmentCount() )
90 return false;
91
92 m_tunedPathP = topo.AssembleTuningPath( Router()->GetInterface(), m_originPair.PLine().GetLink( 0 ), &m_startPad_p,
93 &m_endPad_p );
94
97
98 if( m_startPad_p )
99 {
100 m_padToDieLengthP += m_startPad_p->GetPadToDie();
101 m_padToDieDelayP += m_startPad_p->GetPadToDieDelay();
102 }
103
104 if( m_endPad_p )
105 {
106 m_padToDieLengthP += m_endPad_p->GetPadToDie();
107 m_padToDieDelayP += m_endPad_p->GetPadToDieDelay();
108 }
109
110 m_tunedPathN = topo.AssembleTuningPath( Router()->GetInterface(), m_originPair.NLine().GetLink( 0 ), &m_startPad_n,
111 &m_endPad_n );
112
115
116 if( m_startPad_n )
117 {
118 m_padToDieLengthN += m_startPad_n->GetPadToDie();
119 m_padToDieDelayN += m_startPad_n->GetPadToDieDelay();
120 }
121
122 if( m_endPad_n )
123 {
124 m_padToDieLengthN += m_endPad_n->GetPadToDie();
125 m_padToDieDelayN += m_endPad_n->GetPadToDieDelay();
126 }
127
128 m_world->Remove( m_originLine );
129
131 m_currentEnd = VECTOR2I( 0, 0 );
132
133 const BOARD_CONNECTED_ITEM* conItem = static_cast<BOARD_CONNECTED_ITEM*>( aStartItem->GetSourceItem() );
134 m_netClass = conItem->GetEffectiveNetClass();
135 m_settings.m_netClass = m_netClass;
136
137 bool pIsActive = ( m_originPair.NetP() == m_originLine.Net() );
142
143 // Query interface for aggregate chain contribution (other nets in same chain)
144 long long int extraSignalLen = 0;
145 long long int extraSignalDelay = 0;
147 extraSignalLen, extraSignalDelay );
148
149 if( pIsActive )
150 {
151 m_coupledLength = lenN + extraSignalLen;
152 m_lastLength = lenP + extraSignalLen;
153 m_coupledDelay = delayN + extraSignalDelay;
154 m_lastDelay = delayP + extraSignalDelay;
156 }
157 else
158 {
159 m_coupledLength = lenP + extraSignalLen;
160 m_lastLength = lenN + extraSignalLen;
161 m_coupledDelay = delayP + extraSignalDelay;
162 m_lastDelay = delayN + extraSignalDelay;
164 }
165
168 m_baselineDelay = m_settings.m_isTimeDomain ? TuningDelayResult() : 0;
169 m_hasBaseline = true;
170
172
174
175 return true;
176}
177
178
186
187
195
196
198{
199 return m_lastLength - m_coupledLength; // Includes aggregate chain contribution if applicable
200}
201
202
203bool MEANDER_SKEW_PLACER::Move( const VECTOR2I& aP, ITEM* aEndItem )
204{
206
207 bool isPositive = m_originPair.NetP() == m_originLine.Net();
208
209 for( const ITEM* item : m_tunedPathP.CItems() )
210 {
211 if( const LINE* l = dyn_cast<const LINE*>( item ) )
212 {
213 PNS_DBG( Dbg(), AddItem, l, BLUE, 10000, wxT( "tuned-path-skew-p" ) );
214
215 m_router->GetInterface()->DisplayPathLine( l->CLine(), isPositive ? 1 : 0 );
216 }
217 }
218
219 for( const ITEM* item : m_tunedPathN.CItems() )
220 {
221 if( const LINE* l = dyn_cast<const LINE*>( item ) )
222 {
223 PNS_DBG( Dbg(), AddItem, l, YELLOW, 10000, wxT( "tuned-path-skew-n" ) );
224
225 m_router->GetInterface()->DisplayPathLine( l->CLine(), isPositive ? 0 : 1 );
226 }
227 }
228
229 // Convert the user-facing skew target (active total minus coupled total) into a meander-only
230 // doMove target. m_coupledLength already includes the chain-extras aggregate captured at
231 // Start(); the chain extras and any unmeasured stub on the active net are absorbed by the
232 // chain rather than by the meander, so subtract them here. Without this, the meander
233 // over-corrects by exactly chainNarrowingOffset() whenever the diff pair belongs to a chain.
234 const long long offset = chainNarrowingOffset();
235
236 return doMove( aP, aEndItem, m_coupledLength + m_settings.m_targetSkew.Opt() - offset,
237 m_coupledLength + m_settings.m_targetSkew.Min() - offset,
238 m_coupledLength + m_settings.m_targetSkew.Max() - offset );
239}
240
241
243{
245}
246
247
252
253
255{
256 auto calculateTargetSkew = [this]( const int64_t targetSkewDelay )
257 {
258 const int64_t curSkewDelay = m_lastDelay - m_coupledDelay;
259 const int64_t skewDelayDifference = targetSkewDelay - curSkewDelay;
260
261 int64_t skewLengthDiff = m_router->GetInterface()->CalculateLengthForDelay(
262 std::abs( skewDelayDifference ), m_originPair.Dimensions().Width(), true, m_originPair.Dimensions().Gap(),
263 m_router->GetCurrentLayer(), m_netClass );
264
265 const int64_t curSkew = CurrentSkew();
266 skewLengthDiff = skewDelayDifference > 0 ? skewLengthDiff : -skewLengthDiff;
267
268 return static_cast<int>( curSkew + skewLengthDiff );
269 };
270
271 if( m_settings.m_isTimeDomain )
272 {
273 const int minSkew = calculateTargetSkew( m_settings.m_targetSkewDelay.Min() );
274 m_settings.m_targetSkew.SetMin( static_cast<int>( minSkew ) );
275
276 const int optSkew = calculateTargetSkew( m_settings.m_targetSkewDelay.Opt() );
277 m_settings.m_targetSkew.SetOpt( static_cast<int>( optSkew ) );
278
279 const int maxSkew = calculateTargetSkew( m_settings.m_targetSkewDelay.Max() );
280 m_settings.m_targetSkew.SetMax( static_cast<int>( maxSkew ) );
281 }
282}
283}
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.
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
long long int chainNarrowingOffset() const
Return the length offset to subtract when converting a user-facing total signal length target into a ...
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.
bool doMove(const VECTOR2I &aP, ITEM *aEndItem, long long int aTargetLength, long long int aTargetMin, long long int aTargetMax)
LINKED_ITEM * m_initialSegment
MEANDER_PLACER(ROUTER *aRouter)
VECTOR2I m_currentStart
current routing start point (end of tail, beginning of head)
NETCLASS * m_netClass
The netclass for the placed segments.
int64_t origPathDelay() const override
long long int origPathLength() const override
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...
bool Start(const VECTOR2I &aP, ITEM *aStartItem) override
Start placement/drag operation at point aP, taking item aStartItem as anchor (unless NULL).
long long int TuningLengthResult() const override
Return the resultant length or skew of the tuned traces.
int64_t TuningDelayResult() const override
Return the resultant delay or skew of the tuned traces.
NODE * Branch()
Create a lightweight copy (called branch) of self that tracks the changes (added/removed items) wrs t...
Definition pns_node.cpp:157
virtual bool GetSignalAggregate(NET_HANDLE aNetP, NET_HANDLE aNetN, long long &aExtraLength, long long &aExtraDelay) const =0
ROUTER_IFACE * GetInterface() const
Definition pns_router.h:261
void SetFailureReason(const wxString &aReason)
Definition pns_router.h:256
NODE * GetWorld() const
Definition pns_router.h:207
const DIFF_PAIR AssembleDiffPair(SEGMENT *aStart)
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...
const ITEM_SET AssembleTrivialPath(ITEM *aStart, std::pair< const JOINT *, const JOINT * > *aTerminalJoints=nullptr, bool aFollowLockedSegments=false)
Assemble a trivial path between two joints given a starting item.
@ BLUE
Definition color4d.h:52
@ YELLOW
Definition color4d.h:63
#define _(s)
Push and Shove diff pair dimensions (gap) settings dialog.
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)
Casted dyn_cast(From aObject)
A lightweight dynamic downcast.
Definition typeinfo.h:55
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:708