52 std::string
name = aProposedName;
56 name = fmt::format(
"{}#{}", aProposedName, ii++ );
64 m_libMgr( &aSchematic->
Prj() )
73 return DoWriteNetlist( wxEmptyString, aNetlistOptions, formatter, aReporter );
106 aFormatter.
Print( 0,
".title KiCad schematic\n" );
112 aFormatter.
Print( 0,
".end\n" );
120 std::set<std::string> refNames;
132 cacheDir.AppendDir( wxT(
"ibis" ) );
134 if( !cacheDir.DirExists() )
136 cacheDir.Mkdir( wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL );
138 if( !cacheDir.DirExists() )
140 wxLogTrace( wxT(
"IBIS_CACHE:" ),
141 wxT(
"%s:%s:%d\n * failed to create ibis cache directory '%s'" ),
142 __FILE__, __FUNCTION__, __LINE__, cacheDir.GetPath() );
149 wxString dirName = cacheDir.GetFullPath();
151 if( !dir.Open( dirName ) )
155 wxArrayString fileList;
156 wxString fileSpec = wxT(
"*.cache" );
158 thisFile.SetPath( dirName );
160 size_t numFilesFound = wxDir::GetAllFiles( dirName, &fileList, fileSpec );
162 for(
size_t ii = 0; ii < numFilesFound; ii++ )
165 thisFile.SetFullName( fileList[ii] );
166 wxRemoveFile( thisFile.GetFullPath() );
179 std::vector<PIN_INFO> pins =
CreatePinList( symbol, sheet,
true );
183 spiceItem.
fields.emplace_back(
VECTOR2I(), -1, symbol, field.GetName() );
186 spiceItem.
fields.back().SetText( symbol->
GetRef( &sheet ) );
188 spiceItem.
fields.back().SetText( field.GetShownText( &sheet,
false ) );
191 readRefName( sheet, *symbol, spiceItem, refNames );
192 readModel( sheet, *symbol, spiceItem, aReporter );
198 m_items.push_back( std::move( spiceItem ) );
209 std::unique_ptr<MARKUP::NODE> root = markupParser.
Parse();
211 std::function<void(
const std::unique_ptr<MARKUP::NODE>&)> convertMarkup =
212 [&](
const std::unique_ptr<MARKUP::NODE>& aNode )
216 if( !aNode->is_root() )
218 if( aNode->isOverbar() )
223 else if( aNode->isSubscript() || aNode->isSuperscript() )
228 if( aNode->has_content() )
229 *aNetName += aNode->string();
232 for(
const std::unique_ptr<MARKUP::NODE>& child : aNode->children )
233 convertMarkup( child );
237 *aNetName = wxEmptyString;
238 convertMarkup( root );
241 aNetName->Replace(
'%',
'_' );
242 aNetName->Replace(
'(',
'_' );
243 aNetName->Replace(
')',
'_' );
244 aNetName->Replace(
',',
'_' );
245 aNetName->Replace(
'[',
'_' );
246 aNetName->Replace(
']',
'_' );
247 aNetName->Replace(
'<',
'_' );
248 aNetName->Replace(
'>',
'_' );
249 aNetName->Replace(
'~',
'_' );
250 aNetName->Replace(
' ',
'_' );
254 if( aNetName->StartsWith( wxS(
"//" ) ) )
255 aNetName->Replace( wxS(
"//" ), wxS(
"/root/" ),
false );
262 return item->model->SpiceGenerator().ItemName( *item );
264 return wxEmptyString;
270 const std::string refName = aRefName.ToStdString();
271 const std::list<SPICE_ITEM>& spiceItems =
GetItems();
273 auto it = std::find_if( spiceItems.begin(), spiceItems.end(),
276 return item.refName == refName;
279 if( it != spiceItems.end() )
295 for(
SCH_ITEM* item : sheet.LastScreen()->Items() )
297 if( item->GetExcludedFromSim() )
301 text =
static_cast<SCH_TEXT*
>( item )->GetShownText( &sheet,
false );
308 wxStringTokenizer tokenizer(
text, wxT(
"\r\n" ), wxTOKEN_STRTOK );
309 bool foundDirective =
false;
312 [](
const wxString& line,
const wxString& dir )
314 return line == dir || line.StartsWith( dir + wxS(
" " ) );
317 while( tokenizer.HasMoreTokens() )
319 wxString line = tokenizer.GetNextToken().Upper();
321 if( line.StartsWith( wxT(
"." ) ) )
323 if( isDirective( line, wxS(
".AC" ) )
324 || isDirective( line, wxS(
".CONTROL" ) )
325 || isDirective( line, wxS(
".CSPARAM" ) )
326 || isDirective( line, wxS(
".DISTO" ) )
327 || isDirective( line, wxS(
".DC" ) )
328 || isDirective( line, wxS(
".ELSE" ) )
329 || isDirective( line, wxS(
".ELSEIF" ) )
330 || isDirective( line, wxS(
".END" ) )
331 || isDirective( line, wxS(
".ENDC" ) )
332 || isDirective( line, wxS(
".ENDIF" ) )
333 || isDirective( line, wxS(
".ENDS" ) )
334 || isDirective( line, wxS(
".FOUR" ) )
335 || isDirective( line, wxS(
".FUNC" ) )
336 || isDirective( line, wxS(
".GLOBAL" ) )
337 || isDirective( line, wxS(
".IC" ) )
338 || isDirective( line, wxS(
".IF" ) )
339 || isDirective( line, wxS(
".INCLUDE" ) )
340 || isDirective( line, wxS(
".LIB" ) )
341 || isDirective( line, wxS(
".MEAS" ) )
342 || isDirective( line, wxS(
".MODEL" ) )
343 || isDirective( line, wxS(
".NODESET" ) )
344 || isDirective( line, wxS(
".NOISE" ) )
345 || isDirective( line, wxS(
".OP" ) )
346 || isDirective( line, wxS(
".OPTIONS" ) )
347 || isDirective( line, wxS(
".PARAM" ) )
348 || isDirective( line, wxS(
".PLOT" ) )
349 || isDirective( line, wxS(
".PRINT" ) )
350 || isDirective( line, wxS(
".PROBE" ) )
351 || isDirective( line, wxS(
".PZ" ) )
352 || isDirective( line, wxS(
".SAVE" ) )
353 || isDirective( line, wxS(
".SENS" ) )
354 || isDirective( line, wxS(
".SP" ) )
355 || isDirective( line, wxS(
".SUBCKT" ) )
356 || isDirective( line, wxS(
".TEMP" ) )
357 || isDirective( line, wxS(
".TF" ) )
358 || isDirective( line, wxS(
".TITLE" ) )
359 || isDirective( line, wxS(
".TRAN" ) )
360 || isDirective( line, wxS(
".WIDTH" ) ) )
362 foundDirective =
true;
366 else if( line.StartsWith( wxT(
"K" ) ) )
369 wxStringTokenizer line_t( line, wxT(
" \t" ), wxTOKEN_STRTOK );
372 if( !line_t.HasMoreTokens() || !line_t.GetNextToken().StartsWith( wxT(
"K" ) ) )
376 if( !line_t.HasMoreTokens() || !line_t.GetNextToken().StartsWith( wxT(
"L" ) ) )
380 if( !line_t.HasMoreTokens() || !line_t.GetNextToken().StartsWith( wxT(
"L" ) ) )
385 if( line_t.HasMoreTokens() )
387 foundDirective =
true;
401 SPICE_ITEM& aItem, std::set<std::string>& aRefNames )
405 if( !aRefNames.insert( aItem.
refName ).second )
406 wxASSERT( wxT(
"Duplicate refdes encountered; what happened to ReadyToNetlist()?" ) );
425 int libParamIndex =
static_cast<int>( SIM_MODEL_RAW_SPICE::SPICE_PARAM::LIB );
426 wxString
path = rawSpiceModel->GetParam( libParamIndex ).value;
428 if( !
path.IsEmpty() )
435 cacheFn.AppendDir( wxT(
"ibis" ) );
436 cacheFn.SetFullName( aSymbol.
GetRef( &aSheet ) + wxT(
".cache" ) );
438 wxFile cacheFile( cacheFn.GetFullPath(), wxFile::write );
440 if( !cacheFile.IsOpened() )
442 wxLogError(
_(
"Could not open file '%s' to write IBIS model" ),
443 cacheFn.GetFullPath() );
448 wxString cacheFilepath = cacheFn.GetPath( wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR );
450 cacheFilepath, aReporter );
452 cacheFile.Write( wxString( modelData ) );
459 const std::vector<PIN_INFO>& aPins )
467 const std::vector<PIN_INFO>& aPins,
int& aNcCounter )
469 for(
const PIN_INFO& pinInfo : aPins )
473 aItem.
pinNetNames.push_back( netName.ToStdString() );
480 std::vector<std::string>& aModifiers )
487 tao::pegtl::string_input<> in( input,
"Sim.NodesFormat field" );
488 std::unique_ptr<tao::pegtl::parse_tree::node> root;
489 std::string singleNodeModifier;
497 for(
const auto& node : root->children )
502 aModifiers.back().append( node->string() );
506 singleNodeModifier.append( node->string() );
511 aModifiers.push_back( singleNodeModifier );
512 singleNodeModifier.erase( singleNodeModifier.begin(), singleNodeModifier.end() );
516 catch(
const tao::pegtl::parse_error& e )
518 THROW_IO_ERROR( wxString::Format(
_(
"Error in parsing model '%s', error: '%s'" ),
524 std::vector<std::string> xspicePattern;
527 if( xspicePattern.empty() )
530 if( xspicePattern.size() != aItem.
pinNetNames.size() )
532 THROW_IO_ERROR( wxString::Format(
_(
"Error in parsing model '%s', wrong number of nodes "
533 "'?' in Sim.NodesFormat compared to connections" ),
540 for( std::string& pattern : xspicePattern )
543 const std::string netName =
" " + *itNetNames +
" ";
544 pattern.replace( pattern.find(
"?" ), 1, netName );
545 *itNetNames = pattern;
551 const wxString& aPath )
557 expandedPath.Replace(
'\\',
'/' );
566 if( fullPath.IsEmpty() )
568 wxLogError(
_(
"Could not find library file '%s'" ), expandedPath );
569 fullPath = expandedPath;
571 else if( wxFileName::GetPathSeparator() ==
'\\' )
574 fullPath.Replace(
'\\',
'/' );
579 fullPath = expandedPath;
582 aFormatter.
Print( 0,
".include \"%s\"\n",
TO_UTF8( fullPath ) );
603 if( !item.model->IsEnabled() )
606 aFormatter.
Print( 0,
"%s", item.model->SpiceGenerator().ModelLine( item ).c_str() );
615 if( !item.model->IsEnabled() )
618 aFormatter.
Print( 0,
"%s", item.model->SpiceGenerator().ItemLine( item ).c_str() );
627 aFormatter.
Print( 0,
".save all\n" );
630 aFormatter.
Print( 0,
".probe alli\n" );
638 std::string itemName = item.model->SpiceGenerator().ItemName( item );
640 if( ( item.model->GetPinCount() >= 2 ) && ( itemName.size() > 0 )
641 && ( itemName.c_str()[0] !=
'A' ) )
643 aFormatter.
Print( 0,
".probe p(%s)\n", itemName.c_str() );
649 [](
const wxString& candidate,
const wxString& dir )
651 return candidate == dir || candidate.StartsWith( dir + wxS(
" " ) );
656 bool simCommand =
false;
658 if( directive.StartsWith(
"." ) )
660 wxString candidate = directive.Upper();
662 simCommand = ( isSimCommand( candidate, wxS(
".AC" ) )
663 || isSimCommand( candidate, wxS(
".DC" ) )
664 || isSimCommand( candidate, wxS(
".TRAN" ) )
665 || isSimCommand( candidate, wxS(
".OP" ) )
666 || isSimCommand( candidate, wxS(
".DISTO" ) )
667 || isSimCommand( candidate, wxS(
".NOISE" ) )
668 || isSimCommand( candidate, wxS(
".PZ" ) )
669 || isSimCommand( candidate, wxS(
".SENS" ) )
670 || isSimCommand( candidate, wxS(
".TF" ) ) );
680 int& aNcCounter )
const
686 if( netName.IsEmpty() )
687 netName.Printf( wxS(
"NC-%d" ), aNcCounter++ );
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 HasMessage() const =0
Returns true if the reporter client is non-empty.
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