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 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
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
Meander settings.
bool m_hasBaseline
Active path length at Start().
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)
bool doMove(const VECTOR2I &aP, ITEM *aEndItem, long long int aTargetLength, long long int aTargetMin, long long int aTargetMax)
LINKED_ITEM * m_initialSegment
Total length added by pad to die size.
MEANDER_PLACER(ROUTER *aRouter)
VECTOR2I m_currentStart
Current world state.
int64_t origPathDelay() const override
long long int origPathLength() const override
bool Move(const VECTOR2I &aP, ITEM *aEndItem) override
Function Move()
bool Start(const VECTOR2I &aP, ITEM *aStartItem) override
Function Start()
long long int TuningLengthResult() const override
Return the resultant length or skew of the tuned traces.
void calculateTimeDomainTargets() override
current routing start point (end of tail, beginning of head)
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:254
void SetFailureReason(const wxString &aReason)
Definition pns_router.h:249
NODE * GetWorld() const
Definition pns_router.h:200
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:411
#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:683