53 std::string
name = aProposedName;
57 name = fmt::format(
"{}#{}", aProposedName, ii++ );
65 m_libMgr( &aSchematic->
Prj() )
74 return DoWriteNetlist( wxEmptyString, aNetlistOptions, formatter, aReporter );
107 aFormatter.
Print( 0,
".title KiCad schematic\n" );
113 aFormatter.
Print( 0,
".end\n" );
121 std::set<std::string> refNames;
133 cacheDir.AppendDir( wxT(
"ibis" ) );
135 if( !cacheDir.DirExists() )
137 cacheDir.Mkdir( wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL );
139 if( !cacheDir.DirExists() )
141 wxLogTrace( wxT(
"IBIS_CACHE:" ),
142 wxT(
"%s:%s:%d\n * failed to create ibis cache directory '%s'" ),
143 __FILE__, __FUNCTION__, __LINE__, cacheDir.GetPath() );
150 wxString dirName = cacheDir.GetFullPath();
152 if( !dir.Open( dirName ) )
156 wxArrayString fileList;
157 wxString fileSpec = wxT(
"*.cache" );
159 thisFile.SetPath( dirName );
161 size_t numFilesFound = wxDir::GetAllFiles( dirName, &fileList, fileSpec );
163 for(
size_t ii = 0; ii < numFilesFound; ii++ )
166 thisFile.SetFullName( fileList[ii] );
167 wxRemoveFile( thisFile.GetFullPath() );
182 std::vector<PIN_INFO> pins =
CreatePinList( symbol, sheet,
true );
186 spiceItem.
fields.emplace_back(
VECTOR2I(), -1, symbol, field.GetName() );
189 spiceItem.
fields.back().SetText( symbol->
GetRef( &sheet ) );
191 spiceItem.
fields.back().SetText( field.GetShownText( &sheet,
false ) );
194 readRefName( sheet, *symbol, spiceItem, refNames );
195 readModel( sheet, *symbol, spiceItem, aReporter );
201 m_items.push_back( std::move( spiceItem ) );
217 std::unique_ptr<MARKUP::NODE> root = markupParser.
Parse();
219 std::function<void(
const std::unique_ptr<MARKUP::NODE>&)> convertMarkup =
220 [&](
const std::unique_ptr<MARKUP::NODE>& aNode )
224 if( !aNode->is_root() )
226 if( aNode->isOverbar() )
231 else if( aNode->isSubscript() || aNode->isSuperscript() )
236 if( aNode->has_content() )
237 *aNetName += aNode->string();
240 for(
const std::unique_ptr<MARKUP::NODE>& child : aNode->children )
241 convertMarkup( child );
245 *aNetName = wxEmptyString;
246 convertMarkup( root );
249 aNetName->Replace(
'%',
'_' );
250 aNetName->Replace(
'(',
'_' );
251 aNetName->Replace(
')',
'_' );
252 aNetName->Replace(
',',
'_' );
253 aNetName->Replace(
'[',
'_' );
254 aNetName->Replace(
']',
'_' );
255 aNetName->Replace(
'<',
'_' );
256 aNetName->Replace(
'>',
'_' );
257 aNetName->Replace(
'~',
'_' );
258 aNetName->Replace(
' ',
'_' );
262 if( aNetName->StartsWith( wxS(
"//" ) ) )
263 aNetName->Replace( wxS(
"//" ), wxS(
"/root/" ),
false );
270 return item->model->SpiceGenerator().ItemName( *item );
272 return wxEmptyString;
278 const std::string refName = aRefName.ToStdString();
279 const std::list<SPICE_ITEM>& spiceItems =
GetItems();
281 auto it = std::find_if( spiceItems.begin(), spiceItems.end(),
284 return item.refName == refName;
287 if( it != spiceItems.end() )
303 for(
SCH_ITEM* item : sheet.LastScreen()->Items() )
305 if( item->GetExcludedFromSim() )
309 text =
static_cast<SCH_TEXT*
>( item )->GetShownText( &sheet,
false );
316 wxStringTokenizer tokenizer(
text, wxT(
"\r\n" ), wxTOKEN_STRTOK );
317 bool foundDirective =
false;
320 [](
const wxString& line,
const wxString& dir )
322 return line == dir || line.StartsWith( dir + wxS(
" " ) );
325 while( tokenizer.HasMoreTokens() )
327 wxString line = tokenizer.GetNextToken().Upper();
329 if( line.StartsWith( wxT(
"." ) ) )
331 if( isDirective( line, wxS(
".AC" ) )
332 || isDirective( line, wxS(
".CONTROL" ) )
333 || isDirective( line, wxS(
".CSPARAM" ) )
334 || isDirective( line, wxS(
".DISTO" ) )
335 || isDirective( line, wxS(
".DC" ) )
336 || isDirective( line, wxS(
".ELSE" ) )
337 || isDirective( line, wxS(
".ELSEIF" ) )
338 || isDirective( line, wxS(
".END" ) )
339 || isDirective( line, wxS(
".ENDC" ) )
340 || isDirective( line, wxS(
".ENDIF" ) )
341 || isDirective( line, wxS(
".ENDS" ) )
342 || isDirective( line, wxS(
".FOUR" ) )
343 || isDirective( line, wxS(
".FUNC" ) )
344 || isDirective( line, wxS(
".GLOBAL" ) )
345 || isDirective( line, wxS(
".IC" ) )
346 || isDirective( line, wxS(
".IF" ) )
347 || isDirective( line, wxS(
".INCLUDE" ) )
348 || isDirective( line, wxS(
".LIB" ) )
349 || isDirective( line, wxS(
".MEAS" ) )
350 || isDirective( line, wxS(
".MODEL" ) )
351 || isDirective( line, wxS(
".NODESET" ) )
352 || isDirective( line, wxS(
".NOISE" ) )
353 || isDirective( line, wxS(
".OP" ) )
354 || isDirective( line, wxS(
".OPTIONS" ) )
355 || isDirective( line, wxS(
".PARAM" ) )
356 || isDirective( line, wxS(
".PLOT" ) )
357 || isDirective( line, wxS(
".PRINT" ) )
358 || isDirective( line, wxS(
".PROBE" ) )
359 || isDirective( line, wxS(
".PZ" ) )
360 || isDirective( line, wxS(
".SAVE" ) )
361 || isDirective( line, wxS(
".SENS" ) )
362 || isDirective( line, wxS(
".SP" ) )
363 || isDirective( line, wxS(
".SUBCKT" ) )
364 || isDirective( line, wxS(
".TEMP" ) )
365 || isDirective( line, wxS(
".TF" ) )
366 || isDirective( line, wxS(
".TITLE" ) )
367 || isDirective( line, wxS(
".TRAN" ) )
368 || isDirective( line, wxS(
".WIDTH" ) ) )
370 foundDirective =
true;
374 else if( line.StartsWith( wxT(
"K" ) ) )
377 wxStringTokenizer line_t( line, wxT(
" \t" ), wxTOKEN_STRTOK );
380 if( !line_t.HasMoreTokens() || !line_t.GetNextToken().StartsWith( wxT(
"K" ) ) )
384 if( !line_t.HasMoreTokens() || !line_t.GetNextToken().StartsWith( wxT(
"L" ) ) )
388 if( !line_t.HasMoreTokens() || !line_t.GetNextToken().StartsWith( wxT(
"L" ) ) )
393 if( line_t.HasMoreTokens() )
395 foundDirective =
true;
409 SPICE_ITEM& aItem, std::set<std::string>& aRefNames )
413 if( !aRefNames.insert( aItem.
refName ).second )
414 wxASSERT( wxT(
"Duplicate refdes encountered; what happened to ReadyToNetlist()?" ) );
433 int libParamIndex =
static_cast<int>( SIM_MODEL_RAW_SPICE::SPICE_PARAM::LIB );
434 wxString
path = rawSpiceModel->GetParam( libParamIndex ).value;
436 if( !
path.IsEmpty() )
443 cacheFn.AppendDir( wxT(
"ibis" ) );
444 cacheFn.SetFullName( aSymbol.
GetRef( &aSheet ) + wxT(
".cache" ) );
446 wxFile cacheFile( cacheFn.GetFullPath(), wxFile::write );
448 if( !cacheFile.IsOpened() )
450 wxLogError(
_(
"Could not open file '%s' to write IBIS model" ),
451 cacheFn.GetFullPath() );
456 wxString cacheFilepath = cacheFn.GetPath( wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR );
458 cacheFilepath, aReporter );
460 cacheFile.Write( wxString( modelData ) );
467 const std::vector<PIN_INFO>& aPins )
475 const std::vector<PIN_INFO>& aPins,
int& aNcCounter )
477 for(
const PIN_INFO& pinInfo : aPins )
481 aItem.
pinNetNames.push_back( netName.ToStdString() );
488 std::vector<std::string>& aModifiers )
495 tao::pegtl::string_input<> in( input,
"Sim.NodesFormat field" );
496 std::unique_ptr<tao::pegtl::parse_tree::node> root;
497 std::string singleNodeModifier;
505 for(
const auto& node : root->children )
510 aModifiers.back().append( node->string() );
514 singleNodeModifier.append( node->string() );
519 aModifiers.push_back( singleNodeModifier );
520 singleNodeModifier.erase( singleNodeModifier.begin(), singleNodeModifier.end() );
524 catch(
const tao::pegtl::parse_error& e )
526 THROW_IO_ERROR( wxString::Format(
_(
"Error in parsing model '%s', error: '%s'" ),
532 std::vector<std::string> xspicePattern;
535 if( xspicePattern.empty() )
538 if( xspicePattern.size() != aItem.
pinNetNames.size() )
540 THROW_IO_ERROR( wxString::Format(
_(
"Error in parsing model '%s', wrong number of nodes "
541 "'?' in Sim.NodesFormat compared to connections" ),
548 for( std::string& pattern : xspicePattern )
551 const std::string netName =
" " + *itNetNames +
" ";
552 pattern.replace( pattern.find(
"?" ), 1, netName );
553 *itNetNames = pattern;
559 const wxString& aPath )
565 expandedPath.Replace(
'\\',
'/' );
574 if( fullPath.IsEmpty() )
576 wxLogError(
_(
"Could not find library file '%s'" ), expandedPath );
577 fullPath = expandedPath;
579 else if( wxFileName::GetPathSeparator() ==
'\\' )
582 fullPath.Replace(
'\\',
'/' );
587 fullPath = expandedPath;
590 aFormatter.
Print( 0,
".include \"%s\"\n",
TO_UTF8( fullPath ) );
611 if( !item.model->IsEnabled() )
614 aFormatter.
Print( 0,
"%s", item.model->SpiceGenerator().ModelLine( item ).c_str() );
623 if( !item.model->IsEnabled() )
626 aFormatter.
Print( 0,
"%s", item.model->SpiceGenerator().ItemLine( item ).c_str() );
635 aFormatter.
Print( 0,
".save all\n" );
638 aFormatter.
Print( 0,
".probe alli\n" );
646 std::string itemName = item.model->SpiceGenerator().ItemName( item );
648 if( ( item.model->GetPinCount() >= 2 ) && ( itemName.size() > 0 )
649 && ( itemName.c_str()[0] !=
'A' ) )
651 aFormatter.
Print( 0,
".probe p(%s)\n", itemName.c_str() );
657 [](
const wxString& candidate,
const wxString& dir )
659 return candidate == dir || candidate.StartsWith( dir + wxS(
" " ) );
664 bool simCommand =
false;
666 if( directive.StartsWith(
"." ) )
668 wxString candidate = directive.Upper();
670 simCommand = ( isSimCommand( candidate, wxS(
".AC" ) )
671 || isSimCommand( candidate, wxS(
".DC" ) )
672 || isSimCommand( candidate, wxS(
".TRAN" ) )
673 || isSimCommand( candidate, wxS(
".OP" ) )
674 || isSimCommand( candidate, wxS(
".DISTO" ) )
675 || isSimCommand( candidate, wxS(
".NOISE" ) )
676 || isSimCommand( candidate, wxS(
".PZ" ) )
677 || isSimCommand( candidate, wxS(
".SENS" ) )
678 || isSimCommand( candidate, wxS(
".TF" ) ) );
688 int& aNcCounter )
const
694 if( netName.IsEmpty() )
695 netName.Printf( wxS(
"NC-%d" ), aNcCounter++ );
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
virtual const wxString What() const
A composite of Problem() and Where()
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
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::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.
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
UNIQUE_STRINGS m_referencesAlreadyFound
Used for "multiple symbols per package" symbols to avoid processing a lib symbol more than once.
SCHEMATIC_IFACE * m_schematic
The schematic we're generating a netlist for.
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)
std::list< SPICE_ITEM > m_items
void getNodePattern(SPICE_ITEM &aItem, std::vector< std::string > &aModifiers)
static void ConvertToSpiceMarkup(wxString *aNetName)
Remove formatting wrappers and replace illegal spice net name characters with underscores.
void ReadDirectives(unsigned aNetlistOptions)
@ OPTION_SAVE_ALL_CURRENTS
@ OPTION_SAVE_ALL_VOLTAGES
@ OPTION_SAVE_ALL_DISSIPATIONS
@ OPTION_ADJUST_INCLUDE_PATHS
@ OPTION_CUR_SHEET_AS_ROOT
SCH_SHEET_LIST BuildSheetList(unsigned aNetlistOptions=0) const
Return the paths of exported sheets (either all or the current one).
void readModel(SCH_SHEET_PATH &aSheet, SCH_SYMBOL &aSymbol, SPICE_ITEM &aItem, REPORTER &aReporter)
virtual wxString GenerateItemPinNetName(const wxString &aNetName, int &aNcCounter) const
std::set< wxString > m_nets
Items representing schematic symbols in Spice world.
void readRefName(SCH_SHEET_PATH &aSheet, SCH_SYMBOL &aSymbol, SPICE_ITEM &aItem, std::set< std::string > &aRefNames)
wxString GetItemName(const wxString &aRefName) const
Return name of Spice device corresponding to a schematic symbol.
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).
void writeInclude(OUTPUTFORMATTER &aFormatter, unsigned aNetlistOptions, const wxString &aPath)
virtual void WriteDirectives(const wxString &aSimCommand, unsigned aSimOptions, OUTPUTFORMATTER &candidate) const
SIM_LIB_MGR m_libMgr
Holds libraries and models.
const SPICE_ITEM * FindItem(const wxString &aRefName) const
Find and return the item corresponding to aRefName.
virtual bool ReadSchematicAndLibraries(unsigned aNetlistOptions, REPORTER &aReporter)
Process the schematic and Spice libraries to create net mapping and a list of SPICE_ITEMs.
bool DoWriteNetlist(const wxString &aSimCommand, unsigned aSimOptions, OUTPUTFORMATTER &aFormatter, REPORTER &aReporter)
Write the netlist in aFormatter.
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.
void readNodePattern(SPICE_ITEM &aItem)
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.
NETLIST_EXPORTER_SPICE(SCHEMATIC_IFACE *aSchematic)
bool WriteNetlist(const wxString &aOutFileName, unsigned aNetlistOptions, REPORTER &aReporter) override
Write to specified output file.
static wxString GetUserCachePath()
Gets the stock (install) 3d viewer plugins path.
A pure virtual class used to derive REPORTER objects from.
virtual bool HasMessageOfSeverity(int aSeverityMask) const
Returns true if the reporter has one or more messages matching the specified severity mask.
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)=0
Report a string with a given severity.
virtual SCH_SHEET_PATH & CurrentSheet() const =0
virtual SCH_SHEET_LIST BuildSheetListSortedByPageNumbers() const =0
virtual PROJECT & Prj() const =0
Instances are attached to a symbol or sheet and provide a place for the symbol's value,...
Base class for any item which can be embedded within the SCHEMATIC container class,...
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...
bool GetExcludedFromSim() const
SCH_SHEET * Last() const
Return a pointer to the last SCH_SHEET of the list.
void GetFields(std::vector< SCH_FIELD * > &aVector, bool aVisibleOnly)
Populate a std::vector with SCH_FIELDs.
const wxString GetRef(const SCH_SHEET_PATH *aSheet, bool aIncludeUnit=false) const override
virtual wxString GetShownText(const SCH_SHEET_PATH *aPath, bool aAllowExtraText, int aDepth=0) const
SIM_MODEL & CreateModel(SIM_MODEL::TYPE aType, const std::vector< SCH_PIN * > &aPins, REPORTER &aReporter)
std::map< wxString, std::reference_wrapper< const SIM_LIBRARY > > GetLibraries() const
const SPICE_GENERATOR & SpiceGenerator() const
static std::string GetFieldValue(const std::vector< SCH_FIELD > *aFields, const wxString &aFieldName, bool aResolve=true)
std::string IbisDevice(const SPICE_ITEM &aItem, const PROJECT &aProject, const wxString &aCacheDir, REPORTER &aReporter) const
virtual std::string ModelName(const SPICE_ITEM &aItem) const
bool GetExcludedFromSim() const override
void Clear()
Erase the record.
An 8 bit string that is assuredly encoded in UTF8, and supplies special conversion support to and fro...
const char * c_str() const
const wxString ExpandEnvVarSubstitutions(const wxString &aString, const PROJECT *aProject)
Replace any environment variable & text variable references with their values.
This file is part of the common library.
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.
#define THROW_IO_ERROR(msg)
must_if< error >::control< Rule > control
void delete_if(_Container &__c, _Function &&__f)
Deletes all values from __c for which __f returns true.
PGM_BASE & Pgm()
The global Program "get" accessor.
#define SIM_NODES_FORMAT_FIELD
std::vector< FAB_LAYER_COLOR > dummy
wxString UnescapeString(const wxString &aSource)
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
Notes: spaces are allowed everywhere in any number ~ can only be before ? ~~ is not allowed [] can en...
std::vector< SCH_FIELD > fields
std::vector< std::string > pinNetNames
std::string baseModelName
std::vector< std::string > pinNumbers
@ REFERENCE_FIELD
Field Reference of part, i.e. "IC21".
VECTOR2< int32_t > VECTOR2I