Fix more SPICE case-insensitivity bugs.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/14793
This commit is contained in:
parent
0d235ac64b
commit
03486443c7
|
@ -24,7 +24,6 @@
|
||||||
*/
|
*/
|
||||||
#include <lib_symbol.h>
|
#include <lib_symbol.h>
|
||||||
#include <sch_symbol.h>
|
#include <sch_symbol.h>
|
||||||
#include <confirm.h>
|
|
||||||
#include <string_utils.h>
|
#include <string_utils.h>
|
||||||
#include <wx/regex.h>
|
#include <wx/regex.h>
|
||||||
|
|
||||||
|
@ -800,13 +799,19 @@ const SIM_MODEL::PARAM& SIM_MODEL::GetParam( unsigned aParamIndex ) const
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool SIM_MODEL::PARAM::INFO::Matches( const std::string& aParamName ) const
|
||||||
|
{
|
||||||
|
return boost::iequals( name, aParamName );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int SIM_MODEL::doFindParam( const std::string& aParamName ) const
|
int SIM_MODEL::doFindParam( const std::string& aParamName ) const
|
||||||
{
|
{
|
||||||
std::vector<std::reference_wrapper<const PARAM>> params = GetParams();
|
std::vector<std::reference_wrapper<const PARAM>> params = GetParams();
|
||||||
|
|
||||||
for( int ii = 0; ii < (int) params.size(); ++ii )
|
for( int ii = 0; ii < (int) params.size(); ++ii )
|
||||||
{
|
{
|
||||||
if( boost::iequals( params[ii].get().info.name, aParamName ) )
|
if( params[ii].get().Matches( aParamName ) )
|
||||||
return ii;
|
return ii;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -362,6 +362,8 @@ public:
|
||||||
enumValues( std::move( aEnumValues ) )
|
enumValues( std::move( aEnumValues ) )
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
bool Matches( const std::string& aName ) const;
|
||||||
|
|
||||||
std::string name;
|
std::string name;
|
||||||
unsigned id;
|
unsigned id;
|
||||||
DIR dir;
|
DIR dir;
|
||||||
|
@ -377,12 +379,17 @@ public:
|
||||||
std::vector<std::string> enumValues;
|
std::vector<std::string> enumValues;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::string value;
|
|
||||||
const INFO& info;
|
|
||||||
|
|
||||||
PARAM( const INFO& aInfo ) :
|
PARAM( const INFO& aInfo ) :
|
||||||
info( aInfo )
|
info( aInfo )
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
bool Matches( const std::string& aName ) const
|
||||||
|
{
|
||||||
|
return info.Matches( aName );
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string value;
|
||||||
|
const INFO& info;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
|
|
||||||
#include <sim/sim_model_ngspice.h>
|
#include <sim/sim_model_ngspice.h>
|
||||||
|
|
||||||
#include <boost/algorithm/string/case_conv.hpp>
|
#include <boost/algorithm/string.hpp>
|
||||||
#include <fmt/core.h>
|
#include <fmt/core.h>
|
||||||
|
|
||||||
|
|
||||||
|
@ -85,15 +85,13 @@ int SIM_MODEL_NGSPICE::doFindParam( const std::string& aParamName ) const
|
||||||
{
|
{
|
||||||
// Special case to allow escaped model parameters (suffixed with "_")
|
// Special case to allow escaped model parameters (suffixed with "_")
|
||||||
|
|
||||||
std::string lowerParamName = boost::to_lower_copy( aParamName );
|
|
||||||
|
|
||||||
std::vector<std::reference_wrapper<const PARAM>> params = GetParams();
|
std::vector<std::reference_wrapper<const PARAM>> params = GetParams();
|
||||||
|
|
||||||
for( int ii = 0; ii < (int) params.size(); ++ii )
|
for( int ii = 0; ii < (int) params.size(); ++ii )
|
||||||
{
|
{
|
||||||
const PARAM& param = params[ii];
|
const PARAM& param = params[ii];
|
||||||
|
|
||||||
if( param.info.name == lowerParamName || param.info.name == lowerParamName + "_" )
|
if( param.Matches( aParamName ) || param.Matches( aParamName + "_" ) )
|
||||||
return ii;
|
return ii;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,27 +103,24 @@ void SIM_MODEL_NGSPICE::SetParamFromSpiceCode( const std::string& aParamName,
|
||||||
const std::string& aValue,
|
const std::string& aValue,
|
||||||
SIM_VALUE_GRAMMAR::NOTATION aNotation )
|
SIM_VALUE_GRAMMAR::NOTATION aNotation )
|
||||||
{
|
{
|
||||||
std::string paramName = boost::to_lower_copy( aParamName );
|
|
||||||
|
|
||||||
// "level" and "version" are not really parameters - they're part of the type - so silently
|
// "level" and "version" are not really parameters - they're part of the type - so silently
|
||||||
// ignore them.
|
// ignore them.
|
||||||
if( paramName == "level" || paramName == "version" )
|
if( boost::iequals( aParamName, "level" ) || boost::iequals( aParamName, "version" ) )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// First we try to use the name as is. Note that you can't set instance parameters from this
|
// First we try to use the name as is. Note that you can't set instance parameters from this
|
||||||
// function, it's for ".model" cards, not for instantiations.
|
// function, it's for ".model" cards, not for instantiations.
|
||||||
|
|
||||||
std::string lowerParamName = boost::to_lower_copy( paramName );
|
|
||||||
|
|
||||||
std::vector<std::reference_wrapper<const PARAM>> params = GetParams();
|
std::vector<std::reference_wrapper<const PARAM>> params = GetParams();
|
||||||
|
|
||||||
for( int ii = 0; ii < (int) params.size(); ++ii )
|
for( int ii = 0; ii < (int) params.size(); ++ii )
|
||||||
{
|
{
|
||||||
const PARAM& param = params[ii];
|
const PARAM& param = params[ii];
|
||||||
|
|
||||||
if( !param.info.isSpiceInstanceParam
|
if( param.info.isSpiceInstanceParam || param.info.category == PARAM::CATEGORY::SUPERFLUOUS )
|
||||||
&& param.info.category != PARAM::CATEGORY::SUPERFLUOUS
|
continue;
|
||||||
&& ( param.info.name == lowerParamName || param.info.name == lowerParamName + "_" ) )
|
|
||||||
|
if( param.Matches( aParamName ) || param.Matches( aParamName + "_" ) )
|
||||||
{
|
{
|
||||||
SetParamValue( ii, aValue, aNotation );
|
SetParamValue( ii, aValue, aNotation );
|
||||||
return;
|
return;
|
||||||
|
@ -139,16 +134,18 @@ void SIM_MODEL_NGSPICE::SetParamFromSpiceCode( const std::string& aParamName,
|
||||||
|
|
||||||
for( const PARAM::INFO& ngspiceParamInfo : ModelInfo( getModelType() ).modelParams )
|
for( const PARAM::INFO& ngspiceParamInfo : ModelInfo( getModelType() ).modelParams )
|
||||||
{
|
{
|
||||||
if( ngspiceParamInfo.name == lowerParamName )
|
if( ngspiceParamInfo.Matches( aParamName ) )
|
||||||
{
|
{
|
||||||
// Find an actual parameter with the same id. Even if the ngspiceParam was
|
// Find an actual parameter with the same id. Even if the ngspiceParam was
|
||||||
// superfluous, its alias target might not be.
|
// superfluous, its alias target might not be.
|
||||||
for( int ii = 0; ii < (int) params.size(); ++ii )
|
for( int ii = 0; ii < (int) params.size(); ++ii )
|
||||||
{
|
{
|
||||||
const PARAM& param = params[ii];
|
const PARAM::INFO& paramInfo = params[ii].get().info;
|
||||||
|
|
||||||
if( param.info.id == ngspiceParamInfo.id
|
if( paramInfo.category == PARAM::CATEGORY::SUPERFLUOUS )
|
||||||
&& param.info.category != PARAM::CATEGORY::SUPERFLUOUS )
|
continue;
|
||||||
|
|
||||||
|
if( paramInfo.id == ngspiceParamInfo.id )
|
||||||
{
|
{
|
||||||
SetParamValue( ii, aValue, aNotation );
|
SetParamValue( ii, aValue, aNotation );
|
||||||
return;
|
return;
|
||||||
|
@ -159,7 +156,7 @@ void SIM_MODEL_NGSPICE::SetParamFromSpiceCode( const std::string& aParamName,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !canSilentlyIgnoreParam( paramName ) )
|
if( !canSilentlyIgnoreParam( aParamName ) )
|
||||||
THROW_IO_ERROR( wxString::Format( "Unknown simulation model parameter '%s'", aParamName ) );
|
THROW_IO_ERROR( wxString::Format( "Unknown simulation model parameter '%s'", aParamName ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,19 +164,19 @@ void SIM_MODEL_NGSPICE::SetParamFromSpiceCode( const std::string& aParamName,
|
||||||
bool SIM_MODEL_NGSPICE::canSilentlyIgnoreParam( const std::string& aParamName )
|
bool SIM_MODEL_NGSPICE::canSilentlyIgnoreParam( const std::string& aParamName )
|
||||||
{
|
{
|
||||||
// Ignore the purely informative LTspice-specific parameters "mfg" and "type".
|
// Ignore the purely informative LTspice-specific parameters "mfg" and "type".
|
||||||
if( aParamName == "mfg" || aParamName == "type" )
|
if( boost::iequals( aParamName, "mfg" ) || boost::iequals( aParamName, "type" ) )
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if( GetDeviceType() == DEVICE_T::D )
|
if( GetDeviceType() == DEVICE_T::D )
|
||||||
{
|
{
|
||||||
if( aParamName == "perim"
|
if( boost::iequals( aParamName, "perim" )
|
||||||
|| aParamName == "isw"
|
|| boost::iequals( aParamName, "isw" )
|
||||||
|| aParamName == "ns"
|
|| boost::iequals( aParamName, "ns" )
|
||||||
|| aParamName == "rsw"
|
|| boost::iequals( aParamName, "rsw" )
|
||||||
|| aParamName == "cjsw"
|
|| boost::iequals( aParamName, "cjsw" )
|
||||||
|| aParamName == "vjsw"
|
|| boost::iequals( aParamName, "vjsw" )
|
||||||
|| aParamName == "mjsw"
|
|| boost::iequals( aParamName, "mjsw" )
|
||||||
|| aParamName == "fcs" )
|
|| boost::iequals( aParamName, "fcs" ) )
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -188,20 +185,20 @@ bool SIM_MODEL_NGSPICE::canSilentlyIgnoreParam( const std::string& aParamName )
|
||||||
if( GetDeviceType() == DEVICE_T::NPN || GetDeviceType() == DEVICE_T::PNP )
|
if( GetDeviceType() == DEVICE_T::NPN || GetDeviceType() == DEVICE_T::PNP )
|
||||||
{
|
{
|
||||||
// Ignore the purely informative LTspice-specific parameters "icrating" and "vceo".
|
// Ignore the purely informative LTspice-specific parameters "icrating" and "vceo".
|
||||||
if( aParamName == "icrating" || aParamName == "vceo" )
|
if( boost::iequals( aParamName, "icrating" ) || boost::iequals( aParamName, "vceo" ) )
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( GetType() == TYPE::NPN_GUMMELPOON || GetType() == TYPE::PNP_GUMMELPOON )
|
if( GetType() == TYPE::NPN_GUMMELPOON || GetType() == TYPE::PNP_GUMMELPOON )
|
||||||
{
|
{
|
||||||
// Ignore unused parameters.
|
// Ignore unused parameters.
|
||||||
if( aParamName == "bvcbo"
|
if( boost::iequals( aParamName, "bvcbo" )
|
||||||
|| aParamName == "nbvcbo"
|
|| boost::iequals( aParamName, "nbvcbo" )
|
||||||
|| aParamName == "tbvcbo1"
|
|| boost::iequals( aParamName, "tbvcbo1" )
|
||||||
|| aParamName == "tbvcbo2"
|
|| boost::iequals( aParamName, "tbvcbo2" )
|
||||||
|| aParamName == "bvbe"
|
|| boost::iequals( aParamName, "bvbe" )
|
||||||
|| aParamName == "ibvbe"
|
|| boost::iequals( aParamName, "ibvbe" )
|
||||||
|| aParamName == "nbvbe" )
|
|| boost::iequals( aParamName, "nbvbe" ) )
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -210,9 +207,9 @@ bool SIM_MODEL_NGSPICE::canSilentlyIgnoreParam( const std::string& aParamName )
|
||||||
if( GetType() == TYPE::NMOS_VDMOS || GetType() == TYPE::PMOS_VDMOS )
|
if( GetType() == TYPE::NMOS_VDMOS || GetType() == TYPE::PMOS_VDMOS )
|
||||||
{
|
{
|
||||||
// Ignore the purely informative LTspice-specific parameters "Vds", "Ron" and "Qg".
|
// Ignore the purely informative LTspice-specific parameters "Vds", "Ron" and "Qg".
|
||||||
if( aParamName == "vds"
|
if( boost::iequals( aParamName, "vds" )
|
||||||
|| aParamName == "ron"
|
|| boost::iequals( aParamName, "ron" )
|
||||||
|| aParamName == "qg" )
|
|| boost::iequals( aParamName, "qg" ) )
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -211,7 +211,7 @@ bool SIM_MODEL_SERIALIZER::ParseParams( const std::string& aParams )
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string paramName;
|
std::string paramName;
|
||||||
bool isPrimaryValueSet = false;
|
bool isPrimaryValueSet = false;
|
||||||
|
|
||||||
for( const auto& node : root->children )
|
for( const auto& node : root->children )
|
||||||
{
|
{
|
||||||
|
@ -225,11 +225,10 @@ bool SIM_MODEL_SERIALIZER::ParseParams( const std::string& aParams )
|
||||||
|| node->is_type<SIM_MODEL_SERIALIZER_PARSER::unquotedString>() )
|
|| node->is_type<SIM_MODEL_SERIALIZER_PARSER::unquotedString>() )
|
||||||
{
|
{
|
||||||
wxASSERT( paramName != "" );
|
wxASSERT( paramName != "" );
|
||||||
// TODO: Shouldn't be named "...fromSpiceCode" here...
|
|
||||||
|
|
||||||
m_model.SetParamValue( paramName, node->string(), SIM_VALUE_GRAMMAR::NOTATION::SI );
|
m_model.SetParamValue( paramName, node->string(), SIM_VALUE_GRAMMAR::NOTATION::SI );
|
||||||
|
|
||||||
if( paramName == m_model.GetParam( 0 ).info.name )
|
if( m_model.GetParam( 0 ).Matches( paramName ) )
|
||||||
isPrimaryValueSet = true;
|
isPrimaryValueSet = true;
|
||||||
}
|
}
|
||||||
else if( node->is_type<SIM_MODEL_SERIALIZER_PARSER::quotedString>() )
|
else if( node->is_type<SIM_MODEL_SERIALIZER_PARSER::quotedString>() )
|
||||||
|
@ -305,13 +304,13 @@ std::string SIM_MODEL_SERIALIZER::generateParamValuePair( const SIM_MODEL::PARAM
|
||||||
std::string name = aParam.info.name;
|
std::string name = aParam.info.name;
|
||||||
|
|
||||||
// Because of collisions with instance parameters, we append some model parameters with "_".
|
// Because of collisions with instance parameters, we append some model parameters with "_".
|
||||||
if( boost::ends_with( aParam.info.name, "_" ) )
|
if( boost::ends_with( name, "_" ) )
|
||||||
name = aParam.info.name.substr( 0, aParam.info.name.length() - 1 );
|
name = name.substr( 0, aParam.info.name.length() - 1 );
|
||||||
|
|
||||||
std::string value = aParam.value;
|
std::string value = aParam.value;
|
||||||
|
|
||||||
if( aParam.info.category == SIM_MODEL::PARAM::CATEGORY::FLAGS )
|
if( aParam.info.category == SIM_MODEL::PARAM::CATEGORY::FLAGS )
|
||||||
return value == "1" ? aParam.info.name : "";
|
return value == "1" ? name : "";
|
||||||
|
|
||||||
if( value == "" || value.find( ' ' ) != std::string::npos )
|
if( value == "" || value.find( ' ' ) != std::string::npos )
|
||||||
value = fmt::format( "\"{}\"", value );
|
value = fmt::format( "\"{}\"", value );
|
||||||
|
|
|
@ -23,7 +23,6 @@
|
||||||
|
|
||||||
#include <sim/sim_model_spice_fallback.h>
|
#include <sim/sim_model_spice_fallback.h>
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
#include <boost/algorithm/string/case_conv.hpp>
|
|
||||||
|
|
||||||
|
|
||||||
SIM_MODEL_SPICE_FALLBACK::SIM_MODEL_SPICE_FALLBACK( TYPE aType, const std::string& aRawSpiceCode ) :
|
SIM_MODEL_SPICE_FALLBACK::SIM_MODEL_SPICE_FALLBACK( TYPE aType, const std::string& aRawSpiceCode ) :
|
||||||
|
@ -67,15 +66,13 @@ int SIM_MODEL_SPICE_FALLBACK::doFindParam( const std::string& aParamName ) const
|
||||||
{
|
{
|
||||||
// Special case to allow escaped model parameters (suffixed with "_")
|
// Special case to allow escaped model parameters (suffixed with "_")
|
||||||
|
|
||||||
std::string lowerParamName = boost::to_lower_copy( aParamName );
|
|
||||||
|
|
||||||
std::vector<std::reference_wrapper<const PARAM>> params = GetParams();
|
std::vector<std::reference_wrapper<const PARAM>> params = GetParams();
|
||||||
|
|
||||||
for( int ii = 0; ii < (int) params.size(); ++ii )
|
for( int ii = 0; ii < (int) params.size(); ++ii )
|
||||||
{
|
{
|
||||||
const PARAM& param = params[ii];
|
const PARAM& param = params[ii];
|
||||||
|
|
||||||
if( param.info.name == lowerParamName || param.info.name == lowerParamName + "_" )
|
if( param.Matches( aParamName ) || param.Matches( aParamName + "_" ) )
|
||||||
return ii;
|
return ii;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue