2016-08-11 12:41:07 +00:00
|
|
|
/*
|
|
|
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
|
|
*
|
|
|
|
* Copyright (C) 2016 CERN
|
|
|
|
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
|
|
|
|
* @author Maciej Suminski <maciej.suminski@cern.ch>
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
2016-08-11 12:41:43 +00:00
|
|
|
* as published by the Free Software Foundation; either version 3
|
2016-08-11 12:41:07 +00:00
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, you may find one here:
|
2016-08-11 12:41:43 +00:00
|
|
|
* https://www.gnu.org/licenses/gpl-3.0.html
|
|
|
|
* or you may search the http://www.gnu.org website for the version 3 license,
|
2016-08-11 12:41:07 +00:00
|
|
|
* or you may write to the Free Software Foundation, Inc.,
|
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "ngspice.h"
|
2016-08-11 12:41:19 +00:00
|
|
|
#include "spice_reporter.h"
|
2016-08-11 12:41:01 +00:00
|
|
|
|
2016-08-15 13:52:07 +00:00
|
|
|
#include <common.h>
|
|
|
|
|
2016-08-11 12:41:07 +00:00
|
|
|
#include <sstream>
|
2016-08-11 12:41:01 +00:00
|
|
|
|
2016-08-11 12:41:07 +00:00
|
|
|
using namespace std;
|
2016-08-11 12:41:01 +00:00
|
|
|
|
|
|
|
NGSPICE::NGSPICE()
|
|
|
|
{
|
2016-08-15 11:52:13 +00:00
|
|
|
init();
|
2016-08-11 12:41:07 +00:00
|
|
|
}
|
2016-08-11 12:41:01 +00:00
|
|
|
|
|
|
|
|
2016-08-11 12:41:07 +00:00
|
|
|
NGSPICE::~NGSPICE()
|
|
|
|
{
|
2016-08-11 12:41:01 +00:00
|
|
|
}
|
|
|
|
|
2016-08-11 12:41:07 +00:00
|
|
|
|
2016-08-11 12:41:01 +00:00
|
|
|
void NGSPICE::Init()
|
|
|
|
{
|
2016-08-11 12:42:18 +00:00
|
|
|
if( m_error )
|
2016-08-15 11:52:13 +00:00
|
|
|
init();
|
2016-08-11 12:42:18 +00:00
|
|
|
|
|
|
|
Command( "reset" );
|
2016-08-11 12:41:01 +00:00
|
|
|
}
|
|
|
|
|
2016-08-11 12:41:07 +00:00
|
|
|
|
2016-08-11 12:41:31 +00:00
|
|
|
vector<COMPLEX> NGSPICE::GetPlot( const string& aName, int aMaxLen )
|
|
|
|
{
|
2016-08-15 13:52:07 +00:00
|
|
|
LOCALE_IO c_locale; // ngspice works correctly only with C locale
|
2016-08-11 12:41:31 +00:00
|
|
|
vector<COMPLEX> data;
|
2016-08-15 11:52:13 +00:00
|
|
|
vector_info* vi = ngGet_Vec_Info( (char*) aName.c_str() );
|
2016-08-11 12:41:31 +00:00
|
|
|
|
|
|
|
if( vi )
|
|
|
|
{
|
|
|
|
int length = aMaxLen < 0 ? vi->v_length : std::min( aMaxLen, vi->v_length );
|
|
|
|
data.reserve( length );
|
|
|
|
|
|
|
|
if( vi->v_realdata )
|
|
|
|
{
|
|
|
|
for( int i = 0; i < length; i++ )
|
|
|
|
data.push_back( COMPLEX( vi->v_realdata[i], 0.0 ) );
|
|
|
|
}
|
|
|
|
else if( vi->v_compdata )
|
|
|
|
{
|
|
|
|
for( int i = 0; i < length; i++ )
|
|
|
|
data.push_back( COMPLEX( vi->v_compdata[i].cx_real, vi->v_compdata[i].cx_imag ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
vector<double> NGSPICE::GetRealPlot( const string& aName, int aMaxLen )
|
2016-08-11 12:41:01 +00:00
|
|
|
{
|
2016-08-15 13:52:07 +00:00
|
|
|
LOCALE_IO c_locale; // ngspice works correctly only with C locale
|
2016-08-11 12:41:01 +00:00
|
|
|
vector<double> data;
|
2016-08-15 11:52:13 +00:00
|
|
|
vector_info* vi = ngGet_Vec_Info( (char*) aName.c_str() );
|
2016-08-11 12:41:01 +00:00
|
|
|
|
2016-08-11 12:41:31 +00:00
|
|
|
if( vi )
|
|
|
|
{
|
|
|
|
int length = aMaxLen < 0 ? vi->v_length : std::min( aMaxLen, vi->v_length );
|
|
|
|
data.reserve( length );
|
|
|
|
|
|
|
|
if( vi->v_realdata )
|
|
|
|
{
|
|
|
|
for( int i = 0; i < length; i++ )
|
|
|
|
{
|
|
|
|
data.push_back( vi->v_realdata[i] );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if( vi->v_compdata )
|
|
|
|
{
|
|
|
|
for( int i = 0; i < length; i++ )
|
|
|
|
{
|
|
|
|
assert( vi->v_compdata[i].cx_imag == 0.0 );
|
|
|
|
data.push_back( vi->v_compdata[i].cx_real );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
vector<double> NGSPICE::GetImagPlot( const string& aName, int aMaxLen )
|
|
|
|
{
|
2016-08-15 13:52:07 +00:00
|
|
|
LOCALE_IO c_locale; // ngspice works correctly only with C locale
|
2016-08-11 12:41:31 +00:00
|
|
|
vector<double> data;
|
2016-08-15 11:52:13 +00:00
|
|
|
vector_info* vi = ngGet_Vec_Info( (char*) aName.c_str() );
|
2016-08-11 12:41:01 +00:00
|
|
|
|
2016-08-11 12:41:31 +00:00
|
|
|
if( vi )
|
2016-08-11 12:41:07 +00:00
|
|
|
{
|
2016-08-11 12:41:31 +00:00
|
|
|
int length = aMaxLen < 0 ? vi->v_length : std::min( aMaxLen, vi->v_length );
|
|
|
|
data.reserve( length );
|
|
|
|
|
|
|
|
if( vi->v_compdata )
|
|
|
|
{
|
|
|
|
for( int i = 0; i < length; i++ )
|
|
|
|
{
|
|
|
|
data.push_back( vi->v_compdata[i].cx_imag );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-08-11 12:41:11 +00:00
|
|
|
|
2016-08-11 12:41:31 +00:00
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
vector<double> NGSPICE::GetMagPlot( const string& aName, int aMaxLen )
|
|
|
|
{
|
2016-08-15 13:52:07 +00:00
|
|
|
LOCALE_IO c_locale; // ngspice works correctly only with C locale
|
2016-08-11 12:41:31 +00:00
|
|
|
vector<double> data;
|
2016-08-15 11:52:13 +00:00
|
|
|
vector_info* vi = ngGet_Vec_Info( (char*) aName.c_str() );
|
2016-08-11 12:41:31 +00:00
|
|
|
|
|
|
|
if( vi )
|
|
|
|
{
|
|
|
|
int length = aMaxLen < 0 ? vi->v_length : std::min( aMaxLen, vi->v_length );
|
|
|
|
data.reserve( length );
|
|
|
|
|
|
|
|
if( vi->v_realdata )
|
|
|
|
{
|
|
|
|
for( int i = 0; i < length; i++ )
|
|
|
|
data.push_back( vi->v_realdata[i] );
|
|
|
|
}
|
|
|
|
else if( vi->v_compdata )
|
|
|
|
{
|
|
|
|
for( int i = 0; i < length; i++ )
|
|
|
|
data.push_back( hypot( vi->v_compdata[i].cx_real, vi->v_compdata[i].cx_imag ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
vector<double> NGSPICE::GetPhasePlot( const string& aName, int aMaxLen )
|
|
|
|
{
|
2016-08-15 13:52:07 +00:00
|
|
|
LOCALE_IO c_locale; // ngspice works correctly only with C locale
|
2016-08-11 12:41:31 +00:00
|
|
|
vector<double> data;
|
2016-08-15 11:52:13 +00:00
|
|
|
vector_info* vi = ngGet_Vec_Info( (char*) aName.c_str() );
|
2016-08-11 12:41:31 +00:00
|
|
|
|
|
|
|
if( vi )
|
|
|
|
{
|
|
|
|
int length = aMaxLen < 0 ? vi->v_length : std::min( aMaxLen, vi->v_length );
|
|
|
|
data.reserve( length );
|
|
|
|
|
|
|
|
if( vi->v_realdata )
|
|
|
|
{
|
|
|
|
for( int i = 0; i < length; i++ )
|
|
|
|
data.push_back( 0.0 ); // well, that's life
|
|
|
|
}
|
|
|
|
else if( vi->v_compdata )
|
|
|
|
{
|
|
|
|
for( int i = 0; i < length; i++ )
|
|
|
|
data.push_back( atan2( vi->v_compdata[i].cx_imag, vi->v_compdata[i].cx_real ) );
|
|
|
|
}
|
2016-08-11 12:41:07 +00:00
|
|
|
}
|
2016-08-11 12:41:01 +00:00
|
|
|
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-08-11 12:41:07 +00:00
|
|
|
bool NGSPICE::LoadNetlist( const string& aNetlist )
|
2016-08-11 12:41:01 +00:00
|
|
|
{
|
2016-08-15 13:52:07 +00:00
|
|
|
LOCALE_IO c_locale; // ngspice works correctly only with C locale
|
2016-08-11 12:42:17 +00:00
|
|
|
vector<char*> lines;
|
2016-08-11 12:41:07 +00:00
|
|
|
stringstream ss( aNetlist );
|
2016-08-11 12:41:01 +00:00
|
|
|
|
2016-08-11 12:42:17 +00:00
|
|
|
while( !ss.eof() )
|
2016-08-11 12:41:01 +00:00
|
|
|
{
|
|
|
|
char line[1024];
|
2016-08-11 12:42:17 +00:00
|
|
|
ss.getline( line, sizeof( line ) );
|
|
|
|
lines.push_back( strdup( line ) );
|
2016-08-11 12:41:01 +00:00
|
|
|
}
|
2016-08-11 12:42:17 +00:00
|
|
|
|
|
|
|
lines.push_back( nullptr );
|
2016-08-11 12:42:01 +00:00
|
|
|
|
2016-08-15 11:52:13 +00:00
|
|
|
ngSpice_Circ( lines.data() );
|
2016-08-11 12:41:01 +00:00
|
|
|
|
2016-08-11 12:42:17 +00:00
|
|
|
for( auto line : lines )
|
|
|
|
delete line;
|
2016-08-11 12:41:01 +00:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-08-11 12:41:07 +00:00
|
|
|
bool NGSPICE::Run()
|
|
|
|
{
|
2016-08-15 13:52:07 +00:00
|
|
|
LOCALE_IO c_locale; // ngspice works correctly only with C locale
|
|
|
|
return Command( "bg_run" ); // bg_* commands execute in a separate thread
|
2016-08-11 12:41:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool NGSPICE::Stop()
|
|
|
|
{
|
2016-08-15 13:52:07 +00:00
|
|
|
LOCALE_IO c_locale; // ngspice works correctly only with C locale
|
|
|
|
return Command( "bg_halt" ); // bg_* commands execute in a separate thread
|
2016-08-11 12:41:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool NGSPICE::IsRunning()
|
|
|
|
{
|
2016-08-15 13:52:07 +00:00
|
|
|
LOCALE_IO c_locale; // ngspice works correctly only with C locale
|
|
|
|
return ngSpice_running();
|
2016-08-11 12:41:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-08-11 12:41:07 +00:00
|
|
|
bool NGSPICE::Command( const string& aCmd )
|
2016-08-11 12:41:01 +00:00
|
|
|
{
|
2016-08-15 13:52:07 +00:00
|
|
|
LOCALE_IO c_locale; // ngspice works correctly only with C locale
|
2016-08-15 11:52:13 +00:00
|
|
|
ngSpice_Command( (char*) aCmd.c_str() );
|
2016-08-11 12:41:07 +00:00
|
|
|
|
2016-08-11 12:41:01 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-08-11 12:41:51 +00:00
|
|
|
string NGSPICE::GetXAxis( SIM_TYPE aType ) const
|
|
|
|
{
|
|
|
|
switch( aType )
|
|
|
|
{
|
|
|
|
case ST_AC:
|
|
|
|
case ST_NOISE:
|
|
|
|
return string( "frequency" );
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ST_DC:
|
|
|
|
return string( "v-sweep" );
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ST_TRANSIENT:
|
|
|
|
return string( "time" );
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return string( "" );
|
|
|
|
}
|
|
|
|
|
2016-08-11 12:42:17 +00:00
|
|
|
|
2016-08-15 11:52:13 +00:00
|
|
|
void NGSPICE::init()
|
2016-08-11 12:41:01 +00:00
|
|
|
{
|
2016-08-11 12:42:18 +00:00
|
|
|
m_error = false;
|
|
|
|
|
2016-08-15 13:52:07 +00:00
|
|
|
LOCALE_IO c_locale; // ngspice works correctly only with C locale
|
2016-08-15 11:52:13 +00:00
|
|
|
ngSpice_Init( &cbSendChar, &cbSendStat, &cbControlledExit, NULL, NULL, &cbBGThreadRunning, this );
|
|
|
|
|
2016-08-11 12:42:18 +00:00
|
|
|
// Workaround to avoid hang ups on certain errors
|
|
|
|
Command( "unset interactive" );
|
2016-08-11 12:41:01 +00:00
|
|
|
}
|
|
|
|
|
2016-08-11 12:41:01 +00:00
|
|
|
|
2016-08-11 12:41:07 +00:00
|
|
|
int NGSPICE::cbSendChar( char* what, int id, void* user )
|
2016-08-11 12:41:01 +00:00
|
|
|
{
|
2016-08-11 12:41:07 +00:00
|
|
|
NGSPICE* sim = reinterpret_cast<NGSPICE*>( user );
|
|
|
|
|
2016-08-11 12:41:19 +00:00
|
|
|
if( sim->m_reporter )
|
2016-08-11 12:41:35 +00:00
|
|
|
{
|
|
|
|
// strip stdout/stderr from the line
|
|
|
|
if( ( strncasecmp( what, "stdout ", 7 ) == 0 )
|
|
|
|
|| ( strncasecmp( what, "stderr ", 7 ) == 0 ) )
|
|
|
|
what += 7;
|
|
|
|
|
2016-08-11 12:41:19 +00:00
|
|
|
sim->m_reporter->Report( what );
|
2016-08-11 12:41:35 +00:00
|
|
|
}
|
2016-08-11 12:41:07 +00:00
|
|
|
|
|
|
|
return 0;
|
2016-08-11 12:41:01 +00:00
|
|
|
}
|
|
|
|
|
2016-08-11 12:41:07 +00:00
|
|
|
|
2016-08-11 12:41:07 +00:00
|
|
|
int NGSPICE::cbSendStat( char* what, int id, void* user )
|
2016-08-11 12:41:01 +00:00
|
|
|
{
|
2016-08-11 12:41:07 +00:00
|
|
|
/* NGSPICE* sim = reinterpret_cast<NGSPICE*>( user );
|
|
|
|
if( sim->m_consoleReporter )
|
|
|
|
sim->m_consoleReporter->Report( what );*/
|
2016-08-11 12:41:19 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int NGSPICE::cbBGThreadRunning( bool is_running, int id, void* user )
|
|
|
|
{
|
|
|
|
NGSPICE* sim = reinterpret_cast<NGSPICE*>( user );
|
|
|
|
|
|
|
|
if( sim->m_reporter )
|
|
|
|
// I know the test below seems like an error, but well, it works somehow..
|
|
|
|
sim->m_reporter->OnSimStateChange( sim, is_running ? SIM_IDLE : SIM_RUNNING );
|
|
|
|
|
2016-08-11 12:41:07 +00:00
|
|
|
return 0;
|
2016-08-11 12:41:01 +00:00
|
|
|
}
|
2016-08-11 12:42:18 +00:00
|
|
|
|
|
|
|
|
|
|
|
int NGSPICE::cbControlledExit( int status, bool immediate, bool exit_upon_quit, int id, void* user )
|
|
|
|
{
|
|
|
|
// Something went wrong, reload the dll
|
|
|
|
NGSPICE* sim = reinterpret_cast<NGSPICE*>( user );
|
|
|
|
sim->m_error = true;
|
|
|
|
//printf("stat %d immed %d quit %d\n", status, !!immediate, !!exit_upon_quit);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|