1 /*
2  * KiRouter - a push-and-(sometimes-)shove PCB router
3  *
4  * Copyright (C) 2013-2015 CERN
5  * Copyright (C) 2016 KiCad Developers, see AUTHORS.txt for contributors.
6  * Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
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 along
19  * with this program.  If not, see <http://www.gnu.org/licenses/>.
20  */
21 
22 #include <base_units.h> // God forgive me doing this...
23 
24 #include "pns_node.h"
25 #include "pns_itemset.h"
26 #include "pns_topology.h"
27 #include "pns_meander_skew_placer.h"
28 #include "pns_solid.h"
29 
30 #include "pns_router.h"
31 #include "pns_debug_decorator.h"
32 
33 namespace PNS {
34 
MEANDER_SKEW_PLACER(ROUTER * aRouter)35 MEANDER_SKEW_PLACER::MEANDER_SKEW_PLACER ( ROUTER* aRouter ) :
36     MEANDER_PLACER ( aRouter )
37 {
38     // Init temporary variables (do not leave uninitialized members)
39     m_coupledLength = 0;
40     m_padToDieN = 0;
41     m_padToDieP = 0;
42 }
43 
44 
~MEANDER_SKEW_PLACER()45 MEANDER_SKEW_PLACER::~MEANDER_SKEW_PLACER( )
46 {
47 }
48 
49 
Start(const VECTOR2I & aP,ITEM * aStartItem)50 bool MEANDER_SKEW_PLACER::Start( const VECTOR2I& aP, ITEM* aStartItem )
51 {
52     if( !aStartItem || !aStartItem->OfKind( ITEM::SEGMENT_T | ITEM::ARC_T) )
53     {
54         Router()->SetFailureReason( _( "Please select a differential pair trace you want to tune." ) );
55         return false;
56     }
57 
58     m_initialSegment = static_cast<LINKED_ITEM*>( aStartItem );
59     m_currentNode    = nullptr;
60     m_currentStart   = getSnappedStartPoint( m_initialSegment, aP );
61 
62     m_world = Router()->GetWorld( )->Branch();
63     m_originLine = m_world->AssembleLine( m_initialSegment );
64 
65     TOPOLOGY topo( m_world );
66     m_tunedPath = topo.AssembleTrivialPath( m_initialSegment );
67 
68     if( !topo.AssembleDiffPair ( m_initialSegment, m_originPair ) )
69     {
70         Router()->SetFailureReason( _( "Unable to find complementary differential pair "
71                                        "net for skew tuning. Make sure the names of the nets belonging "
72                                        "to a differential pair end with either _N/_P or +/-." ) );
73         return false;
74     }
75 
76     if( m_originPair.Gap() < 0 )
77         m_originPair.SetGap( Router()->Sizes().DiffPairGap() );
78 
79     if( !m_originPair.PLine().SegmentCount() ||
80         !m_originPair.NLine().SegmentCount() )
81         return false;
82 
83     SOLID* padA = nullptr;
84     SOLID* padB = nullptr;
85 
86     m_tunedPathP = topo.AssembleTuningPath( m_originPair.PLine().GetLink( 0 ), &padA, &padB );
87 
88     m_padToDieP = 0;
89 
90     if( padA )
91         m_padToDieP += padA->GetPadToDie();
92 
93     if( padB )
94         m_padToDieP += padB->GetPadToDie();
95 
96     m_tunedPathN = topo.AssembleTuningPath( m_originPair.NLine().GetLink( 0 ), &padA, &padB );
97 
98     m_padToDieN = 0;
99 
100     if( padA )
101         m_padToDieN += padA->GetPadToDie();
102 
103     if( padB )
104         m_padToDieN += padB->GetPadToDie();
105 
106     m_world->Remove( m_originLine );
107 
108     m_currentWidth = m_originLine.Width();
109     m_currentEnd = VECTOR2I( 0, 0 );
110 
111     if ( m_originPair.PLine().Net() == m_originLine.Net() )
112     {
113         m_padToDieLength = m_padToDieN;
114         m_coupledLength = lineLength( m_tunedPathN );
115         m_tunedPath = m_tunedPathP;
116     }
117     else
118     {
119         m_padToDieLength = m_padToDieP;
120         m_coupledLength = lineLength( m_tunedPathP );
121         m_tunedPath = m_tunedPathN;
122     }
123 
124     return true;
125 }
126 
127 
origPathLength() const128 long long int MEANDER_SKEW_PLACER::origPathLength() const
129 {
130     return m_padToDieLength + lineLength( m_tunedPath );
131 }
132 
133 
currentSkew() const134 long long int MEANDER_SKEW_PLACER::currentSkew() const
135 {
136     return m_lastLength - m_coupledLength;
137 }
138 
139 
Move(const VECTOR2I & aP,ITEM * aEndItem)140 bool MEANDER_SKEW_PLACER::Move( const VECTOR2I& aP, ITEM* aEndItem )
141 {
142     for( const ITEM* item : m_tunedPathP.CItems() )
143     {
144         if( const LINE* l = dyn_cast<const LINE*>( item ) )
145             PNS_DBG( Dbg(), AddLine, l->CLine(), BLUE, 10000, "tuned-path-skew-p" );
146     }
147 
148     for( const ITEM* item : m_tunedPathN.CItems() )
149     {
150         if( const LINE* l = dyn_cast<const LINE*>( item ) )
151             PNS_DBG( Dbg(), AddLine, l->CLine(), YELLOW, 10000, "tuned-path-skew-n" );
152     }
153 
154     return doMove( aP, aEndItem, m_coupledLength + m_settings.m_targetSkew );
155 }
156 
157 
TuningInfo(EDA_UNITS aUnits) const158 const wxString MEANDER_SKEW_PLACER::TuningInfo( EDA_UNITS aUnits ) const
159 {
160     wxString status;
161 
162     switch( m_lastStatus )
163     {
164     case TOO_LONG:
165         status = _( "Too long: skew " );
166         break;
167     case TOO_SHORT:
168         status = _( "Too short: skew " );
169         break;
170     case TUNED:
171         status = _( "Tuned: skew " );
172         break;
173     default:
174         return _( "?" );
175     }
176 
177     status += ::MessageTextFromValue( aUnits, m_lastLength - m_coupledLength );
178     status += "/";
179     status += ::MessageTextFromValue( aUnits, m_settings.m_targetSkew );
180 
181     return status;
182 }
183 
184 }
185