KiCad PCB EDA Suite
netlist_exporter_spice.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-2013 jp.charras at wanadoo.fr
5 * Copyright (C) 2013 SoftPLC Corporation, Dick Hollenbeck <[email protected]>
6 * Copyright (C) 1992-2023 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, you may find one here:
20 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21 * or you may search the http://www.gnu.org website for the version 2 license,
22 * or you may write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24 */
25
26#include <sim/kibis/kibis.h>
31#include <sim/sim_model_ideal.h>
32#include <sim/spice_grammar.h>
33#include <common.h>
34#include <confirm.h>
35#include <pgm_base.h>
36#include <env_paths.h>
37#include <sim/sim_library.h>
39#include <sim/sim_model_kibis.h>
40#include <sim/sim_model.h>
41#include <sch_screen.h>
42#include <sch_text.h>
43#include <sch_textbox.h>
44#include <string_utils.h>
45
47#include <fmt/core.h>
48#include <paths.h>
49#include <wx/dir.h>
50#include <locale_io.h>
51#include "markup_parser.h"
52
53#if 0
54
55#include <pegtl.hpp>
56#include <pegtl/contrib/parse_tree.hpp>
57
58namespace NETLIST_EXPORTER_SPICE_PARSER
59{
60 using namespace SPICE_GRAMMAR;
61
62 struct textGrammar : must<spiceSource> {};
63
64 template <typename Rule> struct textSelector : std::false_type {};
65 template <> struct textSelector<modelUnit> : std::true_type {};
66
67 template <> struct textSelector<dotControl> : std::true_type {};
68
69 template <> struct textSelector<dotTitle> : std::true_type {};
70 template <> struct textSelector<dotTitleTitle> : std::true_type {};
71
72 template <> struct textSelector<dotInclude> : std::true_type {};
73 template <> struct textSelector<dotIncludePathWithoutQuotes> : std::true_type {};
74 template <> struct textSelector<dotIncludePathWithoutApostrophes> : std::true_type {};
75 template <> struct textSelector<dotIncludePath> : std::true_type {};
76
77 template <> struct textSelector<kLine> : std::true_type {};
78
79 template <> struct textSelector<dotLine> : std::true_type {};
80}
81#endif
82
83
84std::string NAME_GENERATOR::Generate( const std::string& aProposedName )
85{
86 if( !m_names.count( aProposedName ) )
87 return aProposedName;
88
89 for( uint64_t i = 1; i < UINT64_MAX; ++i )
90 {
91 std::string name = fmt::format( "{}#{}", aProposedName, i );
92
93 if( !m_names.count( name ) )
94 return name;
95 }
96
97 // Should never happen.
98 THROW_IO_ERROR( wxString::Format( _( "Failed to generate a name for '%s': exceeded UINT64_MAX" ),
99 aProposedName ) );
100}
101
102
104 wxWindow* aDialogParent ) :
105 NETLIST_EXPORTER_BASE( aSchematic ),
106 m_libMgr( &aSchematic->Prj() ),
107 m_dialogParent( aDialogParent )
108{
109}
110
111
112bool NETLIST_EXPORTER_SPICE::WriteNetlist( const wxString& aOutFileName, unsigned aNetlistOptions,
113 REPORTER& aReporter )
114{
115 m_libMgr.SetReporter( &aReporter );
116 FILE_OUTPUTFORMATTER formatter( aOutFileName, wxT( "wt" ), '\'' );
117 return DoWriteNetlist( formatter, aNetlistOptions, aReporter );
118}
119
120
121bool NETLIST_EXPORTER_SPICE::DoWriteNetlist( OUTPUTFORMATTER& aFormatter, unsigned aNetlistOptions,
122 REPORTER& aReporter )
123{
125
126 // Cleanup list to avoid duplicate if the netlist exporter is run more than once.
127 m_rawIncludes.clear();
128
129 if( !ReadSchematicAndLibraries( aNetlistOptions, aReporter ) )
130 return false;
131
132 WriteHead( aFormatter, aNetlistOptions );
133
134 writeIncludes( aFormatter, aNetlistOptions );
135 writeModels( aFormatter );
136
137 // Skip this if there is no netlist to avoid an ngspice segfault
138 if( !m_items.empty() )
139 WriteDirectives( aFormatter, aNetlistOptions );
140
141 writeItems( aFormatter );
142
143 WriteTail( aFormatter, aNetlistOptions );
144
145 return true;
146}
147
148
149void NETLIST_EXPORTER_SPICE::WriteHead( OUTPUTFORMATTER& aFormatter, unsigned aNetlistOptions )
150{
151 aFormatter.Print( 0, "KiCad schematic\n" );
152}
153
154
155void NETLIST_EXPORTER_SPICE::WriteTail( OUTPUTFORMATTER& aFormatter, unsigned aNetlistOptions )
156{
157 aFormatter.Print( 0, ".end\n" );
158}
159
160
162 REPORTER& aReporter )
163{
164 wxString msg;
165 std::set<std::string> refNames; // Set of reference names to check for duplication.
166 int ncCounter = 1;
167
168 ReadDirectives( aNetlistOptions );
169
170 m_nets.clear();
171 m_items.clear();
173 m_libParts.clear();
174
175 wxFileName cacheDir;
176 cacheDir.AssignDir( PATHS::GetUserCachePath() );
177 cacheDir.AppendDir( wxT( "ibis" ) );
178
179 if( !cacheDir.DirExists() )
180 {
181 cacheDir.Mkdir( wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL );
182
183 if( !cacheDir.DirExists() )
184 {
185 wxLogTrace( wxT( "IBIS_CACHE:" ),
186 wxT( "%s:%s:%d\n * failed to create ibis cache directory '%s'" ),
187 __FILE__, __FUNCTION__, __LINE__, cacheDir.GetPath() );
188
189 return false;
190 }
191 }
192
193 wxDir dir;
194 wxString dirName = cacheDir.GetFullPath();
195
196 if( !dir.Open( dirName ) )
197 return false;
198
199 wxFileName thisFile;
200 wxArrayString fileList;
201 wxString fileSpec = wxT( "*.cache" );
202
203 thisFile.SetPath( dirName ); // Set the base path to the cache folder
204
205 size_t numFilesFound = wxDir::GetAllFiles( dirName, &fileList, fileSpec );
206
207 for( size_t ii = 0; ii < numFilesFound; ii++ )
208 {
209 // Completes path to specific file so we can get its "last access" date
210 thisFile.SetFullName( fileList[ii] );
211 wxRemoveFile( thisFile.GetFullPath() );
212 }
213
214 for( SCH_SHEET_PATH& sheet : GetSheets( aNetlistOptions ) )
215 {
216 for( SCH_ITEM* item : sheet.LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
217 {
218 SCH_SYMBOL* symbol = findNextSymbol( item, &sheet );
219
220 if( !symbol || symbol->GetFieldText( SIM_ENABLE_FIELD ) == wxT( "0" ) )
221 continue;
222
223 std::vector<PIN_INFO> pins = CreatePinList( symbol, &sheet, true );
224
225 SPICE_ITEM spiceItem;
226
227 for( int i = 0; i < symbol->GetFieldCount(); ++i )
228 {
229 spiceItem.fields.emplace_back( VECTOR2I(), i, symbol,
230 symbol->GetFields()[ i ].GetName() );
231
232 if( i == REFERENCE_FIELD )
233 spiceItem.fields.back().SetText( symbol->GetRef( &sheet ) );
234 else
235 spiceItem.fields.back().SetText( symbol->GetFields()[i].GetShownText( 0, false ) );
236 }
237
238 wxString deviceType;
239 wxString modelType;
240 wxString modelParams;
241 wxString pinMap;
242
243 try
244 {
245 readRefName( sheet, *symbol, spiceItem, refNames );
246 readModel( sheet, *symbol, spiceItem );
247 readPinNumbers( *symbol, spiceItem, pins );
248 readPinNetNames( *symbol, spiceItem, pins, ncCounter );
249
250 // TODO: transmission line handling?
251
252 m_items.push_back( std::move( spiceItem ) );
253 }
254 catch( const IO_ERROR& e )
255 {
256 msg.Printf( _( "Error reading simulation model from symbol '%s':\n%s" ),
257 symbol->GetRef( &sheet ),
258 e.Problem() );
259 aReporter.Report( msg, RPT_SEVERITY_ERROR );
260 }
261 }
262 }
263
264 return !aReporter.HasMessage();
265}
266
267
269{
270 MARKUP::MARKUP_PARSER markupParser( aNetName );
271 std::unique_ptr<MARKUP::NODE> root = markupParser.Parse();
272 std::string converted;
273
274 std::function<void( const std::unique_ptr<MARKUP::NODE>&)> convertMarkup =
275 [&]( const std::unique_ptr<MARKUP::NODE>& aNode )
276 {
277 if( aNode )
278 {
279 if( !aNode->is_root() )
280 {
281 if( aNode->isOverbar() )
282 {
283 // ~{CLK} is a different signal than CLK
284 converted += '~';
285 }
286 else if( aNode->isSubscript() || aNode->isSuperscript() )
287 {
288 // V_{OUT} is just a pretty-printed version of VOUT
289 }
290
291 if( aNode->has_content() )
292 converted += aNode->string();
293 }
294
295 for( const std::unique_ptr<MARKUP::NODE>& child : aNode->children )
296 convertMarkup( child );
297 }
298 };
299
300 convertMarkup( root );
301
302 // Remove ngspice-disallowed chars
303 std::replace( converted.begin(), converted.end(), '%', '_' );
304 std::replace( converted.begin(), converted.end(), '(', '_' );
305 std::replace( converted.begin(), converted.end(), ')', '_' );
306 std::replace( converted.begin(), converted.end(), ',', '_' );
307 std::replace( converted.begin(), converted.end(), '[', '_' );
308 std::replace( converted.begin(), converted.end(), ']', '_' );
309 std::replace( converted.begin(), converted.end(), '<', '_' );
310 std::replace( converted.begin(), converted.end(), '>', '_' );
311 std::replace( converted.begin(), converted.end(), '~', '_' );
312
313 aNetName = converted;
314}
315
316
317std::string NETLIST_EXPORTER_SPICE::GetItemName( const std::string& aRefName ) const
318{
319 const SPICE_ITEM* item = FindItem( aRefName );
320
321 if( !item )
322 return "";
323
324 return item->model->SpiceGenerator().ItemName( *item );
325}
326
327
328const SPICE_ITEM* NETLIST_EXPORTER_SPICE::FindItem( const std::string& aRefName ) const
329{
330 const std::list<SPICE_ITEM>& spiceItems = GetItems();
331
332 auto it = std::find_if( spiceItems.begin(), spiceItems.end(),
333 [aRefName]( const SPICE_ITEM& item )
334 {
335 return item.refName == aRefName;
336 } );
337
338 if( it != spiceItems.end() )
339 return &*it;
340
341 return nullptr;
342}
343
344
345void NETLIST_EXPORTER_SPICE::ReadDirectives( unsigned aNetlistOptions )
346{
347 wxString msg;
348 wxString text;
349
350 m_directives.clear();
351
352 for( const SCH_SHEET_PATH& sheet : GetSheets( aNetlistOptions ) )
353 {
354 for( SCH_ITEM* item : sheet.LastScreen()->Items() )
355 {
356 if( item->Type() == SCH_TEXT_T )
357 text = static_cast<SCH_TEXT*>( item )->GetShownText();
358 else if( item->Type() == SCH_TEXTBOX_T )
359 text = static_cast<SCH_TEXTBOX*>( item )->GetShownText();
360 else
361 continue;
362
363 // Send anything that contains directives to SPICE
364 wxStringTokenizer tokenizer( text, wxT( "\r\n" ), wxTOKEN_STRTOK );
365 bool foundDirective = false;
366
367 auto isDirective =
368 []( const wxString& line, const wxString& dir )
369 {
370 return line == dir || line.StartsWith( dir + wxS( " " ) );
371 };
372
373 while( tokenizer.HasMoreTokens() )
374 {
375 wxString line = tokenizer.GetNextToken().Upper();
376
377 if( line.StartsWith( wxT( "." ) ) )
378 {
379 if( isDirective( line, wxS( ".AC" ) )
380 || isDirective( line, wxS( ".CONTROL" ) )
381 || isDirective( line, wxS( ".CSPARAM" ) )
382 || isDirective( line, wxS( ".DISTO" ) )
383 || isDirective( line, wxS( ".ELSE" ) )
384 || isDirective( line, wxS( ".ELSEIF" ) )
385 || isDirective( line, wxS( ".END" ) )
386 || isDirective( line, wxS( ".ENDC" ) )
387 || isDirective( line, wxS( ".ENDIF" ) )
388 || isDirective( line, wxS( ".ENDS" ) )
389 || isDirective( line, wxS( ".FOUR" ) )
390 || isDirective( line, wxS( ".FUNC" ) )
391 || isDirective( line, wxS( ".GLOBAL" ) )
392 || isDirective( line, wxS( ".IC" ) )
393 || isDirective( line, wxS( ".IF" ) )
394 || isDirective( line, wxS( ".INCLUDE" ) )
395 || isDirective( line, wxS( ".LIB" ) )
396 || isDirective( line, wxS( ".MEAS" ) )
397 || isDirective( line, wxS( ".MODEL" ) )
398 || isDirective( line, wxS( ".NODESET" ) )
399 || isDirective( line, wxS( ".NOISE" ) )
400 || isDirective( line, wxS( ".OP" ) )
401 || isDirective( line, wxS( ".OPTIONS" ) )
402 || isDirective( line, wxS( ".PARAM" ) )
403 || isDirective( line, wxS( ".PLOT" ) )
404 || isDirective( line, wxS( ".PRINT" ) )
405 || isDirective( line, wxS( ".PROBE" ) )
406 || isDirective( line, wxS( ".PZ" ) )
407 || isDirective( line, wxS( ".SAVE" ) )
408 || isDirective( line, wxS( ".SENS" ) )
409 || isDirective( line, wxS( ".SP" ) )
410 || isDirective( line, wxS( ".SUBCKT" ) )
411 || isDirective( line, wxS( ".TEMP" ) )
412 || isDirective( line, wxS( ".TF" ) )
413 || isDirective( line, wxS( ".TITLE" ) )
414 || isDirective( line, wxS( ".TRAN" ) )
415 || isDirective( line, wxS( ".WIDTH" ) ) )
416 {
417 foundDirective = true;
418 break;
419 }
420 }
421 else if( line.StartsWith( wxT( "K" ) ) )
422 {
423 // Check for mutual inductor declaration
424 wxStringTokenizer line_t( line, wxT( " \t" ), wxTOKEN_STRTOK );
425
426 // Coupling ID
427 if( !line_t.HasMoreTokens() || !line_t.GetNextToken().StartsWith( wxT( "K" ) ) )
428 continue;
429
430 // Inductor 1 ID
431 if( !line_t.HasMoreTokens() || !line_t.GetNextToken().StartsWith( wxT( "L" ) ) )
432 continue;
433
434 // Inductor 2 ID
435 if( !line_t.HasMoreTokens() || !line_t.GetNextToken().StartsWith( wxT( "L" ) ) )
436 continue;
437
438 // That's probably distinctive enough not to bother trying to parse the
439 // coupling value. If there's anything else, assume it's the value.
440 if( line_t.HasMoreTokens() )
441 {
442 foundDirective = true;
443 break;
444 }
445 }
446 }
447
448 if( foundDirective )
449 m_directives.emplace_back( text );
450 }
451 }
452}
453
454
456 SPICE_ITEM& aItem, std::set<std::string>& aRefNames )
457{
458 aItem.refName = aSymbol.GetRef( &aSheet );
459
460 if( !aRefNames.insert( aItem.refName ).second )
461 wxASSERT( wxT( "Duplicate refdes encountered; what happened to ReadyToNetlist()?" ) );
462}
463
464
466 SPICE_ITEM& aItem )
467{
468 SIM_LIBRARY::MODEL libModel = m_libMgr.CreateModel( &aSheet, aSymbol );
469
470 aItem.baseModelName = libModel.name;
471 aItem.model = &libModel.model;
472
473 std::string modelName = aItem.model->SpiceGenerator().ModelName( aItem );
474 // Resolve model name collisions.
476
477 // FIXME: Don't have special cases for raw Spice models and KIBIS.
478 if( auto rawSpiceModel = dynamic_cast<const SIM_MODEL_RAW_SPICE*>( aItem.model ) )
479 {
480 int libParamIndex = static_cast<int>( SIM_MODEL_RAW_SPICE::SPICE_PARAM::LIB );
481 wxString path = rawSpiceModel->GetParam( libParamIndex ).value;
482
483 if( !path.IsEmpty() )
484 m_rawIncludes.insert( path );
485 }
486 else if( auto kibisModel = dynamic_cast<const SIM_MODEL_KIBIS*>( aItem.model ) )
487 {
488 wxFileName cacheFn;
489 cacheFn.AssignDir( PATHS::GetUserCachePath() );
490 cacheFn.AppendDir( wxT( "ibis" ) );
491 cacheFn.SetFullName( aSymbol.GetRef( &aSheet ) + wxT( ".cache" ) );
492
493 wxFile cacheFile( cacheFn.GetFullPath(), wxFile::write );
494
495 if( !cacheFile.IsOpened() )
496 {
498 wxString::Format( _( "Could not open file '%s' to write "
499 "IBIS model" ),
500 cacheFn.GetFullPath() ) );
501 }
502
503 auto spiceGenerator = static_cast<const SPICE_GENERATOR_KIBIS&>( kibisModel->SpiceGenerator() );
504 std::string modelData = spiceGenerator.IbisDevice( aItem, m_schematic->Prj(),
505 cacheFn.GetPath( wxPATH_GET_SEPARATOR ) );
506
507 cacheFile.Write( wxString( modelData ) );
508 m_rawIncludes.insert( cacheFn.GetFullPath() );
509 }
510}
511
512
514 const std::vector<PIN_INFO>& aPins )
515{
516 for( const PIN_INFO& pin : aPins )
517 aItem.pinNumbers.emplace_back( pin.num.ToStdString() );
518}
519
520
522 const std::vector<PIN_INFO>& aPins, int& aNcCounter )
523{
524 for( const PIN_INFO& pinInfo : aPins )
525 {
526 std::string netName = GenerateItemPinNetName( pinInfo.netName.ToStdString(), aNcCounter );
527
528 aItem.pinNetNames.push_back( netName );
529 m_nets.insert( netName );
530 }
531}
532
533
534void NETLIST_EXPORTER_SPICE::writeInclude( OUTPUTFORMATTER& aFormatter, unsigned aNetlistOptions,
535 const wxString& aPath )
536{
537 // First, expand env vars, if any.
538 wxString expandedPath = ExpandEnvVarSubstitutions( aPath, &m_schematic->Prj() );
539
540 // Path may have been authored by someone on a Windows box; convert it to UNIX format
541 expandedPath.Replace( '\\', '/' );
542
543 wxString fullPath;
544
545 if( aNetlistOptions & OPTION_ADJUST_INCLUDE_PATHS )
546 {
547 // Look for the library in known search locations.
548 fullPath = ResolveFile( expandedPath, &Pgm().GetLocalEnvVariables(), &m_schematic->Prj() );
549
550 if( fullPath.IsEmpty() )
551 {
553 wxString::Format( _( "Could not find library file '%s'" ),
554 expandedPath ) );
555 fullPath = expandedPath;
556 }
557 else if( wxFileName::GetPathSeparator() == '\\' )
558 {
559 // Convert it to UNIX format (again) if ResolveFile() returned a Windows style path
560 fullPath.Replace( '\\', '/' );
561 }
562 }
563 else
564 {
565 fullPath = expandedPath;
566 }
567
568 aFormatter.Print( 0, ".include \"%s\"\n", TO_UTF8( fullPath ) );
569}
570
571
572void NETLIST_EXPORTER_SPICE::writeIncludes( OUTPUTFORMATTER& aFormatter, unsigned aNetlistOptions )
573{
574 for( const auto& [path, library] : m_libMgr.GetLibraries() )
575 {
576 if( dynamic_cast<const SIM_LIBRARY_SPICE*>( &library.get() ) )
577 writeInclude( aFormatter, aNetlistOptions, path );
578 }
579
580 for( const wxString& path : m_rawIncludes )
581 writeInclude( aFormatter, aNetlistOptions, path );
582}
583
584
586{
587 for( const SPICE_ITEM& item : m_items )
588 {
589 if( !item.model->IsEnabled() )
590 continue;
591
592 aFormatter.Print( 0, "%s", item.model->SpiceGenerator().ModelLine( item ).c_str() );
593 }
594}
595
596
598{
599 for( const SPICE_ITEM& item : m_items )
600 {
601 if( !item.model->IsEnabled() )
602 continue;
603
604 aFormatter.Print( 0, "%s", item.model->SpiceGenerator().ItemLine( item ).c_str() );
605 }
606}
607
608
610 unsigned aNetlistOptions ) const
611{
612 if( aNetlistOptions & OPTION_SAVE_ALL_VOLTAGES )
613 aFormatter.Print( 0, ".save all\n" );
614
615 if( aNetlistOptions & OPTION_SAVE_ALL_CURRENTS )
616 aFormatter.Print( 0, ".probe alli\n" );
617
618 if( aNetlistOptions & OPTION_SAVE_ALL_DISSIPATIONS )
619 {
620 for( const SPICE_ITEM& item : m_items )
621 {
622 // ngspice (v39) does not support power measurement for XSPICE devices
623 // XPSICE devices are marked with 'A'
624 std::string itemName = item.model->SpiceGenerator().ItemName( item );
625
626 if( ( item.model->GetPinCount() >= 2 ) && ( itemName.size() > 0 )
627 && ( itemName.c_str()[0] != 'A' ) )
628 {
629 aFormatter.Print( 0, ".probe p(%s)\n", itemName.c_str() );
630 }
631 }
632 }
633
634 auto isSimCommand =
635 []( const wxString& candidate, const wxString& dir )
636 {
637 return candidate == dir || candidate.StartsWith( dir + wxS( " " ) );
638 };
639
640 for( const wxString& directive : m_directives )
641 {
642 bool simCommand = false;
643
644 if( directive.StartsWith( "." ) )
645 {
646 wxString candidate = directive.Upper();
647
648 simCommand = ( isSimCommand( candidate, wxS( ".AC" ) )
649 || isSimCommand( candidate, wxS( ".DC" ) )
650 || isSimCommand( candidate, wxS( ".TRAN" ) )
651 || isSimCommand( candidate, wxS( ".OP" ) )
652 || isSimCommand( candidate, wxS( ".DISTO" ) )
653 || isSimCommand( candidate, wxS( ".NOISE" ) )
654 || isSimCommand( candidate, wxS( ".PZ" ) )
655 || isSimCommand( candidate, wxS( ".SENS" ) )
656 || isSimCommand( candidate, wxS( ".TF" ) ) );
657 }
658
659 if( !simCommand || ( aNetlistOptions & OPTION_SIM_COMMAND ) )
660 aFormatter.Print( 0, "%s\n", UTF8( directive ).c_str() );
661 }
662}
663
664
665std::string NETLIST_EXPORTER_SPICE::GenerateItemPinNetName( const std::string& aNetName,
666 int& aNcCounter ) const
667{
668 std::string netName = aNetName;
669
670 ConvertToSpiceMarkup( netName );
671 netName = std::string( UnescapeString( netName ).ToUTF8() );
672
673 if( netName == "" )
674 netName = fmt::format( "NC-{}", aNcCounter++ );
675
676 return netName;
677}
678
679
680SCH_SHEET_LIST NETLIST_EXPORTER_SPICE::GetSheets( unsigned aNetlistOptions ) const
681{
682 if( aNetlistOptions & OPTION_CUR_SHEET_AS_ROOT )
684 else
685 return m_schematic->GetSheets();
686}
687
const char * name
Definition: DXF_plotter.cpp:56
Used for text file output.
Definition: richio.h:457
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
Definition: ki_exception.h:76
virtual const wxString Problem() const
what was the problem?
Definition: exceptions.cpp:46
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition: locale_io.h:41
std::unique_ptr< NODE > Parse()
std::unordered_set< std::string > m_names
std::string Generate(const std::string &aProposedName)
An abstract class used for the netlist exporters that Eeschema supports.
std::set< LIB_SYMBOL *, LIB_SYMBOL_LESS_THAN > m_libParts
unique library symbols used. LIB_SYMBOL items are sorted by names
std::vector< PIN_INFO > CreatePinList(SCH_SYMBOL *aSymbol, SCH_SHEET_PATH *aSheetPath, bool aKeepUnconnectedPins)
Find a symbol from the DrawList and builds its pin list.
UNIQUE_STRINGS m_referencesAlreadyFound
Used for "multiple symbols per package" symbols to avoid processing a lib symbol more than once.
SCH_SYMBOL * findNextSymbol(EDA_ITEM *aItem, SCH_SHEET_PATH *aSheetPath)
Check if the given symbol should be processed for netlisting.
SCHEMATIC_IFACE * m_schematic
The schematic we're generating a netlist for.
bool DoWriteNetlist(OUTPUTFORMATTER &aFormatter, unsigned aNetlistOptions, REPORTER &aReporter)
Write the netlist in aFormatter.
void readPinNetNames(SCH_SYMBOL &aSymbol, SPICE_ITEM &aItem, const std::vector< PIN_INFO > &aPins, int &aNcCounter)
void writeModels(OUTPUTFORMATTER &aFormatter)
void writeIncludes(OUTPUTFORMATTER &aFormatter, unsigned aNetlistOptions)
NETLIST_EXPORTER_SPICE(SCHEMATIC_IFACE *aSchematic, wxWindow *aDialogParent=nullptr)
std::list< SPICE_ITEM > m_items
void ReadDirectives(unsigned aNetlistOptions)
virtual void WriteDirectives(OUTPUTFORMATTER &candidate, unsigned aNetlistOptions) const
std::string GetItemName(const std::string &aRefName) const
Return name of Spice device corresponding to a schematic symbol.
SCH_SHEET_LIST GetSheets(unsigned aNetlistOptions=0) const
Return the paths of exported sheets (either all or the current one).
void readRefName(SCH_SHEET_PATH &aSheet, SCH_SYMBOL &aSymbol, SPICE_ITEM &aItem, std::set< std::string > &aRefNames)
static void ConvertToSpiceMarkup(std::string &aNetName)
Remove formatting wrappers and replace illegal spice net name characters with underscores.
void writeItems(OUTPUTFORMATTER &aFormatter)
std::vector< wxString > m_directives
Spice directives found in the schematic sheet.
virtual void WriteHead(OUTPUTFORMATTER &aFormatter, unsigned aNetlistOptions)
Write the netlist head (title and so on).
virtual std::string GenerateItemPinNetName(const std::string &aNetName, int &aNcCounter) const
const SPICE_ITEM * FindItem(const std::string &aRefName) const
Find and return the item corresponding to aRefName.
void writeInclude(OUTPUTFORMATTER &aFormatter, unsigned aNetlistOptions, const wxString &aPath)
SIM_LIB_MGR m_libMgr
Holds libraries and models.
virtual bool ReadSchematicAndLibraries(unsigned aNetlistOptions, REPORTER &aReporter)
Process the schematic and Spice libraries to create net mapping and a list of SPICE_ITEMs.
std::set< std::string > m_nets
Items representing schematic symbols in Spice world.
void readPinNumbers(SCH_SYMBOL &aSymbol, SPICE_ITEM &aItem, const std::vector< PIN_INFO > &aPins)
const std::list< SPICE_ITEM > & GetItems() const
Return the list of items representing schematic symbols in the Spice world.
std::set< wxString > m_rawIncludes
include directives found in symbols
virtual void WriteTail(OUTPUTFORMATTER &aFormatter, unsigned aNetlistOptions)
Write the tail (.end).
NAME_GENERATOR m_modelNameGenerator
Generates unique model names.
bool WriteNetlist(const wxString &aOutFileName, unsigned aNetlistOptions, REPORTER &aReporter) override
Write to specified output file.
void readModel(SCH_SHEET_PATH &aSheet, SCH_SYMBOL &aSymbol, SPICE_ITEM &aItem)
An interface used to output 8 bit text in a convenient way.
Definition: richio.h:310
int PRINTF_FUNC Print(int nestLevel, const char *fmt,...)
Format and write text to the output stream.
Definition: richio.cpp:433
static wxString GetUserCachePath()
Gets the stock (install) 3d viewer plugins path.
Definition: paths.cpp:321
A pure virtual class used to derive REPORTER objects from.
Definition: reporter.h:71
virtual bool HasMessage() const =0
Returns true if the reporter client is non-empty.
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)=0
Report a string with a given severity.
virtual SCH_SHEET_LIST GetSheets() const =0
virtual SCH_SHEET_PATH & CurrentSheet() const =0
virtual PROJECT & Prj() const =0
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:147
A container for handling SCH_SHEET_PATH objects in a flattened hierarchy.
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
SCH_SHEET * Last() const
Return a pointer to the last SCH_SHEET of the list.
Schematic symbol object.
Definition: sch_symbol.h:81
int GetFieldCount() const
Return the number of fields in this symbol.
Definition: sch_symbol.h:486
const wxString GetRef(const SCH_SHEET_PATH *aSheet, bool aIncludeUnit=false) const
Return the reference for the given sheet path.
Definition: sch_symbol.cpp:674
void GetFields(std::vector< SCH_FIELD * > &aVector, bool aVisibleOnly)
Populate a std::vector with SCH_FIELDs.
Definition: sch_symbol.cpp:901
wxString GetFieldText(const wxString &aFieldName) const
Search for a field named aFieldName and returns text associated with this field.
Definition: sch_symbol.cpp:889
wxString GetShownText(int aDepth=0, bool aAllowExtraText=true) const override
Return the string actually shown after processing of the base text.
void SetReporter(REPORTER *aReporter)
Definition: sim_lib_mgr.h:46
std::map< wxString, std::reference_wrapper< const SIM_LIBRARY > > GetLibraries() const
SIM_MODEL & CreateModel(SIM_MODEL::TYPE aType, const std::vector< LIB_PIN * > &aPins)
const SPICE_GENERATOR & SpiceGenerator() const
Definition: sim_model.h:419
std::string IbisDevice(const SPICE_ITEM &aItem, const PROJECT &aProject, const wxString &aCacheDir) const
virtual std::string ItemName(const SPICE_ITEM &aItem) const
virtual std::string ModelName(const SPICE_ITEM &aItem) const
void Clear()
Erase the record.
An 8 bit string that is assuredly encoded in UTF8, and supplies special conversion support to and fro...
Definition: utf8.h:71
const char * c_str() const
Definition: utf8.h:102
const wxString ExpandEnvVarSubstitutions(const wxString &aString, const PROJECT *aProject)
Replace any environment variable & text variable references with their values.
Definition: common.cpp:299
The common library.
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition: confirm.cpp:325
This file is part of the common library.
#define _(s)
wxString ResolveFile(const wxString &aFileName, const ENV_VAR_MAP *aEnvVars, const PROJECT *aProject)
Search the default paths trying to find one with the requested file.
Definition: env_paths.cpp:164
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:38
PROJECT & Prj()
Definition: kicad.cpp:573
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
Definition: macros.h:96
see class PGM_BASE
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
@ RPT_SEVERITY_ERROR
#define SIM_ENABLE_FIELD
Definition: sim_model.h:56
KIWAY Kiway & Pgm(), KFCTL_STANDALONE
The global Program "get" accessor.
Definition: single_top.cpp:111
std::vector< FAB_LAYER_COLOR > dummy
wxString UnescapeString(const wxString &aSource)
SIM_MODEL & model
Definition: sim_library.h:41
std::string name
Definition: sim_library.h:40
std::string refName
std::vector< SCH_FIELD > fields
std::string modelName
const SIM_MODEL * model
std::vector< std::string > pinNetNames
std::string baseModelName
std::vector< std::string > pinNumbers
@ REFERENCE_FIELD
Field Reference of part, i.e. "IC21".
@ SCH_SYMBOL_T
Definition: typeinfo.h:156
@ SCH_TEXT_T
Definition: typeinfo.h:150
@ SCH_TEXTBOX_T
Definition: typeinfo.h:149
VECTOR2< int > VECTOR2I
Definition: vector2d.h:590