35#include <wx/stdpaths.h>
89 wxLogTrace(
traceNgspice,
"Sending Ngspice configuration command '%s'.", command );
115 std::vector<std::string> retVal;
117 if( allVectors !=
nullptr )
119 for(
char**
plot = allVectors; *
plot !=
nullptr;
plot++ )
122 retVal.reserve( noOfVectors );
124 for(
int i = 0; i < noOfVectors; i++, allVectors++ )
126 std::string vec = *allVectors;
127 retVal.push_back( std::move( vec ) );
139 std::vector<COMPLEX> data;
147 int length = aMaxLen < 0 ? vi->v_length : std::min( aMaxLen, vi->v_length );
148 data.reserve( length );
152 for(
int i = 0; i < length; i++ )
153 data.emplace_back( vi->v_realdata[i], 0.0 );
155 else if( vi->v_compdata )
157 for(
int i = 0; i < length; i++ )
158 data.emplace_back( vi->v_compdata[i].cx_real, vi->v_compdata[i].cx_imag );
169 std::vector<double> data;
177 int length = aMaxLen < 0 ? vi->v_length : std::min( aMaxLen, vi->v_length );
178 data.reserve( length );
182 for(
int i = 0; i < length; i++ )
183 data.push_back( vi->v_realdata[i] );
185 else if( vi->v_compdata )
187 for(
int i = 0; i < length; i++ )
188 data.push_back( vi->v_compdata[i].cx_real );
199 std::vector<double> data;
207 int length = aMaxLen < 0 ? vi->v_length : std::min( aMaxLen, vi->v_length );
208 data.reserve( length );
212 for(
int i = 0; i < length; i++ )
213 data.push_back( vi->v_compdata[i].cx_imag );
224 std::vector<double> data;
232 int length = aMaxLen < 0 ? vi->v_length : std::min( aMaxLen, vi->v_length );
233 data.reserve( length );
237 for(
int i = 0; i < length; i++ )
238 data.push_back( vi->v_realdata[i] );
240 else if( vi->v_compdata )
242 for(
int i = 0; i < length; i++ )
243 data.push_back( hypot( vi->v_compdata[i].cx_real, vi->v_compdata[i].cx_imag ) );
254 std::vector<double> data;
262 int length = aMaxLen < 0 ? vi->v_length : std::min( aMaxLen, vi->v_length );
263 data.reserve( length );
267 for(
int i = 0; i < length; i++ )
268 data.push_back( 0.0 );
270 else if( vi->v_compdata )
272 for(
int i = 0; i < length; i++ )
273 data.push_back( atan2( vi->v_compdata[i].cx_imag, vi->v_compdata[i].cx_real ) );
281bool NGSPICE::Attach(
const std::shared_ptr<SIMULATION_MODEL>& aModel,
const wxString& aSimCommand,
282 unsigned aSimOptions,
const wxString& aInputPath,
REPORTER& aReporter )
289 if(
model &&
model->GetNetlist( aSimCommand, aSimOptions, &formatter, aReporter ) )
297 Command(
"echo Command: esave none" );
314 std::stringstream ss( aNetlist );
319 std::vector<std::string> ownedLines;
322 for( std::string line; std::getline( ss, line ); )
326 ownedLines.push_back( std::move( line ) );
329 std::vector<char*> lines;
330 lines.reserve( ownedLines.size() + 1 );
332 for( std::string& line : ownedLines )
333 lines.push_back( line.data() );
335 lines.push_back(
nullptr );
390 case SIGSEGV: signalName = wxT(
"SIGSEGV (segmentation fault)" );
break;
391 case SIGABRT: signalName = wxT(
"SIGABRT (abort)" );
break;
392 case SIGFPE: signalName = wxT(
"SIGFPE (floating point exception)" );
break;
393 case SIGILL: signalName = wxT(
"SIGILL (illegal instruction)" );
break;
394 default: signalName = wxString::Format( wxT(
"signal %d" ), signal );
break;
398 _(
"Simulation crashed (%s). This is usually caused by a bug in ngspice "
399 "or an invalid netlist. The simulator will be reset." ),
427 return wxS(
"frequency" );
433 if( vector.Lower().EndsWith( wxS(
"-sweep" ) ) )
437 return wxS(
"sweep" );
440 return wxS(
"time" );
443 return wxEmptyString;
452 std::vector<std::string> commands;
454 wxCHECK( settings, commands );
464 default: wxFAIL_MSG( wxString::Format(
"Undefined NGSPICE_COMPATIBILITY_MODE %d.",
484 const wxStandardPaths& stdPaths = wxStandardPaths::Get();
486 if(
m_dll.IsLoaded() )
491 wxFileName dllFile(
"", NGSPICE_DLL_FILE );
492#if defined(__WINDOWS__)
493 #if defined( _MSC_VER )
494 std::vector<std::string> dllPaths = {
"" };
496 std::vector<std::string> dllPaths = {
"",
"/mingw64/bin",
"/mingw32/bin" };
498#elif defined(__WXMAC__)
499 std::vector<std::string> dllPaths = {
500 PATHS::GetOSXKicadUserDataDir().ToStdString() +
"/PlugIns/ngspice",
501 PATHS::GetOSXKicadMachineDataDir().ToStdString() +
"/PlugIns/ngspice",
504 stdPaths.GetPluginsDir().ToStdString() +
"/sim",
507 wxFileName( stdPaths.GetExecutablePath() ).GetPath().ToStdString() +
508 "/../../../../../Contents/PlugIns/sim"
511 std::vector<std::string> dllPaths = {
"/usr/local/lib" };
514 if( wxGetEnv( wxT(
"KICAD_RUN_FROM_BUILD_DIR" ),
nullptr ) )
515 dllPaths.emplace_back( NGSPICE_DLL_DIR );
517#if defined(__WINDOWS__) || (__WXMAC__)
518 for(
const auto&
path : dllPaths )
520 dllFile.SetPath(
path );
521 wxLogTrace(
traceNgspice,
"libngspice search path: %s", dllFile.GetFullPath() );
522 m_dll.Load( dllFile.GetFullPath(), wxDL_VERBATIM | wxDL_QUIET | wxDL_NOW );
524 if(
m_dll.IsLoaded() )
526 wxLogTrace(
traceNgspice,
"libngspice path found in: %s", dllFile.GetFullPath() );
531 if( !
m_dll.IsLoaded() )
532 m_dll.Load( wxDynamicLibrary::CanonicalizeName(
"ngspice" ) );
535 m_dll.Load( NGSPICE_DLL_FILE, wxDL_VERBATIM | wxDL_QUIET | wxDL_NOW );
538 if( !
m_dll.IsLoaded() )
540 for(
const auto&
path : dllPaths )
542 dllFile.SetPath(
path );
543 wxLogTrace(
traceNgspice,
"libngspice search path: %s", dllFile.GetFullPath() );
544 m_dll.Load( dllFile.GetFullPath(), wxDL_VERBATIM | wxDL_QUIET | wxDL_NOW );
546 if(
m_dll.IsLoaded() )
548 wxLogTrace(
traceNgspice,
"libngspice path found in: %s", dllFile.GetFullPath() );
555 if( !
m_dll.IsLoaded() )
556 throw std::runtime_error(
_(
"Unable to load ngspice shared library. Please check your install." ).
ToStdString() );
571 if(
m_dll.HasSymbol(
"ngSpice_LockRealloc" ) )
582 wxString cwd( wxGetCwd() );
583 wxFileName exeDir( stdPaths.GetExecutablePath() );
584 wxSetWorkingDirectory( exeDir.GetPath() );
590 if( !cmPath.empty() )
591 Command(
"set __CMPATH=\"" + cmPath +
"\"" );
594 const std::vector<std::string> spiceinitPaths =
598 stdPaths.GetPluginsDir().ToStdString() +
"/sim/ngspice/scripts",
599 wxFileName( stdPaths.GetExecutablePath() ).GetPath().ToStdString() +
600 "/../../../../../Contents/PlugIns/sim/ngspice/scripts"
608 bool foundSpiceinit =
false;
610 for(
const auto&
path : spiceinitPaths )
617 foundSpiceinit =
true;
624 if( !foundSpiceinit && !cmPath.empty() )
628 wxSetWorkingDirectory( cwd );
641 std::vector<char*> lines;
642 lines.push_back( strdup(
"*" ) );
643 lines.push_back( strdup(
".end" ) );
644 lines.push_back(
nullptr );
648 for(
auto line : lines )
657 if( !wxFileName::FileExists( aFileName ) )
662 if( !file.Open( aFileName ) )
665 for( wxString& cmd = file.GetFirstLine(); !file.Eof(); cmd = file.GetNextLine() )
674 const std::vector<std::string> cmPaths =
677 "/Applications/ngspice/lib/ngspice",
678 "Contents/Frameworks",
679 wxStandardPaths::Get().GetPluginsDir().ToStdString() +
"/sim/ngspice",
680 wxFileName( wxStandardPaths::Get().GetExecutablePath() ).GetPath().ToStdString() +
681 "/../../../../../Contents/PlugIns/sim/ngspice",
682 "../Plugins/sim/ngspice",
684 "../eeschema/ngspice",
691 for(
const auto&
path : cmPaths )
695 if( wxFileName::FileExists(
path +
"/spice2poly.cm" ) )
702 return std::string();
721 wxArrayString cmFiles;
722 size_t count = wxDir::GetAllFiles( aPath, &cmFiles );
724 for(
const auto& cm : cmFiles )
725 Command( fmt::format(
"codemodel '{}'", cm.ToStdString() ) );
735 std::lock_guard<std::mutex> lock(
sim->m_reporterMutex );
741 if( ( strncasecmp( aWhat,
"stdout ", 7 ) == 0 )
742 || ( strncasecmp( aWhat,
"stderr ", 7 ) == 0 ) )
766 sim->restoreSignalHandlers();
770 std::lock_guard<std::mutex> lock(
sim->m_reporterMutex );
790 std::lock_guard<std::mutex> lock(
sim->m_reporterMutex );
799 reporter->Report(
_(
"Simulation terminated by ngspice. This may be caused by insufficient "
800 "memory or an internal error. The simulator will be reset." ) );
848 struct sigaction* oldAction =
nullptr;
858 if( oldAction && oldAction->sa_handler != SIG_DFL && oldAction->sa_handler != SIG_IGN )
860 oldAction->sa_handler( aSignal );
865 signal( aSignal, SIG_DFL );
884 pthread_exit(
nullptr );
898 struct sigaction newAction;
900 sigemptyset( &newAction.sa_mask );
901 newAction.sa_flags = 0;
924static bool s_exceptionHandlersInstalled =
false;
925static PVOID s_vectoredHandler =
nullptr;
926static DWORD s_mainThreadId = 0;
928long __stdcall NGSPICE::sehHandler( _EXCEPTION_POINTERS* aException )
930 if( !aException || !aException->ExceptionRecord )
931 return EXCEPTION_CONTINUE_SEARCH;
933 if( GetCurrentThreadId() == s_mainThreadId )
934 return EXCEPTION_CONTINUE_SEARCH;
938 switch( aException->ExceptionRecord->ExceptionCode )
940 case EXCEPTION_ACCESS_VIOLATION:
941 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
942 case EXCEPTION_DATATYPE_MISALIGNMENT:
943 case EXCEPTION_STACK_OVERFLOW:
946 case EXCEPTION_ILLEGAL_INSTRUCTION:
947 case EXCEPTION_PRIV_INSTRUCTION:
950 case EXCEPTION_INT_DIVIDE_BY_ZERO:
951 case EXCEPTION_INT_OVERFLOW:
952 case EXCEPTION_FLT_DIVIDE_BY_ZERO:
953 case EXCEPTION_FLT_INVALID_OPERATION:
954 case EXCEPTION_FLT_OVERFLOW:
955 case EXCEPTION_FLT_UNDERFLOW:
956 case EXCEPTION_FLT_INEXACT_RESULT:
957 case EXCEPTION_FLT_STACK_CHECK:
961 return EXCEPTION_CONTINUE_SEARCH;
971 if( aException->ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW )
972 TerminateThread( GetCurrentThread(), 1 );
976 return EXCEPTION_CONTINUE_EXECUTION;
982 wxUnusedVar( aSignal );
988 if( s_exceptionHandlersInstalled )
991 s_mainThreadId = GetCurrentThreadId();
996 s_vectoredHandler = AddVectoredExceptionHandler( 1, &NGSPICE::sehHandler );
997 s_exceptionHandlersInstalled = ( s_vectoredHandler != nullptr );
1003 if( s_exceptionHandlersInstalled )
1005 RemoveVectoredExceptionHandler( s_vectoredHandler );
1006 s_vectoredHandler =
nullptr;
1007 s_exceptionHandlersInstalled =
false;
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Execute commands from a file.
Container for Ngspice simulator settings.
NGSPICE_COMPATIBILITY_MODE GetCompatibilityMode() const
std::vector< std::string > AllVectors() const override final
Return a requested vector with complex values.
static std::atomic< bool > s_crashed
Set by signal handler when ngspice crashes.
ngSpice_Circ m_ngSpice_Circ
bool Command(const std::string &aCmd) override final
char **(* ngSpice_AllVecs)(char *plotname)
ngSpice_AllPlots m_ngSpice_AllPlots
static int cbControlledExit(int aStatus, NG_BOOL aImmediate, NG_BOOL aExitOnQuit, int aId, void *aUser)
void restoreSignalHandlers()
int(* ngSpice_Circ)(char **circarray)
ngSpice_UnlockRealloc m_ngSpice_UnlockRealloc
char **(* ngSpice_AllPlots)(void)
bool IsRunning() override final
Execute a Spice command as if it was typed into console.
std::vector< double > GetImaginaryVector(const std::string &aName, int aMaxLen=-1) override final
Return a requested vector with magnitude values.
virtual const std::string GetNetlist() const override final
Cleans simulation data (i.e.
char *(* ngSpice_CurPlot)(void)
ngSpice_Init m_ngSpice_Init
void updateNgspiceSettings()
Check a few different locations for codemodel files and returns one if it exists.
ngSpice_Command m_ngSpice_Command
int(* ngSpice_LockRealloc)(void)
void(* ngSpice_Init)(SendChar *, SendStat *, ControlledExit *, SendData *, SendInitData *, BGThreadRunning *, void *)
bool setCodemodelsInputPath(const std::string &aPath)
Load codemodel files from a directory.
wxString GetXAxis(SIM_TYPE aType) const override final
wxString CurrentPlotName() const override final
ngGet_Vec_Info m_ngGet_Vec_Info
bool m_error
Error flag indicating that ngspice needs to be reloaded.
ngCM_Input_Path m_ngCM_Input_Path
std::vector< double > GetPhaseVector(const std::string &aName, int aMaxLen=-1) override final
Return a requested vector with phase values.
ngSpice_LockRealloc m_ngSpice_LockRealloc
ngSpice_CurPlot m_ngSpice_CurPlot
bool loadSpinit(const std::string &aFileName)
bool Run() override final
Halt the simulation.
bool LoadNetlist(const std::string &aNetlist) override final
Execute the simulation with currently loaded netlist.
static int cbBGThreadRunning(NG_BOOL aFinished, int aId, void *aUser)
std::vector< double > GetGainVector(const std::string &aName, int aMaxLen=-1) override final
Return a requested vector with phase values.
bool Stop() override final
Check if simulation is running at the moment.
int(* ngSpice_Command)(char *command)
static bool m_initialized
Ngspice should be initialized only once.
static int cbSendStat(char *what, int aId, void *aUser)
static int cbSendChar(char *what, int aId, void *aUser)
std::vector< double > GetRealVector(const std::string &aName, int aMaxLen=-1) override final
Return a requested vector with imaginary values.
char *(* ngCM_Input_Path)(const char *path)
std::vector< std::string > GetSettingCommands() const override final
Return current SPICE netlist used by the simulator.
std::string m_netlist
Current netlist.
static void signalHandler(int aSignal)
ngSpice_AllVecs m_ngSpice_AllVecs
int(* ngSpice_UnlockRealloc)(void)
Handle to DLL functions.
pvector_info(* ngGet_Vec_Info)(char *vecname)
static std::atomic< int > s_crashSignal
Signal that caused the crash.
ngSpice_Running m_ngSpice_Running
void Clean() override final
Cleans simulation data (i.e.
bool(* ngSpice_Running)(void)
static NGSPICE * s_currentInstance
Instance that is currently running ngspice.
void Init(const SPICE_SETTINGS *aSettings=nullptr) override final
Point out the model that will be used in future simulations.
bool Attach(const std::shared_ptr< SIMULATION_MODEL > &aModel, const wxString &aSimCommand, unsigned aSimOptions, const wxString &aInputPath, REPORTER &aReporter) override final
Load a netlist for the simulation.
std::string findCmPath() const
Send additional search path for codemodels to ngspice.
void installSignalHandlers()
bool loadCodemodels(const std::string &aPath)
std::vector< COMPLEX > GetComplexVector(const std::string &aName, int aMaxLen=-1) override final
Return a requested vector with real values.
A pure virtual class used to derive REPORTER objects from.
virtual bool Attach(const std::shared_ptr< SIMULATION_MODEL > &aModel, const wxString &aSimCommand, unsigned aSimOptions, const wxString &aInputPath, REPORTER &aReporter)
Point out the model that will be used in future simulations.
Interface to receive simulation state transitions from SPICE_SIMULATOR.
virtual void OnSimStateChange(SIMULATOR *aObject, SIM_STATE aNewState)=0
Special netlist exporter flavor that allows one to override simulation commands.
Storage for simulator specific settings.
std::shared_ptr< SPICE_SETTINGS > & Settings()
Return the simulator configuration settings.
std::atomic< REPORTER * > m_reporter
< Reporter object to receive simulation log (not owned, accessed from BG threads).
std::mutex m_reporterMutex
We don't own this. We are just borrowing it from the SCHEMATIC_SETTINGS.
static std::string ToStdString(const wxString &aStr)
static const wxChar *const traceNgspice
Flag to enable debug output of Ngspice simulator.
static struct sigaction s_oldSigSegv
static bool s_signalHandlersInstalled
static struct sigaction s_oldSigFpe
static pthread_t s_mainThread
static struct sigaction s_oldSigAbrt
SIM_TYPE
< Possible simulation types
IbisParser parser & reporter
wxString result
Test unit parsing edge cases and error handling.