From 120b569048c14b946fca468b76f0a3725750e645 Mon Sep 17 00:00:00 2001 From: Mikolaj Wielgus Date: Tue, 4 Oct 2022 17:17:41 +0200 Subject: [PATCH] Sim: Support ako models --- eeschema/sim/sim_model.cpp | 28 +++++++--- eeschema/sim/sim_model.h | 9 ++-- eeschema/sim/sim_model_ngspice.cpp | 6 ++- eeschema/sim/sim_model_source.cpp | 13 +++-- eeschema/sim/sim_model_source.h | 4 +- eeschema/sim/sim_model_spice.cpp | 11 ++-- eeschema/sim/sim_model_spice.h | 9 ++-- eeschema/sim/sim_model_subckt.cpp | 3 +- eeschema/sim/sim_model_subckt.h | 2 +- eeschema/sim/sim_value.cpp | 24 ++++++++- eeschema/sim/sim_value.h | 9 +++- eeschema/sim/spice_grammar.h | 20 +++++++- eeschema/sim/spice_library_parser.cpp | 13 ++--- eeschema/sim/spice_library_parser.h | 2 +- eeschema/sim/spice_model_parser.cpp | 74 +++++++++++++++++++++++++-- eeschema/sim/spice_model_parser.h | 7 ++- 16 files changed, 179 insertions(+), 55 deletions(-) diff --git a/eeschema/sim/sim_model.cpp b/eeschema/sim/sim_model.cpp index e27cee5596..96008712d1 100644 --- a/eeschema/sim/sim_model.cpp +++ b/eeschema/sim/sim_model.cpp @@ -834,15 +834,22 @@ const SIM_MODEL::PARAM& SIM_MODEL::GetBaseParam( unsigned aParamIndex ) const } -bool SIM_MODEL::SetParamValue( unsigned aParamIndex, const std::string& aValue, - SIM_VALUE_GRAMMAR::NOTATION aNotation ) +bool SIM_MODEL::SetParamValue( int aParamIndex, const SIM_VALUE& aValue ) { - return m_params.at( aParamIndex ).value->FromString( aValue, aNotation ); + *m_params.at( aParamIndex ).value = aValue; + return true; } -bool SIM_MODEL::SetParamValue( const std::string& aParamName, const std::string& aValue, - SIM_VALUE_GRAMMAR::NOTATION aNotation ) +bool SIM_MODEL::SetParamValue( int aParamIndex, const std::string& aValue, + SIM_VALUE::NOTATION aNotation ) +{ + const SIM_VALUE& value = *GetParam( aParamIndex ).value; + return SetParamValue( aParamIndex, *SIM_VALUE::Create( value.GetType(), aValue, aNotation ) ); +} + + +bool SIM_MODEL::SetParamValue( const std::string& aParamName, const SIM_VALUE& aValue ) { std::vector> params = GetParams(); @@ -855,7 +862,16 @@ bool SIM_MODEL::SetParamValue( const std::string& aParamName, const std::string& if( it == params.end() ) return false; - return SetParamValue( it - params.begin(), aValue, aNotation ); + SetParamValue( static_cast( it - params.begin() ), aValue ); + return true; +} + + +bool SIM_MODEL::SetParamValue( const std::string& aParamName, const std::string& aValue, + SIM_VALUE::NOTATION aNotation ) +{ + const SIM_VALUE& value = *FindParam( aParamName )->value; + return SetParamValue( aParamName, *SIM_VALUE::Create( value.GetType(), aValue, aNotation ) ); } diff --git a/eeschema/sim/sim_model.h b/eeschema/sim/sim_model.h index 4b6685a50a..7c16281deb 100644 --- a/eeschema/sim/sim_model.h +++ b/eeschema/sim/sim_model.h @@ -532,12 +532,13 @@ public: const PARAM& GetUnderlyingParam( unsigned aParamIndex ) const; // Return the actual parameter. const PARAM& GetBaseParam( unsigned aParamIndex ) const; // Always return base parameter if it exists. - virtual bool SetParamValue( unsigned aParamIndex, const std::string& aValue, - SIM_VALUE_GRAMMAR::NOTATION aNotation - = SIM_VALUE_GRAMMAR::NOTATION::SI ); + virtual bool SetParamValue( int aParamIndex, const SIM_VALUE& aValue ); + bool SetParamValue( int aParamIndex, const std::string& aValue, + SIM_VALUE::NOTATION aNotation = SIM_VALUE::NOTATION::SI ); + bool SetParamValue( const std::string& aParamName, const SIM_VALUE& aValue ); bool SetParamValue( const std::string& aParamName, const std::string& aValue, - SIM_VALUE_GRAMMAR::NOTATION aNotation = SIM_VALUE_GRAMMAR::NOTATION::SI ); + SIM_VALUE::NOTATION aNotation = SIM_VALUE::NOTATION::SI ); bool HasOverrides() const; bool HasNonInstanceOverrides() const; diff --git a/eeschema/sim/sim_model_ngspice.cpp b/eeschema/sim/sim_model_ngspice.cpp index fff45daea8..d081d7b3c6 100644 --- a/eeschema/sim/sim_model_ngspice.cpp +++ b/eeschema/sim/sim_model_ngspice.cpp @@ -112,7 +112,8 @@ bool SIM_MODEL_NGSPICE::SetParamFromSpiceCode( const std::string& aParamName, co } ); if( paramIt != params.end() ) - return SetParamValue( paramIt - params.begin(), aParamValue, aNotation ); + return SIM_MODEL::SetParamValue( static_cast( paramIt - params.begin() ), aParamValue, + aNotation ); // One Spice param can have multiple names, we need to take this into account. @@ -142,7 +143,8 @@ bool SIM_MODEL_NGSPICE::SetParamFromSpiceCode( const std::string& aParamName, co if( paramIt == params.end() ) return false; - return SetParamValue( paramIt - params.begin(), aParamValue, aNotation ); + return SIM_MODEL::SetParamValue( static_cast( paramIt - params.begin() ), aParamValue, + aNotation ); } diff --git a/eeschema/sim/sim_model_source.cpp b/eeschema/sim/sim_model_source.cpp index c43e8f84a0..b425d17ac0 100644 --- a/eeschema/sim/sim_model_source.cpp +++ b/eeschema/sim/sim_model_source.cpp @@ -227,30 +227,29 @@ void SIM_MODEL_SOURCE::WriteDataLibFields( std::vector& aFields ) con } -bool SIM_MODEL_SOURCE::SetParamValue( unsigned aParamIndex, const std::string& aValue, - SIM_VALUE_GRAMMAR::NOTATION aNotation ) +bool SIM_MODEL_SOURCE::SetParamValue( int aParamIndex, const SIM_VALUE& aValue ) { // Sources are special. All preceding parameter values must be filled. If they are not, fill // them out automatically. If a value is nulled, delete everything after it. - if( aValue == "" ) + if( !aValue.HasValue() ) { for( int paramIndex = static_cast( aParamIndex ); paramIndex < GetParamCount(); ++paramIndex ) { - SIM_MODEL::SetParamValue( paramIndex, "", aNotation ); + SIM_MODEL::SetParamValue( paramIndex, "" ); } } else { - for( unsigned paramIndex = 0; paramIndex < aParamIndex; ++paramIndex ) + for( int paramIndex = 0; paramIndex < aParamIndex; ++paramIndex ) { if( GetParam( paramIndex ).value->ToString() == "" ) - SIM_MODEL::SetParamValue( paramIndex, "0", aNotation ); + SIM_MODEL::SetParamValue( paramIndex, "0" ); } } - return SIM_MODEL::SetParamValue( aParamIndex, aValue, aNotation ); + return SIM_MODEL::SetParamValue( aParamIndex, aValue ); } diff --git a/eeschema/sim/sim_model_source.h b/eeschema/sim/sim_model_source.h index f2e4773607..d4fe3cd617 100644 --- a/eeschema/sim/sim_model_source.h +++ b/eeschema/sim/sim_model_source.h @@ -69,9 +69,7 @@ public: void WriteDataSchFields( std::vector& aFields ) const override; void WriteDataLibFields( std::vector& aFields ) const override; - bool SetParamValue( unsigned aParamIndex, const std::string& aValue, - SIM_VALUE_GRAMMAR::NOTATION aNotation = SIM_VALUE_GRAMMAR::NOTATION::SI ) - override; + bool SetParamValue( int aParamIndex, const SIM_VALUE& aValue ) override; bool HasAutofill() const override { return true; } diff --git a/eeschema/sim/sim_model_spice.cpp b/eeschema/sim/sim_model_spice.cpp index f1a2fc0006..2217fabb8d 100644 --- a/eeschema/sim/sim_model_spice.cpp +++ b/eeschema/sim/sim_model_spice.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -50,14 +51,15 @@ std::string SPICE_GENERATOR_SPICE::Preview( const std::string& aModelName ) cons } -std::unique_ptr SIM_MODEL_SPICE::Create( const std::string& aSpiceCode ) +std::unique_ptr SIM_MODEL_SPICE::Create( const SIM_LIBRARY_SPICE& aLibrary, + const std::string& aSpiceCode ) { auto model = static_cast( SIM_MODEL::Create( SPICE_MODEL_PARSER::ReadType( aSpiceCode ) ).release() ); try { - model->m_spiceModelParser->ReadModel( aSpiceCode ); + model->m_spiceModelParser->ReadModel( aLibrary, aSpiceCode ); } catch( const IO_ERROR& e ) { @@ -85,14 +87,13 @@ SIM_MODEL_SPICE::SIM_MODEL_SPICE( TYPE aType, } -bool SIM_MODEL_SPICE::SetParamValue( unsigned aParamIndex, const std::string& aParamValue, - SIM_VALUE_GRAMMAR::NOTATION aNotation ) +bool SIM_MODEL_SPICE::SetParamValue( int aParamIndex, const SIM_VALUE& aValue ) { // Models sourced from a library are immutable. if( m_spiceCode != "" ) return false; - return SIM_MODEL::SetParamValue( aParamIndex, aParamValue, aNotation ); + return SIM_MODEL::SetParamValue( aParamIndex, aValue ); } diff --git a/eeschema/sim/sim_model_spice.h b/eeschema/sim/sim_model_spice.h index c8fb0f4454..bd954aab2c 100644 --- a/eeschema/sim/sim_model_spice.h +++ b/eeschema/sim/sim_model_spice.h @@ -29,6 +29,8 @@ #include #include +class SIM_LIBRARY_SPICE; + class SPICE_GENERATOR_SPICE : public SPICE_GENERATOR { @@ -45,7 +47,8 @@ public: friend class SPICE_GENERATOR_SPICE; friend class SPICE_MODEL_PARSER; - static std::unique_ptr Create( const std::string& aSpiceCode ); + static std::unique_ptr Create( const SIM_LIBRARY_SPICE& aLibrary, + const std::string& aSpiceCode ); SIM_MODEL_SPICE( TYPE aType, std::unique_ptr aSpiceGenerator ); @@ -55,9 +58,7 @@ public: std::unique_ptr aSpiceModelParser ); protected: - bool SetParamValue( unsigned aParamIndex, const std::string& aParamValue, - SIM_VALUE_GRAMMAR::NOTATION aNotation - = SIM_VALUE_GRAMMAR::NOTATION::SI ) override; + bool SetParamValue( int aParamIndex, const SIM_VALUE& aValue ) override; virtual bool SetParamFromSpiceCode( const std::string& aParamName, const std::string& aParamValue, diff --git a/eeschema/sim/sim_model_subckt.cpp b/eeschema/sim/sim_model_subckt.cpp index 9458ddec1f..742f7d7562 100644 --- a/eeschema/sim/sim_model_subckt.cpp +++ b/eeschema/sim/sim_model_subckt.cpp @@ -65,7 +65,8 @@ std::vector SPICE_GENERATOR_SUBCKT::CurrentNames( const std::string } -void SPICE_MODEL_PARSER_SUBCKT::ReadModel( const std::string& aSpiceCode ) +void SPICE_MODEL_PARSER_SUBCKT::ReadModel( const SIM_LIBRARY_SPICE& aLibrary, + const std::string& aSpiceCode ) { tao::pegtl::string_input<> in( aSpiceCode, "from_content" ); std::unique_ptr root; diff --git a/eeschema/sim/sim_model_subckt.h b/eeschema/sim/sim_model_subckt.h index 4ea0597786..5db33cb4e7 100644 --- a/eeschema/sim/sim_model_subckt.h +++ b/eeschema/sim/sim_model_subckt.h @@ -44,7 +44,7 @@ class SPICE_MODEL_PARSER_SUBCKT : public SPICE_MODEL_PARSER public: using SPICE_MODEL_PARSER::SPICE_MODEL_PARSER; - void ReadModel( const std::string& aSpiceCode ) override; + void ReadModel( const SIM_LIBRARY_SPICE& aLibrary, const std::string& aSpiceCode ) override; }; diff --git a/eeschema/sim/sim_value.cpp b/eeschema/sim/sim_value.cpp index 7a3fb900d8..ab5d66b490 100644 --- a/eeschema/sim/sim_value.cpp +++ b/eeschema/sim/sim_value.cpp @@ -359,10 +359,10 @@ std::string SIM_VALUE_PARSER::ExponentToMetricSuffix( double aExponent, int& aRe } -std::unique_ptr SIM_VALUE::Create( TYPE aType, std::string aString ) +std::unique_ptr SIM_VALUE::Create( TYPE aType, std::string aString, NOTATION aNotation ) { std::unique_ptr value = SIM_VALUE::Create( aType ); - value->FromString( aString ); + value->FromString( aString, aNotation ); return value; } @@ -411,6 +411,18 @@ template SIM_VALUE_COMPLEX::SIM_VALUE_INST( const std::complex& aValue ) template SIM_VALUE_STRING::SIM_VALUE_INST( const std::string& aValue ); +template <> SIM_VALUE::TYPE SIM_VALUE_BOOL::GetType() const { return TYPE_BOOL; } +template <> SIM_VALUE::TYPE SIM_VALUE_INT::GetType() const { return TYPE_INT; } +template <> SIM_VALUE::TYPE SIM_VALUE_FLOAT::GetType() const { return TYPE_FLOAT; } +template <> SIM_VALUE::TYPE SIM_VALUE_COMPLEX::GetType() const { return TYPE_FLOAT; } +template <> SIM_VALUE::TYPE SIM_VALUE_STRING::GetType() const { return TYPE_STRING; } +// TODO +/*template <> SIM_VALUE::TYPE SIM_VALUE_BOOL_VECTOR::GetType() const { return TYPE_BOOL; } +template <> SIM_VALUE::TYPE SIM_VALUE_INT_VECTOR::GetType() const { return TYPE_INT; } +template <> SIM_VALUE::TYPE SIM_VALUE_FLOAT_VECTOR::GetType() const { return TYPE_FLOAT; } +template <> SIM_VALUE::TYPE SIM_VALUE_COMPLEX_VECTOR::GetType() const { return TYPE_COMPLEX; }*/ + + template bool SIM_VALUE_INST::HasValue() const { @@ -639,6 +651,14 @@ std::string SIM_VALUE_COMPLEX::ToSimpleString() const } +template +void SIM_VALUE_INST::operator=( const SIM_VALUE& aOther ) +{ + auto other = dynamic_cast*>( &aOther ); + m_value = other->m_value; +} + + template bool SIM_VALUE_INST::operator==( const T& aOther ) const { diff --git a/eeschema/sim/sim_value.h b/eeschema/sim/sim_value.h index 4401a6d9f1..2b9e066c47 100644 --- a/eeschema/sim/sim_value.h +++ b/eeschema/sim/sim_value.h @@ -65,15 +65,19 @@ public: TYPE_COMPLEX_VECTOR }; - static std::unique_ptr Create( TYPE aType, std::string aString ); + static std::unique_ptr Create( TYPE aType, std::string aString, + NOTATION aNotation = NOTATION::SI ); static std::unique_ptr Create( TYPE aType ); virtual ~SIM_VALUE() = default; SIM_VALUE() = default; + virtual TYPE GetType() const = 0; + virtual bool HasValue() const = 0; void operator=( const std::string& aString ); + virtual void operator=( const SIM_VALUE& aValue ) = 0; virtual bool operator==( const SIM_VALUE& aOther ) const = 0; bool operator!=( const SIM_VALUE& aOther ) const; @@ -93,13 +97,16 @@ public: SIM_VALUE_INST() = default; SIM_VALUE_INST( const T& aValue ); + TYPE GetType() const override; bool HasValue() const override; // TODO: Don't pass aNotation. Make a FromSpiceString() function instead. + // TODO: Don't use FromString(). Use assignment. Values should be immutable. bool FromString( const std::string& aString, NOTATION aNotation = NOTATION::SI ) override; std::string ToString( NOTATION aNotation = NOTATION::SI ) const override; std::string ToSimpleString() const override; + void operator=( const SIM_VALUE& aOther ) override; void operator=( const T& aValue ); bool operator==( const T& aOther ) const; bool operator==( const SIM_VALUE& aOther ) const override; diff --git a/eeschema/sim/spice_grammar.h b/eeschema/sim/spice_grammar.h index d69f52b7c6..cc4f0b0b45 100644 --- a/eeschema/sim/spice_grammar.h +++ b/eeschema/sim/spice_grammar.h @@ -102,7 +102,7 @@ namespace SPICE_GRAMMAR struct token : seq, not_at, - not_one<' ', '\t', '=', '(', ')', ',', '+', '-', '*', '/', '^', ';'>>> + not_one<' ', '\t', '=', '(', ')', ',', '*', '/', '^', ';'>>> {}; struct param : token {}; @@ -112,6 +112,18 @@ namespace SPICE_GRAMMAR sep, paramValue> {}; struct paramValuePairs : list {}; + struct dotModelAko : seq, + if_must, + opt, + modelName, + opt, + opt>> {}; struct dotModel : seq, if_must, opt, newline>> {}; + struct dotSubcktPinName : seq, @@ -147,7 +160,8 @@ namespace SPICE_GRAMMAR spiceUnit>>> {}; - struct modelUnit : sor {}; @@ -229,6 +243,8 @@ namespace SPICE_GRAMMAR template <> inline constexpr auto errorMessage> = ""; template <> inline constexpr auto errorMessage = "expected model name"; template <> inline constexpr auto errorMessage = "expected model type"; + template <> inline constexpr auto errorMessage> = ""; template <> inline constexpr auto errorMessage> = ""; template <> inline constexpr auto errorMessageis_type() ) { - m_library.m_models.push_back( SIM_MODEL_SPICE::Create( node->string() ) ); - - if( node->children.size() < 1 - || !node->children.at( 0 )->is_type() ) - { - THROW_IO_ERROR( wxString::Format( "Model name token not found" ) ); - } - + m_library.m_models.push_back( SIM_MODEL_SPICE::Create( m_library, node->string() ) ); m_library.m_modelNames.emplace_back( node->children.at( 0 )->string() ); } else if( node->is_type() ) diff --git a/eeschema/sim/spice_library_parser.h b/eeschema/sim/spice_library_parser.h index bc7b111a00..2b5800044c 100644 --- a/eeschema/sim/spice_library_parser.h +++ b/eeschema/sim/spice_library_parser.h @@ -35,7 +35,7 @@ class SPICE_LIBRARY_PARSER public: SPICE_LIBRARY_PARSER( SIM_LIBRARY_SPICE& aLibrary ) : m_library( aLibrary ) {} - virtual void ReadFile( const wxString& aFilePath ); + virtual void ReadFile( const std::string& aFilePath ); private: SIM_LIBRARY_SPICE& m_library; diff --git a/eeschema/sim/spice_model_parser.cpp b/eeschema/sim/spice_model_parser.cpp index 4a0b143c3c..5a4cbebee6 100644 --- a/eeschema/sim/spice_model_parser.cpp +++ b/eeschema/sim/spice_model_parser.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -38,6 +39,7 @@ namespace SIM_MODEL_SPICE_PARSER template struct spiceUnitSelector : std::false_type {}; + template <> struct spiceUnitSelector : std::true_type {}; template <> struct spiceUnitSelector : std::true_type {}; template <> struct spiceUnitSelector : std::true_type {}; template <> struct spiceUnitSelector : std::true_type {}; @@ -130,7 +132,8 @@ SIM_MODEL::TYPE SPICE_MODEL_PARSER::ReadType( const std::string& aSpiceCode ) } -void SPICE_MODEL_PARSER::ReadModel( const std::string& aSpiceCode ) +void SPICE_MODEL_PARSER::ReadModel( const SIM_LIBRARY_SPICE& aLibrary, + const std::string& aSpiceCode ) { // The default behavior is to treat the Spice param=value pairs as the model parameters and // values (for many models the correspondence is not exact, so this function is overridden). @@ -153,9 +156,25 @@ void SPICE_MODEL_PARSER::ReadModel( const std::string& aSpiceCode ) for( const auto& node : root->children ) { - if( node->is_type() ) + if( node->is_type() ) { - std::string paramName = ""; + std::string modelName = node->children.at( 0 )->string(); + std::string akoName = node->children.at( 1 )->string(); + + const SIM_MODEL* sourceModel = aLibrary.FindModel( modelName ); + + if( !sourceModel ) + { + THROW_IO_ERROR( wxString::Format( + _( "Could not find model '%s' to copy for ako model '%s'" ), + akoName, + modelName ) ); + } + + for( int i = 0; i < static_cast( sourceModel->GetParamCount() ); ++i ) + m_model.SetParamValue( i, *sourceModel->GetParam( i ).value ); + + std::string paramName; for( const auto& subnode : node->children ) { @@ -178,9 +197,48 @@ void SPICE_MODEL_PARSER::ReadModel( const std::string& aSpiceCode ) if( !m_model.SetParamFromSpiceCode( paramName, subnode->string() ) ) { THROW_IO_ERROR( wxString::Format( - _( "Failed to set parameter '%s' to '%s'" ), + _( "Failed to set parameter '%s' to '%s' in model '%s'" ), paramName, - subnode->string() ) ); + subnode->string(), + modelName ) ); + } + } + else + { + wxFAIL_MSG( "Unhandled parse tree subnode" ); + } + } + } + else if( node->is_type() ) + { + std::string modelName; + std::string paramName; + + for( const auto& subnode : node->children ) + { + if( subnode->is_type() ) + { + modelName = subnode->string(); + } + else if( subnode->is_type() ) + { + // Do nothing. + } + else if( subnode->is_type() ) + { + paramName = subnode->string(); + } + else if( subnode->is_type() ) + { + wxASSERT( paramName != "" ); + + if( !m_model.SetParamFromSpiceCode( paramName, subnode->string() ) ) + { + THROW_IO_ERROR( wxString::Format( + _( "Failed to set parameter '%s' to '%s' in model '%s'" ), + paramName, + subnode->string(), + modelName ) ); } } else @@ -230,3 +288,9 @@ SIM_MODEL::TYPE SPICE_MODEL_PARSER::ReadTypeFromSpiceStrings( const std::string& // have an error if there is a type KiCad does not recognize. return SIM_MODEL::TYPE::RAWSPICE; } + + +void SPICE_MODEL_PARSER::CopyModelFromLibrary( const SIM_LIBRARY_SPICE& aSourceLibrary, + const std::string& aModelName ) +{ +} diff --git a/eeschema/sim/spice_model_parser.h b/eeschema/sim/spice_model_parser.h index 3c2c1099cb..62802fffcb 100644 --- a/eeschema/sim/spice_model_parser.h +++ b/eeschema/sim/spice_model_parser.h @@ -28,6 +28,7 @@ #include class SIM_MODEL_SPICE; +class SIM_LIBRARY_SPICE; class SPICE_MODEL_PARSER @@ -36,8 +37,9 @@ public: static SIM_MODEL::TYPE ReadType( const std::string& aSpiceCode ); SPICE_MODEL_PARSER( SIM_MODEL_SPICE& aModel ) : m_model( aModel ) {} + virtual ~SPICE_MODEL_PARSER() = default; - virtual void ReadModel( const std::string& aSpiceCode ); + virtual void ReadModel( const SIM_LIBRARY_SPICE& aLibrary, const std::string& aSpiceCode ); protected: static SIM_MODEL::TYPE ReadTypeFromSpiceStrings( const std::string& aTypeString, @@ -45,6 +47,9 @@ protected: const std::string& aVersion = "", bool aSkipDefaultLevel = true ); + void CopyModelFromLibrary( const SIM_LIBRARY_SPICE& aSourceLibrary, + const std::string& aModelName ); + SIM_MODEL_SPICE& m_model; };