56#include <pegtl/contrib/parse_tree.hpp>
58namespace NETLIST_EXPORTER_SPICE_PARSER
62 struct textGrammar : must<spiceSource> {};
64 template <
typename Rule>
struct textSelector : std::false_type {};
65 template <>
struct textSelector<
modelUnit> : std::true_type {};
67 template <>
struct textSelector<
dotControl> : std::true_type {};
69 template <>
struct textSelector<
dotTitle> : std::true_type {};
70 template <>
struct textSelector<
dotTitleTitle> : std::true_type {};
72 template <>
struct textSelector<
dotInclude> : std::true_type {};
75 template <>
struct textSelector<
dotIncludePath> : std::true_type {};
77 template <>
struct textSelector<
kLine> : std::true_type {};
79 template <>
struct textSelector<
dotLine> : std::true_type {};
86 if( !
m_names.count( aProposedName ) )
89 for( uint64_t i = 1; i < UINT64_MAX; ++i )
91 std::string
name = fmt::format(
"{}#{}", aProposedName, i );
104 wxWindow* aDialogParent ) :
106 m_libMgr( &aSchematic->
Prj() ),
107 m_dialogParent( aDialogParent )
132 WriteHead( aFormatter, aNetlistOptions );
143 WriteTail( aFormatter, aNetlistOptions );
151 aFormatter.
Print( 0,
"KiCad schematic\n" );
157 aFormatter.
Print( 0,
".end\n" );
165 std::set<std::string> refNames;
177 cacheDir.AppendDir( wxT(
"ibis" ) );
179 if( !cacheDir.DirExists() )
181 cacheDir.Mkdir( wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL );
183 if( !cacheDir.DirExists() )
185 wxLogTrace( wxT(
"IBIS_CACHE:" ),
186 wxT(
"%s:%s:%d\n * failed to create ibis cache directory '%s'" ),
187 __FILE__, __FUNCTION__, __LINE__, cacheDir.GetPath() );
194 wxString dirName = cacheDir.GetFullPath();
196 if( !dir.Open( dirName ) )
200 wxArrayString fileList;
201 wxString fileSpec = wxT(
"*.cache" );
203 thisFile.SetPath( dirName );
205 size_t numFilesFound = wxDir::GetAllFiles( dirName, &fileList, fileSpec );
207 for(
size_t ii = 0; ii < numFilesFound; ii++ )
210 thisFile.SetFullName( fileList[ii] );
211 wxRemoveFile( thisFile.GetFullPath() );
223 std::vector<PIN_INFO> pins =
CreatePinList( symbol, &sheet,
true );
233 spiceItem.
fields.back().SetText( symbol->
GetRef( &sheet ) );
235 spiceItem.
fields.back().SetText( symbol->
GetFields()[i].GetShownText( 0,
false ) );
240 wxString modelParams;
245 readRefName( sheet, *symbol, spiceItem, refNames );
252 m_items.push_back( std::move( spiceItem ) );
256 msg.Printf(
_(
"Error reading simulation model from symbol '%s':\n%s" ),
271 std::unique_ptr<MARKUP::NODE> root = markupParser.
Parse();
272 std::string converted;
274 std::function<void(
const std::unique_ptr<MARKUP::NODE>&)> convertMarkup =
275 [&](
const std::unique_ptr<MARKUP::NODE>& aNode )
279 if( !aNode->is_root() )
281 if( aNode->isOverbar() )
286 else if( aNode->isSubscript() || aNode->isSuperscript() )
291 if( aNode->has_content() )
292 converted += aNode->string();
295 for(
const std::unique_ptr<MARKUP::NODE>& child : aNode->children )
296 convertMarkup( child );
300 convertMarkup( root );
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(),
'~',
'_' );
313 aNetName = converted;
330 const std::list<SPICE_ITEM>& spiceItems =
GetItems();
332 auto it = std::find_if( spiceItems.begin(), spiceItems.end(),
335 return item.refName == aRefName;
338 if( it != spiceItems.end() )
354 for(
SCH_ITEM* item : sheet.LastScreen()->Items() )
364 wxStringTokenizer tokenizer(
text, wxT(
"\r\n" ), wxTOKEN_STRTOK );
365 bool foundDirective =
false;
368 [](
const wxString& line,
const wxString& dir )
370 return line == dir || line.StartsWith( dir + wxS(
" " ) );
373 while( tokenizer.HasMoreTokens() )
375 wxString line = tokenizer.GetNextToken().Upper();
377 if( line.StartsWith( wxT(
"." ) ) )
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" ) ) )
417 foundDirective =
true;
421 else if( line.StartsWith( wxT(
"K" ) ) )
424 wxStringTokenizer line_t( line, wxT(
" \t" ), wxTOKEN_STRTOK );
427 if( !line_t.HasMoreTokens() || !line_t.GetNextToken().StartsWith( wxT(
"K" ) ) )
431 if( !line_t.HasMoreTokens() || !line_t.GetNextToken().StartsWith( wxT(
"L" ) ) )
435 if( !line_t.HasMoreTokens() || !line_t.GetNextToken().StartsWith( wxT(
"L" ) ) )
440 if( line_t.HasMoreTokens() )
442 foundDirective =
true;
456 SPICE_ITEM& aItem, std::set<std::string>& aRefNames )
460 if( !aRefNames.insert( aItem.
refName ).second )
461 wxASSERT( wxT(
"Duplicate refdes encountered; what happened to ReadyToNetlist()?" ) );
480 int libParamIndex =
static_cast<int>( SIM_MODEL_RAW_SPICE::SPICE_PARAM::LIB );
481 wxString
path = rawSpiceModel->GetParam( libParamIndex ).value;
483 if( !
path.IsEmpty() )
490 cacheFn.AppendDir( wxT(
"ibis" ) );
491 cacheFn.SetFullName( aSymbol.
GetRef( &aSheet ) + wxT(
".cache" ) );
493 wxFile cacheFile( cacheFn.GetFullPath(), wxFile::write );
495 if( !cacheFile.IsOpened() )
500 cacheFn.GetFullPath() ) );
505 cacheFn.GetPath( wxPATH_GET_SEPARATOR ) );
507 cacheFile.Write( wxString( modelData ) );
514 const std::vector<PIN_INFO>& aPins )
522 const std::vector<PIN_INFO>& aPins,
int& aNcCounter )
524 for(
const PIN_INFO& pinInfo : aPins )
535 const wxString& aPath )
541 expandedPath.Replace(
'\\',
'/' );
550 if( fullPath.IsEmpty() )
555 fullPath = expandedPath;
557 else if( wxFileName::GetPathSeparator() ==
'\\' )
560 fullPath.Replace(
'\\',
'/' );
565 fullPath = expandedPath;
568 aFormatter.
Print( 0,
".include \"%s\"\n",
TO_UTF8( fullPath ) );
589 if( !item.model->IsEnabled() )
592 aFormatter.
Print( 0,
"%s", item.model->SpiceGenerator().ModelLine( item ).c_str() );
601 if( !item.model->IsEnabled() )
604 aFormatter.
Print( 0,
"%s", item.model->SpiceGenerator().ItemLine( item ).c_str() );
610 unsigned aNetlistOptions )
const
613 aFormatter.
Print( 0,
".save all\n" );
616 aFormatter.
Print( 0,
".probe alli\n" );
624 std::string itemName = item.model->SpiceGenerator().ItemName( item );
626 if( ( item.model->GetPinCount() >= 2 ) && ( itemName.size() > 0 )
627 && ( itemName.c_str()[0] !=
'A' ) )
629 aFormatter.
Print( 0,
".probe p(%s)\n", itemName.c_str() );
635 [](
const wxString& candidate,
const wxString& dir )
637 return candidate == dir || candidate.StartsWith( dir + wxS(
" " ) );
642 bool simCommand =
false;
644 if( directive.StartsWith(
"." ) )
646 wxString candidate = directive.Upper();
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" ) ) );
666 int& aNcCounter )
const
668 std::string netName = aNetName;
674 netName = fmt::format(
"NC-{}", aNcCounter++ );
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
virtual const wxString Problem() const
what was the problem?
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.
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.
@ OPTION_SAVE_ALL_CURRENTS
@ OPTION_SAVE_ALL_VOLTAGES
@ OPTION_SAVE_ALL_DISSIPATIONS
@ OPTION_ADJUST_INCLUDE_PATHS
@ OPTION_CUR_SHEET_AS_ROOT
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.
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.
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)
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 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,...
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.
int GetFieldCount() const
Return the number of fields in this symbol.
const wxString GetRef(const SCH_SHEET_PATH *aSheet, bool aIncludeUnit=false) const
Return the reference for the given sheet path.
void GetFields(std::vector< SCH_FIELD * > &aVector, bool aVisibleOnly)
Populate a std::vector with SCH_FIELDs.
wxString GetFieldText(const wxString &aFieldName) const
Search for a field named aFieldName and returns text associated with this field.
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)
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
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.
#define THROW_IO_ERROR(msg)
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
KIWAY Kiway & Pgm(), KFCTL_STANDALONE
The global Program "get" accessor.
std::vector< FAB_LAYER_COLOR > dummy
wxString UnescapeString(const wxString &aSource)
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".