55#include <pegtl/contrib/parse_tree.hpp>
57namespace NETLIST_EXPORTER_SPICE_PARSER
61 struct textGrammar : must<spiceSource> {};
63 template <
typename Rule>
struct textSelector : std::false_type {};
64 template <>
struct textSelector<
modelUnit> : std::true_type {};
66 template <>
struct textSelector<
dotControl> : std::true_type {};
68 template <>
struct textSelector<
dotTitle> : std::true_type {};
69 template <>
struct textSelector<
dotTitleTitle> : std::true_type {};
71 template <>
struct textSelector<
dotInclude> : std::true_type {};
74 template <>
struct textSelector<
dotIncludePath> : std::true_type {};
76 template <>
struct textSelector<
kLine> : std::true_type {};
78 template <>
struct textSelector<
dotLine> : std::true_type {};
85 std::string
name = aProposedName;
89 name = fmt::format(
"{}#{}", aProposedName, ii++ );
96 wxWindow* aDialogParent ) :
98 m_libMgr( &aSchematic->
Prj() ),
99 m_dialogParent( aDialogParent )
108 return DoWriteNetlist( wxEmptyString, aNetlistOptions, formatter, aReporter );
141 aFormatter.
Print( 0,
".title KiCad schematic\n" );
147 aFormatter.
Print( 0,
".end\n" );
155 std::set<std::string> refNames;
167 cacheDir.AppendDir( wxT(
"ibis" ) );
169 if( !cacheDir.DirExists() )
171 cacheDir.Mkdir( wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL );
173 if( !cacheDir.DirExists() )
175 wxLogTrace( wxT(
"IBIS_CACHE:" ),
176 wxT(
"%s:%s:%d\n * failed to create ibis cache directory '%s'" ),
177 __FILE__, __FUNCTION__, __LINE__, cacheDir.GetPath() );
184 wxString dirName = cacheDir.GetFullPath();
186 if( !dir.Open( dirName ) )
190 wxArrayString fileList;
191 wxString fileSpec = wxT(
"*.cache" );
193 thisFile.SetPath( dirName );
195 size_t numFilesFound = wxDir::GetAllFiles( dirName, &fileList, fileSpec );
197 for(
size_t ii = 0; ii < numFilesFound; ii++ )
200 thisFile.SetFullName( fileList[ii] );
201 wxRemoveFile( thisFile.GetFullPath() );
214 std::vector<PIN_INFO> pins =
CreatePinList( symbol, &sheet,
true );
218 spiceItem.
fields.emplace_back(
VECTOR2I(), -1, symbol, field.GetName() );
221 spiceItem.
fields.back().SetText( symbol->
GetRef( &sheet ) );
223 spiceItem.
fields.back().SetText( field.GetShownText( &sheet,
false ) );
226 readRefName( sheet, *symbol, spiceItem, refNames );
227 readModel( sheet, *symbol, spiceItem, aReporter );
233 m_items.push_back( std::move( spiceItem ) );
244 std::unique_ptr<MARKUP::NODE> root = markupParser.
Parse();
245 std::string converted;
247 std::function<void(
const std::unique_ptr<MARKUP::NODE>&)> convertMarkup =
248 [&](
const std::unique_ptr<MARKUP::NODE>& aNode )
252 if( !aNode->is_root() )
254 if( aNode->isOverbar() )
259 else if( aNode->isSubscript() || aNode->isSuperscript() )
264 if( aNode->has_content() )
265 converted += aNode->string();
268 for(
const std::unique_ptr<MARKUP::NODE>& child : aNode->children )
269 convertMarkup( child );
273 convertMarkup( root );
276 std::replace( converted.begin(), converted.end(),
'%',
'_' );
277 std::replace( converted.begin(), converted.end(),
'(',
'_' );
278 std::replace( converted.begin(), converted.end(),
')',
'_' );
279 std::replace( converted.begin(), converted.end(),
',',
'_' );
280 std::replace( converted.begin(), converted.end(),
'[',
'_' );
281 std::replace( converted.begin(), converted.end(),
']',
'_' );
282 std::replace( converted.begin(), converted.end(),
'<',
'_' );
283 std::replace( converted.begin(), converted.end(),
'>',
'_' );
284 std::replace( converted.begin(), converted.end(),
'~',
'_' );
285 std::replace( converted.begin(), converted.end(),
' ',
'_' );
287 aNetName = converted;
304 const std::list<SPICE_ITEM>& spiceItems =
GetItems();
306 auto it = std::find_if( spiceItems.begin(), spiceItems.end(),
309 return item.refName == aRefName;
312 if( it != spiceItems.end() )
328 for(
SCH_ITEM* item : sheet.LastScreen()->Items() )
330 if( item->GetExcludedFromSim() )
334 text =
static_cast<SCH_TEXT*
>( item )->GetShownText( &sheet,
false );
341 wxStringTokenizer tokenizer(
text, wxT(
"\r\n" ), wxTOKEN_STRTOK );
342 bool foundDirective =
false;
345 [](
const wxString& line,
const wxString& dir )
347 return line == dir || line.StartsWith( dir + wxS(
" " ) );
350 while( tokenizer.HasMoreTokens() )
352 wxString line = tokenizer.GetNextToken().Upper();
354 if( line.StartsWith( wxT(
"." ) ) )
356 if( isDirective( line, wxS(
".AC" ) )
357 || isDirective( line, wxS(
".CONTROL" ) )
358 || isDirective( line, wxS(
".CSPARAM" ) )
359 || isDirective( line, wxS(
".DISTO" ) )
360 || isDirective( line, wxS(
".DC" ) )
361 || isDirective( line, wxS(
".ELSE" ) )
362 || isDirective( line, wxS(
".ELSEIF" ) )
363 || isDirective( line, wxS(
".END" ) )
364 || isDirective( line, wxS(
".ENDC" ) )
365 || isDirective( line, wxS(
".ENDIF" ) )
366 || isDirective( line, wxS(
".ENDS" ) )
367 || isDirective( line, wxS(
".FOUR" ) )
368 || isDirective( line, wxS(
".FUNC" ) )
369 || isDirective( line, wxS(
".GLOBAL" ) )
370 || isDirective( line, wxS(
".IC" ) )
371 || isDirective( line, wxS(
".IF" ) )
372 || isDirective( line, wxS(
".INCLUDE" ) )
373 || isDirective( line, wxS(
".LIB" ) )
374 || isDirective( line, wxS(
".MEAS" ) )
375 || isDirective( line, wxS(
".MODEL" ) )
376 || isDirective( line, wxS(
".NODESET" ) )
377 || isDirective( line, wxS(
".NOISE" ) )
378 || isDirective( line, wxS(
".OP" ) )
379 || isDirective( line, wxS(
".OPTIONS" ) )
380 || isDirective( line, wxS(
".PARAM" ) )
381 || isDirective( line, wxS(
".PLOT" ) )
382 || isDirective( line, wxS(
".PRINT" ) )
383 || isDirective( line, wxS(
".PROBE" ) )
384 || isDirective( line, wxS(
".PZ" ) )
385 || isDirective( line, wxS(
".SAVE" ) )
386 || isDirective( line, wxS(
".SENS" ) )
387 || isDirective( line, wxS(
".SP" ) )
388 || isDirective( line, wxS(
".SUBCKT" ) )
389 || isDirective( line, wxS(
".TEMP" ) )
390 || isDirective( line, wxS(
".TF" ) )
391 || isDirective( line, wxS(
".TITLE" ) )
392 || isDirective( line, wxS(
".TRAN" ) )
393 || isDirective( line, wxS(
".WIDTH" ) ) )
395 foundDirective =
true;
399 else if( line.StartsWith( wxT(
"K" ) ) )
402 wxStringTokenizer line_t( line, wxT(
" \t" ), wxTOKEN_STRTOK );
405 if( !line_t.HasMoreTokens() || !line_t.GetNextToken().StartsWith( wxT(
"K" ) ) )
409 if( !line_t.HasMoreTokens() || !line_t.GetNextToken().StartsWith( wxT(
"L" ) ) )
413 if( !line_t.HasMoreTokens() || !line_t.GetNextToken().StartsWith( wxT(
"L" ) ) )
418 if( line_t.HasMoreTokens() )
420 foundDirective =
true;
434 SPICE_ITEM& aItem, std::set<std::string>& aRefNames )
438 if( !aRefNames.insert( aItem.
refName ).second )
439 wxASSERT( wxT(
"Duplicate refdes encountered; what happened to ReadyToNetlist()?" ) );
458 int libParamIndex =
static_cast<int>( SIM_MODEL_RAW_SPICE::SPICE_PARAM::LIB );
459 wxString
path = rawSpiceModel->GetParam( libParamIndex ).value;
461 if( !
path.IsEmpty() )
468 cacheFn.AppendDir( wxT(
"ibis" ) );
469 cacheFn.SetFullName( aSymbol.
GetRef( &aSheet ) + wxT(
".cache" ) );
471 wxFile cacheFile( cacheFn.GetFullPath(), wxFile::write );
473 if( !cacheFile.IsOpened() )
476 "to write IBIS model" ),
477 cacheFn.GetFullPath() ) );
482 cacheFn.GetPath( wxPATH_GET_SEPARATOR ) );
484 cacheFile.Write( wxString( modelData ) );
491 const std::vector<PIN_INFO>& aPins )
499 const std::vector<PIN_INFO>& aPins,
int& aNcCounter )
501 for(
const PIN_INFO& pinInfo : aPins )
512 const wxString& aPath )
518 expandedPath.Replace(
'\\',
'/' );
527 if( fullPath.IsEmpty() )
532 fullPath = expandedPath;
534 else if( wxFileName::GetPathSeparator() ==
'\\' )
537 fullPath.Replace(
'\\',
'/' );
542 fullPath = expandedPath;
545 aFormatter.
Print( 0,
".include \"%s\"\n",
TO_UTF8( fullPath ) );
566 if( !item.model->IsEnabled() )
569 aFormatter.
Print( 0,
"%s", item.model->SpiceGenerator().ModelLine( item ).c_str() );
578 if( !item.model->IsEnabled() )
581 aFormatter.
Print( 0,
"%s", item.model->SpiceGenerator().ItemLine( item ).c_str() );
590 aFormatter.
Print( 0,
".save all\n" );
593 aFormatter.
Print( 0,
".probe alli\n" );
601 std::string itemName = item.model->SpiceGenerator().ItemName( item );
603 if( ( item.model->GetPinCount() >= 2 ) && ( itemName.size() > 0 )
604 && ( itemName.c_str()[0] !=
'A' ) )
606 aFormatter.
Print( 0,
".probe p(%s)\n", itemName.c_str() );
612 [](
const wxString& candidate,
const wxString& dir )
614 return candidate == dir || candidate.StartsWith( dir + wxS(
" " ) );
619 bool simCommand =
false;
621 if( directive.StartsWith(
"." ) )
623 wxString candidate = directive.Upper();
625 simCommand = ( isSimCommand( candidate, wxS(
".AC" ) )
626 || isSimCommand( candidate, wxS(
".DC" ) )
627 || isSimCommand( candidate, wxS(
".TRAN" ) )
628 || isSimCommand( candidate, wxS(
".OP" ) )
629 || isSimCommand( candidate, wxS(
".DISTO" ) )
630 || isSimCommand( candidate, wxS(
".NOISE" ) )
631 || isSimCommand( candidate, wxS(
".PZ" ) )
632 || isSimCommand( candidate, wxS(
".SENS" ) )
633 || isSimCommand( candidate, wxS(
".TF" ) ) );
643 int& aNcCounter )
const
645 std::string netName = aNetName;
651 netName = fmt::format(
"NC-{}", 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::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.
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)
std::string GetItemName(const std::string &aRefName) const
Return name of Spice device corresponding to a schematic symbol.
@ OPTION_SAVE_ALL_CURRENTS
@ OPTION_SAVE_ALL_VOLTAGES
@ OPTION_SAVE_ALL_DISSIPATIONS
@ OPTION_ADJUST_INCLUDE_PATHS
@ OPTION_CUR_SHEET_AS_ROOT
void readModel(SCH_SHEET_PATH &aSheet, SCH_SYMBOL &aSymbol, SPICE_ITEM &aItem, REPORTER &aReporter)
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)
virtual void WriteDirectives(const wxString &aSimCommand, unsigned aSimOptions, OUTPUTFORMATTER &candidate) const
SIM_LIB_MGR m_libMgr
Holds libraries and models.
wxWindow * m_dialogParent
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.
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.
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_LIST GetSheets() const =0
virtual SCH_SHEET_PATH & CurrentSheet() 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...
SCH_SHEET * Last() const
Return a pointer to the last SCH_SHEET of the list.
const wxString GetRef(const SCH_SHEET_PATH *aSheet, bool aIncludeUnit=false) const
Return the reference for the given sheet path.
bool GetExcludedFromSim() const override
void GetFields(std::vector< SCH_FIELD * > &aVector, bool aVisibleOnly)
Populate a std::vector with SCH_FIELDs.
virtual wxString GetShownText(const SCH_SHEET_PATH *aPath, bool aAllowExtraText, int aDepth=0) const
SIM_MODEL & CreateModel(SIM_MODEL::TYPE aType, const std::vector< LIB_PIN * > &aPins, REPORTER &aReporter)
std::map< wxString, std::reference_wrapper< const SIM_LIBRARY > > GetLibraries() const
const SPICE_GENERATOR & SpiceGenerator() const
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...
const char * c_str() const
const wxString ExpandEnvVarSubstitutions(const wxString &aString, const PROJECT *aProject)
Replace any environment variable & text variable references with their values.
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
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.
KIWAY Kiway & Pgm(), KFCTL_STANDALONE
The global Program "get" accessor.
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.
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".