KiCad PCB EDA Suite
Loading...
Searching...
No Matches
netlist_exporter_base.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 1992-2017 jp.charras at wanadoo.fr
5 * Copyright (C) 2013-2017 SoftPLC Corporation, Dick Hollenbeck <[email protected]>
6 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU 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 <string_utils.h>
25
26#include <trace_helpers.h>
27#include <connection_graph.h>
28#include <sch_reference_list.h>
29#include <sch_screen.h>
30#include <schematic.h>
31
32
33// a "less than" test on two LIB_SYMBOLs (.m_name wxStrings)
35 LIB_SYMBOL* const& libsymbol2 ) const
36{
37 // Use case specific GetName() wxString compare
38 return libsymbol1->GetLibId() < libsymbol2->GetLibId();
39}
40
41
42wxString NETLIST_EXPORTER_BASE::MakeCommandLine( const wxString& aFormatString,
43 const wxString& aNetlistFile,
44 const wxString& aFinalFile,
45 const wxString& aProjectPath )
46{
47 // Expand format symbols in the command line:
48 // %B => base filename of selected output file, minus path and extension.
49 // %P => project directory name, without trailing '/' or '\'.
50 // %I => full filename of the input file (the intermediate net file).
51 // %O => complete filename and path (but without extension) of the user chosen output file.
52
53 wxString ret = aFormatString;
54 wxFileName in = aNetlistFile;
55 wxFileName out = aFinalFile;
56 wxString str_out = out.GetFullPath();
57
58 ret.Replace( "%P", aProjectPath, true );
59 ret.Replace( "%B", out.GetName(), true );
60 ret.Replace( "%I", in.GetFullPath(), true );
61
62#ifdef __WINDOWS__
63 // A ugly hack to run xsltproc that has a serious bug on Window since a long time:
64 // the filename given after -o option (output filename) cannot use '\' in filename
65 // so replace if by '/' if possible (I mean if the filename does not start by "\\"
66 // that is a filename on a Windows server)
67
68 if( !str_out.StartsWith( "\\\\" ) )
69 str_out.Replace( "\\", "/" );
70#endif
71
72 ret.Replace( "%O", str_out, true );
73
74 return ret;
75}
76
77
79 const SCH_SHEET_PATH& aSheetPath )
80{
81 wxCHECK( aItem, nullptr );
82
83 wxString ref;
84
85 if( aItem->Type() != SCH_SYMBOL_T )
86 return nullptr;
87
88 // found next symbol
89 SCH_SYMBOL* symbol = (SCH_SYMBOL*) aItem;
90
91 // Power symbols and other symbols which have the reference starting with "#" are not
92 // included in netlist (pseudo or virtual symbols)
93 ref = symbol->GetRef( &aSheetPath );
94
95 if( ref[0] == wxChar( '#' ) )
96 return nullptr;
97
98 SCH_SCREEN* screen = aSheetPath.LastScreen();
99
100 wxCHECK( screen, nullptr );
101
102 auto it = screen->GetLibSymbols().find( symbol->GetSchSymbolLibraryName() );
103
104 if( it == screen->GetLibSymbols().end() )
105 return nullptr;
106
107 LIB_SYMBOL* libSymbol = it->second;
108
109 // If symbol is a "multi parts per package" type
110 if( libSymbol->GetUnitCount() > 1 )
111 {
112 // test if this reference has already been processed, and if so skip
113 if( m_referencesAlreadyFound.Lookup( ref ) )
114 return nullptr;
115 }
116
117 // record the usage of this library symbol entry.
118 m_libParts.insert( libSymbol ); // rejects non-unique pointers
119
120 return symbol;
121}
122
123
124std::vector<PIN_INFO> NETLIST_EXPORTER_BASE::CreatePinList( SCH_SYMBOL* aSymbol,
125 const SCH_SHEET_PATH& aSheetPath,
126 bool aKeepUnconnectedPins )
127{
128 std::vector<PIN_INFO> pins;
129
130 if( !aSymbol )
131 return pins;
132
133 wxString ref( aSymbol->GetRef( &aSheetPath ) );
134
135 // Power symbols and other symbols which have the reference starting with "#" are not
136 // included in netlist (pseudo or virtual symbols)
137 if( ( ref[0] == wxChar( '#' ) ) || aSymbol->IsPower() )
138 return pins;
139
140 // if( aSymbol->m_FlagControlMulti == 1 )
141 // continue; /* yes */
142 // removed because with multiple instances of one schematic (several sheets pointing to
143 // 1 screen), this will be erroneously be toggled.
144
145 if( !aSymbol->GetLibSymbolRef() )
146 return pins;
147
148 // If symbol is a "multi parts per package" type
149 if( aSymbol->GetLibSymbolRef()->GetUnitCount() > 1 )
150 {
151 // Collect all pins for this reference designator by searching the entire design for
152 // other parts with the same reference designator.
153 findAllUnitsOfSymbol( aSymbol, aSheetPath, pins, aKeepUnconnectedPins );
154 wxLogTrace( traceStackedPins, "CreatePinList(multi): ref='%s' pins=%zu", aSymbol->GetRef( &aSheetPath ), pins.size() );
155 }
156
157 else // GetUnitCount() <= 1 means one part per package
158 {
159 CONNECTION_GRAPH* graph = m_schematic->ConnectionGraph();
160
161 for( const SCH_PIN* pin : aSymbol->GetPins( &aSheetPath ) )
162 {
163 if( SCH_CONNECTION* conn = pin->Connection( &aSheetPath ) )
164 {
165 const wxString& netName = conn->Name();
166
167 if( !aKeepUnconnectedPins ) // Skip unconnected pins if requested
168 {
169 CONNECTION_SUBGRAPH* sg = graph->FindSubgraphByName( netName, aSheetPath );
170
171 if( !sg || sg->GetNoConnect() || sg->GetItems().size() < 2 )
172 continue;
173 }
174
175 bool valid;
176 std::vector<wxString> numbers = pin->GetStackedPinNumbers( &valid );
177 wxString baseName = pin->GetShownName();
178 wxLogTrace( traceStackedPins,
179 wxString::Format( "CreatePinList(single): ref='%s' pinNameBase='%s' shownNum='%s' net='%s' "
180 "valid=%d expand=%zu",
181 ref, baseName, pin->GetShownNumber(), netName, valid, numbers.size() ) );
182
183 for( const wxString& num : numbers )
184 {
185 wxString pinName = baseName.IsEmpty() ? num : baseName + wxT( "_" ) + num;
186 wxLogTrace( traceStackedPins,
187 wxString::Format( " -> emit pin num='%s' name='%s' net='%s'", num, pinName, netName ) );
188 pins.emplace_back( num, netName, pinName );
189 }
190 }
191 }
192 }
193
194 // Sort pins in m_SortedSymbolPinList by pin number
195 std::sort( pins.begin(), pins.end(),
196 []( const PIN_INFO& lhs, const PIN_INFO& rhs )
197 {
198 return StrNumCmp( lhs.num, rhs.num, true ) < 0;
199 } );
200
201 // Remove duplicate Pins in m_SortedSymbolPinList
202 eraseDuplicatePins( pins );
203
204 // record the usage of this library symbol
205 m_libParts.insert( aSymbol->GetLibSymbolRef().get() ); // rejects non-unique pointers
206
207 return pins;
208}
209
210
211void NETLIST_EXPORTER_BASE::eraseDuplicatePins( std::vector<PIN_INFO>& aPins )
212{
213 // Helper to check if a net name is auto-generated rather than user-assigned.
214 // Auto-generated nets start with "unconnected-(" for NC pins or "Net-(" for unnamed nets.
215 auto isAutoGeneratedNet = []( const wxString& aNetName ) -> bool
216 {
217 return aNetName.StartsWith( wxT( "unconnected-(" ) )
218 || aNetName.StartsWith( wxT( "Net-(" ) );
219 };
220
221 for( unsigned ii = 0; ii < aPins.size(); ii++ )
222 {
223 if( aPins[ii].num.empty() )
224 continue;
225
226 // Search for duplicated pins and keep only one. Duplicate pin numbers can occur
227 // for multi-unit symbols with shared pins, or for symbols with the "duplicate pin
228 // numbers are jumpers" flag. In either case, all pins with the same number should
229 // connect to the same net. When they don't (user error), we prefer user-assigned
230 // nets over auto-generated ones to preserve user intent in the netlist.
231 // Because the pin list is sorted by pin number, duplicates are consecutive.
232 unsigned idxBest = ii;
233
234 for( unsigned jj = ii + 1; jj < aPins.size(); jj++ )
235 {
236 if( aPins[jj].num.empty() )
237 continue;
238
239 if( aPins[idxBest].num != aPins[jj].num )
240 break;
241
242 // Check if jj has a better (user-assigned) net than the current best.
243 // Prefer user-assigned nets over auto-generated "unconnected-(" or "Net-(" nets.
244 bool bestIsAuto = isAutoGeneratedNet( aPins[idxBest].netName );
245 bool jjIsAuto = isAutoGeneratedNet( aPins[jj].netName );
246
247 if( bestIsAuto && !jjIsAuto )
248 {
249 // jj has a user-assigned net while best has auto-generated; switch to jj
250 aPins[idxBest].num.clear();
251 idxBest = jj;
252 }
253 else
254 {
255 aPins[jj].num.clear();
256 }
257 }
258 }
259}
260
261
263 const SCH_SHEET_PATH& aSheetPath,
264 std::vector<PIN_INFO>& aPins,
265 bool aKeepUnconnectedPins )
266{
267 wxString ref = aSchSymbol->GetRef( &aSheetPath );
268 wxString ref2;
269
270 CONNECTION_GRAPH* graph = m_schematic->ConnectionGraph();
271
272 for( const SCH_SHEET_PATH& sheet : m_schematic->Hierarchy() )
273 {
274 for( SCH_ITEM* item : sheet.LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
275 {
276 SCH_SYMBOL* comp2 = static_cast<SCH_SYMBOL*>( item );
277
278 ref2 = comp2->GetRef( &sheet );
279
280 if( ref2.CmpNoCase( ref ) != 0 )
281 continue;
282
283 for( const SCH_PIN* pin : comp2->GetPins( &sheet ) )
284 {
285 if( SCH_CONNECTION* conn = pin->Connection( &sheet ) )
286 {
287 const wxString& netName = conn->Name();
288
289 if( !aKeepUnconnectedPins ) // Skip unconnected pins if requested
290 {
291 CONNECTION_SUBGRAPH* sg = graph->FindSubgraphByName( netName, sheet );
292
293 if( !sg || sg->GetNoConnect() || sg->GetItems().size() < 2 )
294 continue;
295 }
296
297 bool valid;
298 std::vector<wxString> numbers = pin->GetStackedPinNumbers( &valid );
299 wxString baseName = pin->GetShownName();
300 wxLogTrace( traceStackedPins,
301 wxString::Format( "CreatePinList(multi): ref='%s' pinNameBase='%s' shownNum='%s' net='%s' valid=%d expand=%zu",
302 ref2, baseName, pin->GetShownNumber(), netName, valid, numbers.size() ) );
303
304 for( const wxString& num : numbers )
305 {
306 wxString pinName = baseName.IsEmpty() ? num : baseName + wxT( "_" ) + num;
307 wxLogTrace( traceStackedPins,
308 wxString::Format( " -> emit pin num='%s' name='%s' net='%s'", num, pinName, netName ) );
309 aPins.emplace_back( num, netName, pinName );
310 }
311 }
312 }
313 }
314 }
315}
Calculate the connectivity of a schematic and generates netlists.
CONNECTION_SUBGRAPH * FindSubgraphByName(const wxString &aNetName, const SCH_SHEET_PATH &aPath)
Return the subgraph for a given net name on a given sheet.
A subgraph is a set of items that are electrically connected on a single sheet.
const std::set< SCH_ITEM * > & GetItems() const
Provide a read-only reference to the items in the subgraph.
const SCH_ITEM * GetNoConnect() const
A base class for most all the KiCad significant classes used in schematics and boards.
Definition eda_item.h:96
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:108
Define a library symbol object.
Definition lib_symbol.h:79
const LIB_ID & GetLibId() const override
Definition lib_symbol.h:148
int GetUnitCount() const override
SCHEMATIC * m_schematic
The schematic we're generating a netlist for.
std::vector< PIN_INFO > CreatePinList(SCH_SYMBOL *aSymbol, const SCH_SHEET_PATH &aSheetPath, bool aKeepUnconnectedPins)
Find a symbol from the DrawList and builds its pin list.
void findAllUnitsOfSymbol(SCH_SYMBOL *aSchSymbol, const SCH_SHEET_PATH &aSheetPath, std::vector< PIN_INFO > &aPins, bool aKeepUnconnectedPins)
Find all units for symbols with multiple symbols per package.
SCH_SYMBOL * findNextSymbol(EDA_ITEM *aItem, const SCH_SHEET_PATH &aSheetPath)
Check if the given symbol should be processed for netlisting.
std::set< LIB_SYMBOL *, LIB_SYMBOL_LESS_THAN > m_libParts
unique library symbols used. LIB_SYMBOL items are sorted by names
void eraseDuplicatePins(std::vector< PIN_INFO > &pins)
Erase duplicate pins.
UNIQUE_STRINGS m_referencesAlreadyFound
Used for "multiple symbols per package" symbols to avoid processing a lib symbol more than once.
static wxString MakeCommandLine(const wxString &aFormatString, const wxString &aNetlistFile, const wxString &aFinalFile, const wxString &aProjectDirectory)
Build up a string that describes a command line for executing a child process.
Each graphical item can have a SCH_CONNECTION describing its logical connection (to a bus or net).
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:162
const std::map< wxString, LIB_SYMBOL * > & GetLibSymbols() const
Fetch a list of unique LIB_SYMBOL object pointers required to properly render each SCH_SYMBOL in this...
Definition sch_screen.h:494
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
SCH_SCREEN * LastScreen()
Schematic symbol object.
Definition sch_symbol.h:69
wxString GetSchSymbolLibraryName() const
std::vector< const SCH_PIN * > GetPins(const SCH_SHEET_PATH *aSheet) const
Retrieve a list of the SCH_PINs for the given sheet path.
std::unique_ptr< LIB_SYMBOL > & GetLibSymbolRef()
Definition sch_symbol.h:177
const wxString GetRef(const SCH_SHEET_PATH *aSheet, bool aIncludeUnit=false) const override
bool IsPower() const override
const wxChar *const traceStackedPins
Flag to enable debug output for stacked pins handling in symbol/pin code.
bool operator()(LIB_SYMBOL *const &libsymbol1, LIB_SYMBOL *const &libsymbol2) const
KIBIS_PIN * pin
wxLogTrace helper definitions.
@ SCH_SYMBOL_T
Definition typeinfo.h:169