Fix more SPICE case-insensitivity bugs.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/14793
This commit is contained in:
Jeff Young 2023-05-22 11:45:59 +01:00
parent 0d235ac64b
commit 03486443c7
5 changed files with 57 additions and 52 deletions

View File

@ -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;
} }

View File

@ -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;
}; };

View File

@ -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;
} }

View File

@ -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 );

View File

@ -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;
} }