40#include <wx/stdpaths.h>
93 wxLogTrace(
traceNgspice,
"Sending Ngspice configuration command '%s'.", command );
119 std::vector<std::string> retVal;
121 if( allVectors !=
nullptr )
123 for(
char**
plot = allVectors; *
plot !=
nullptr;
plot++ )
126 retVal.reserve( noOfVectors );
128 for(
int i = 0; i < noOfVectors; i++, allVectors++ )
130 std::string vec = *allVectors;
131 retVal.push_back( std::move( vec ) );
143 std::vector<COMPLEX> data;
151 int length = aMaxLen < 0 ? vi->v_length : std::min( aMaxLen, vi->v_length );
152 data.reserve( length );
156 for(
int i = 0; i < length; i++ )
157 data.emplace_back( vi->v_realdata[i], 0.0 );
159 else if( vi->v_compdata )
161 for(
int i = 0; i < length; i++ )
162 data.emplace_back( vi->v_compdata[i].cx_real, vi->v_compdata[i].cx_imag );
173 std::vector<double> data;
181 int length = aMaxLen < 0 ? vi->v_length : std::min( aMaxLen, vi->v_length );
182 data.reserve( length );
186 for(
int i = 0; i < length; i++ )
187 data.push_back( vi->v_realdata[i] );
189 else if( vi->v_compdata )
191 for(
int i = 0; i < length; i++ )
192 data.push_back( vi->v_compdata[i].cx_real );
203 std::vector<double> data;
211 int length = aMaxLen < 0 ? vi->v_length : std::min( aMaxLen, vi->v_length );
212 data.reserve( length );
216 for(
int i = 0; i < length; i++ )
217 data.push_back( vi->v_compdata[i].cx_imag );
228 std::vector<double> data;
236 int length = aMaxLen < 0 ? vi->v_length : std::min( aMaxLen, vi->v_length );
237 data.reserve( length );
241 for(
int i = 0; i < length; i++ )
242 data.push_back( vi->v_realdata[i] );
244 else if( vi->v_compdata )
246 for(
int i = 0; i < length; i++ )
247 data.push_back( hypot( vi->v_compdata[i].cx_real, vi->v_compdata[i].cx_imag ) );
258 std::vector<double> data;
266 int length = aMaxLen < 0 ? vi->v_length : std::min( aMaxLen, vi->v_length );
267 data.reserve( length );
271 for(
int i = 0; i < length; i++ )
272 data.push_back( 0.0 );
274 else if( vi->v_compdata )
276 for(
int i = 0; i < length; i++ )
277 data.push_back( atan2( vi->v_compdata[i].cx_imag, vi->v_compdata[i].cx_real ) );
285bool NGSPICE::Attach(
const std::shared_ptr<SIMULATION_MODEL>& aModel,
const wxString& aSimCommand,
286 unsigned aSimOptions,
const wxString& aInputPath,
REPORTER& aReporter )
293 if(
model &&
model->GetNetlist( aSimCommand, aSimOptions, &formatter, aReporter ) )
301 Command(
"echo Command: esave none" );
318 std::vector<char*> lines;
319 std::stringstream ss( aNetlist );
323 for( std::string line; std::getline( ss, line ); )
325 lines.push_back( strdup( line.data() ) );
330 lines.push_back(
nullptr );
335 for(
char* line : lines )
385 case SIGSEGV: signalName = wxT(
"SIGSEGV (segmentation fault)" );
break;
386 case SIGABRT: signalName = wxT(
"SIGABRT (abort)" );
break;
387 case SIGFPE: signalName = wxT(
"SIGFPE (floating point exception)" );
break;
388 case SIGILL: signalName = wxT(
"SIGILL (illegal instruction)" );
break;
389 default: signalName = wxString::Format( wxT(
"signal %d" ), signal );
break;
393 _(
"Simulation crashed (%s). This is usually caused by a bug in ngspice "
394 "or an invalid netlist. The simulator will be reset." ),
422 return wxS(
"frequency" );
428 if( vector.Lower().EndsWith( wxS(
"-sweep" ) ) )
432 return wxS(
"sweep" );
435 return wxS(
"time" );
438 return wxEmptyString;
447 std::vector<std::string> commands;
449 wxCHECK( settings, commands );
459 default: wxFAIL_MSG( wxString::Format(
"Undefined NGSPICE_COMPATIBILITY_MODE %d.",
479 const wxStandardPaths& stdPaths = wxStandardPaths::Get();
481 if(
m_dll.IsLoaded() )
486 wxFileName dllFile(
"", NGSPICE_DLL_FILE );
487#if defined(__WINDOWS__)
488 #if defined( _MSC_VER )
489 std::vector<std::string> dllPaths = {
"" };
491 std::vector<std::string> dllPaths = {
"",
"/mingw64/bin",
"/mingw32/bin" };
493#elif defined(__WXMAC__)
494 std::vector<std::string> dllPaths = {
495 PATHS::GetOSXKicadUserDataDir().ToStdString() +
"/PlugIns/ngspice",
496 PATHS::GetOSXKicadMachineDataDir().ToStdString() +
"/PlugIns/ngspice",
499 stdPaths.GetPluginsDir().ToStdString() +
"/sim",
502 wxFileName( stdPaths.GetExecutablePath() ).GetPath().ToStdString() +
503 "/../../../../../Contents/PlugIns/sim"
506 std::vector<std::string> dllPaths = {
"/usr/local/lib" };
509 if( wxGetEnv( wxT(
"KICAD_RUN_FROM_BUILD_DIR" ),
nullptr ) )
510 dllPaths.emplace_back( NGSPICE_DLL_DIR );
512#if defined(__WINDOWS__) || (__WXMAC__)
513 for(
const auto&
path : dllPaths )
515 dllFile.SetPath(
path );
516 wxLogTrace(
traceNgspice,
"libngspice search path: %s", dllFile.GetFullPath() );
517 m_dll.Load( dllFile.GetFullPath(), wxDL_VERBATIM | wxDL_QUIET | wxDL_NOW );
519 if(
m_dll.IsLoaded() )
521 wxLogTrace(
traceNgspice,
"libngspice path found in: %s", dllFile.GetFullPath() );
526 if( !
m_dll.IsLoaded() )
527 m_dll.Load( wxDynamicLibrary::CanonicalizeName(
"ngspice" ) );
530 m_dll.Load( NGSPICE_DLL_FILE, wxDL_VERBATIM | wxDL_QUIET | wxDL_NOW );
533 if( !
m_dll.IsLoaded() )
535 for(
const auto&
path : dllPaths )
537 dllFile.SetPath(
path );
538 wxLogTrace(
traceNgspice,
"libngspice search path: %s", dllFile.GetFullPath() );
539 m_dll.Load( dllFile.GetFullPath(), wxDL_VERBATIM | wxDL_QUIET | wxDL_NOW );
541 if(
m_dll.IsLoaded() )
543 wxLogTrace(
traceNgspice,
"libngspice path found in: %s", dllFile.GetFullPath() );
550 if( !
m_dll.IsLoaded() )
551 throw std::runtime_error(
_(
"Unable to load ngspice shared library. Please check your install." ).ToStdString() );
566 if(
m_dll.HasSymbol(
"ngSpice_LockRealloc" ) )
577 wxString cwd( wxGetCwd() );
578 wxFileName exeDir( stdPaths.GetExecutablePath() );
579 wxSetWorkingDirectory( exeDir.GetPath() );
585 if( !cmPath.empty() )
586 Command(
"set __CMPATH=\"" + cmPath +
"\"" );
589 const std::vector<std::string> spiceinitPaths =
593 stdPaths.GetPluginsDir().ToStdString() +
"/sim/ngspice/scripts",
594 wxFileName( stdPaths.GetExecutablePath() ).GetPath().ToStdString() +
595 "/../../../../../Contents/PlugIns/sim/ngspice/scripts"
603 bool foundSpiceinit =
false;
605 for(
const auto&
path : spiceinitPaths )
612 foundSpiceinit =
true;
619 if( !foundSpiceinit && !cmPath.empty() )
623 wxSetWorkingDirectory( cwd );
636 std::vector<char*> lines;
637 lines.push_back( strdup(
"*" ) );
638 lines.push_back( strdup(
".end" ) );
639 lines.push_back(
nullptr );
643 for(
auto line : lines )
652 if( !wxFileName::FileExists( aFileName ) )
657 if( !file.Open( aFileName ) )
660 for( wxString& cmd = file.GetFirstLine(); !file.Eof(); cmd = file.GetNextLine() )
669 const std::vector<std::string> cmPaths =
672 "/Applications/ngspice/lib/ngspice",
673 "Contents/Frameworks",
674 wxStandardPaths::Get().GetPluginsDir().ToStdString() +
"/sim/ngspice",
675 wxFileName( wxStandardPaths::Get().GetExecutablePath() ).GetPath().ToStdString() +
676 "/../../../../../Contents/PlugIns/sim/ngspice",
677 "../Plugins/sim/ngspice",
679 "../eeschema/ngspice",
686 for(
const auto&
path : cmPaths )
690 if( wxFileName::FileExists(
path +
"/spice2poly.cm" ) )
697 return std::string();
716 wxArrayString cmFiles;
717 size_t count = wxDir::GetAllFiles( aPath, &cmFiles );
719 for(
const auto& cm : cmFiles )
720 Command( fmt::format(
"codemodel '{}'", cm.ToStdString() ) );
733 if( ( strncasecmp( aWhat,
"stdout ", 7 ) == 0 )
734 || ( strncasecmp( aWhat,
"stderr ", 7 ) == 0 ) )
815 struct sigaction* oldAction =
nullptr;
825 if( oldAction && oldAction->sa_handler != SIG_DFL && oldAction->sa_handler != SIG_IGN )
827 oldAction->sa_handler( aSignal );
832 signal( aSignal, SIG_DFL );
851 pthread_exit(
nullptr );
865 struct sigaction newAction;
867 sigemptyset( &newAction.sa_mask );
868 newAction.sa_flags = 0;
891static bool s_exceptionHandlersInstalled =
false;
892static PVOID s_vectoredHandler =
nullptr;
893static DWORD s_mainThreadId = 0;
895long __stdcall NGSPICE::sehHandler( _EXCEPTION_POINTERS* aException )
897 if( !aException || !aException->ExceptionRecord )
898 return EXCEPTION_CONTINUE_SEARCH;
900 if( GetCurrentThreadId() == s_mainThreadId )
901 return EXCEPTION_CONTINUE_SEARCH;
905 switch( aException->ExceptionRecord->ExceptionCode )
907 case EXCEPTION_ACCESS_VIOLATION:
908 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
909 case EXCEPTION_DATATYPE_MISALIGNMENT:
910 case EXCEPTION_STACK_OVERFLOW:
913 case EXCEPTION_ILLEGAL_INSTRUCTION:
914 case EXCEPTION_PRIV_INSTRUCTION:
917 case EXCEPTION_INT_DIVIDE_BY_ZERO:
918 case EXCEPTION_INT_OVERFLOW:
919 case EXCEPTION_FLT_DIVIDE_BY_ZERO:
920 case EXCEPTION_FLT_INVALID_OPERATION:
921 case EXCEPTION_FLT_OVERFLOW:
922 case EXCEPTION_FLT_UNDERFLOW:
923 case EXCEPTION_FLT_INEXACT_RESULT:
924 case EXCEPTION_FLT_STACK_CHECK:
928 return EXCEPTION_CONTINUE_SEARCH;
938 if( aException->ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW )
939 TerminateThread( GetCurrentThread(), 1 );
943 return EXCEPTION_CONTINUE_EXECUTION;
949 wxUnusedVar( aSignal );
955 if( s_exceptionHandlersInstalled )
958 s_mainThreadId = GetCurrentThreadId();
963 s_vectoredHandler = AddVectoredExceptionHandler( 1, &NGSPICE::sehHandler );
964 s_exceptionHandlersInstalled = ( s_vectoredHandler != nullptr );
970 if( s_exceptionHandlersInstalled )
972 RemoveVectoredExceptionHandler( s_vectoredHandler );
973 s_vectoredHandler =
nullptr;
974 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
Set a SIMULATOR_REPORTER object to receive the simulation log.
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 REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)
Report a string with a given severity.
virtual void OnSimStateChange(SIMULATOR *aObject, SIM_STATE aNewState)=0
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.
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.
SIMULATOR_REPORTER * m_reporter
< Reporter object to receive simulation log.
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
wxString result
Test unit parsing edge cases and error handling.