From 6b70c679cff4b1c8cbba7f6fd8779b80d347c2eb Mon Sep 17 00:00:00 2001 From: Jeff Young Date: Sat, 17 Dec 2022 15:21:35 +0000 Subject: [PATCH] Migrate more V6 SPICE syntax to V7. Also fixes various bugs if symbols contained non-indexed pin numbers. We really need to know the actual pin names when creating models, rather than just assuming 1, 2... etc. Fixes https://gitlab.com/kicad/code/kicad/issues/13183 --- eeschema/dialogs/dialog_sim_model.cpp | 24 +- eeschema/sim/sim_lib_mgr.cpp | 47 ++-- eeschema/sim/sim_lib_mgr.h | 15 +- eeschema/sim/sim_library_kibis.cpp | 12 +- eeschema/sim/sim_model.cpp | 327 +++++++++++++++++--------- eeschema/sim/sim_model.h | 29 ++- eeschema/sim/sim_model_kibis.cpp | 17 -- eeschema/sim/sim_model_kibis.h | 7 +- eeschema/sim/sim_model_source.cpp | 6 +- 9 files changed, 306 insertions(+), 178 deletions(-) diff --git a/eeschema/dialogs/dialog_sim_model.cpp b/eeschema/dialogs/dialog_sim_model.cpp index 4c2f5b1da9..85acf7de33 100644 --- a/eeschema/dialogs/dialog_sim_model.cpp +++ b/eeschema/dialogs/dialog_sim_model.cpp @@ -240,14 +240,22 @@ bool DIALOG_SIM_MODEL::TransferDataToWindow() m_curModelType = SIM_MODEL::ReadTypeFromFields( m_fields ); } + std::vector sourcePins = m_symbol.GetAllLibPins(); + + std::sort( sourcePins.begin(), sourcePins.end(), + []( const LIB_PIN* lhs, const LIB_PIN* rhs ) + { + return StrNumCmp( lhs->GetNumber(), rhs->GetNumber(), true ) < 0; + } ); + for( SIM_MODEL::TYPE type : SIM_MODEL::TYPE_ITERATOR() ) { try { if( m_useInstanceModelRadioButton->GetValue() && type == m_curModelType ) - m_builtinModelsMgr.CreateModel( m_fields, m_symbol.GetFullPinCount() ); + m_builtinModelsMgr.CreateModel( m_fields, sourcePins ); else - m_builtinModelsMgr.CreateModel( type, m_symbol.GetFullPinCount() ); + m_builtinModelsMgr.CreateModel( type, sourcePins ); } catch( const IO_ERROR& e ) { @@ -656,6 +664,14 @@ void DIALOG_SIM_MODEL::loadLibrary( const wxString& aLibraryP return; } + std::vector sourcePins = m_symbol.GetAllLibPins(); + + std::sort( sourcePins.begin(), sourcePins.end(), + []( const LIB_PIN* lhs, const LIB_PIN* rhs ) + { + return StrNumCmp( lhs->GetNumber(), rhs->GetNumber(), true ) < 0; + } ); + try { std::string modelName = SIM_MODEL::GetFieldValue( &m_fields, SIM_LIBRARY::NAME_FIELD ); @@ -663,9 +679,9 @@ void DIALOG_SIM_MODEL::loadLibrary( const wxString& aLibraryP for( auto& [baseModelName, baseModel] : library()->GetModels() ) { if( baseModelName == modelName ) - m_libraryModelsMgr.CreateModel( baseModel, m_symbol.GetFullPinCount(), m_fields ); + m_libraryModelsMgr.CreateModel( baseModel, sourcePins, m_fields ); else - m_libraryModelsMgr.CreateModel( baseModel, m_symbol.GetFullPinCount() ); + m_libraryModelsMgr.CreateModel( baseModel, sourcePins ); } } catch( const IO_ERROR& e ) diff --git a/eeschema/sim/sim_lib_mgr.cpp b/eeschema/sim/sim_lib_mgr.cpp index f194b6f9d4..07b3f8b8f9 100644 --- a/eeschema/sim/sim_lib_mgr.cpp +++ b/eeschema/sim/sim_lib_mgr.cpp @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -143,31 +144,35 @@ SIM_LIBRARY& SIM_LIB_MGR::SetLibrary( const wxString& aLibraryPath, REPORTER* aR } -SIM_MODEL& SIM_LIB_MGR::CreateModel( SIM_MODEL::TYPE aType, int aSymbolPinCount ) +SIM_MODEL& SIM_LIB_MGR::CreateModel( SIM_MODEL::TYPE aType, const std::vector& aPins ) { - m_models.push_back( SIM_MODEL::Create( aType, aSymbolPinCount ) ); + m_models.push_back( SIM_MODEL::Create( aType, aPins ) ); return *m_models.back(); } -SIM_MODEL& SIM_LIB_MGR::CreateModel( const SIM_MODEL& aBaseModel, int aSymbolPinCount ) +SIM_MODEL& SIM_LIB_MGR::CreateModel( const SIM_MODEL& aBaseModel, + const std::vector& aPins ) { - m_models.push_back( SIM_MODEL::Create( aBaseModel, aSymbolPinCount ) ); + m_models.push_back( SIM_MODEL::Create( aBaseModel, aPins ) ); return *m_models.back(); } template -SIM_MODEL& SIM_LIB_MGR::CreateModel( const SIM_MODEL& aBaseModel, int aSymbolPinCount, +SIM_MODEL& SIM_LIB_MGR::CreateModel( const SIM_MODEL& aBaseModel, + const std::vector& aPins, const std::vector& aFields ) { - m_models.push_back( SIM_MODEL::Create( aBaseModel, aSymbolPinCount, aFields ) ); + m_models.push_back( SIM_MODEL::Create( aBaseModel, aPins, aFields ) ); return *m_models.back(); } -template SIM_MODEL& SIM_LIB_MGR::CreateModel( const SIM_MODEL& aBaseModel, int aSymbolPinCount, +template SIM_MODEL& SIM_LIB_MGR::CreateModel( const SIM_MODEL& aBaseModel, + const std::vector& aPins, const std::vector& aFields ); -template SIM_MODEL& SIM_LIB_MGR::CreateModel( const SIM_MODEL& aBaseModel, int aSymbolPinCount, +template SIM_MODEL& SIM_LIB_MGR::CreateModel( const SIM_MODEL& aBaseModel, + const std::vector& aPins, const std::vector& aFields ); @@ -220,37 +225,47 @@ SIM_LIBRARY::MODEL SIM_LIB_MGR::CreateModel( const SCH_SHEET_PATH* aSheetPath, S } } - return CreateModel( fields, static_cast( aSymbol.GetRawPins().size() ) ); + std::vector sourcePins = aSymbol.GetAllLibPins(); + + std::sort( sourcePins.begin(), sourcePins.end(), + []( const LIB_PIN* lhs, const LIB_PIN* rhs ) + { + return StrNumCmp( lhs->GetNumber(), rhs->GetNumber(), true ) < 0; + } ); + + return CreateModel( fields, sourcePins ); } + template -SIM_LIBRARY::MODEL SIM_LIB_MGR::CreateModel( const std::vector& aFields, int aSymbolPinCount ) +SIM_LIBRARY::MODEL SIM_LIB_MGR::CreateModel( const std::vector& aFields, + const std::vector& aPins ) { std::string libraryPath = SIM_MODEL::GetFieldValue( &aFields, SIM_LIBRARY::LIBRARY_FIELD ); std::string baseModelName = SIM_MODEL::GetFieldValue( &aFields, SIM_LIBRARY::NAME_FIELD ); if( libraryPath != "" ) { - return CreateModel( libraryPath, baseModelName, aFields, aSymbolPinCount ); + return CreateModel( libraryPath, baseModelName, aFields, aPins ); } else { - m_models.push_back( SIM_MODEL::Create( aSymbolPinCount, aFields ) ); + m_models.push_back( SIM_MODEL::Create( aFields, aPins ) ); return { baseModelName, *m_models.back() }; } } template SIM_LIBRARY::MODEL SIM_LIB_MGR::CreateModel( const std::vector& aFields, - int aSymbolPinCount ); + const std::vector& aPins ); template SIM_LIBRARY::MODEL SIM_LIB_MGR::CreateModel( const std::vector& aFields, - int aSymbolPinCount ); + const std::vector& aPins ); template SIM_LIBRARY::MODEL SIM_LIB_MGR::CreateModel( const wxString& aLibraryPath, const std::string& aBaseModelName, const std::vector& aFields, - int aSymbolPinCount ) + const std::vector& aPins ) { wxString path = ResolveLibraryPath( aLibraryPath, m_project ); SIM_LIBRARY* library = nullptr; @@ -286,7 +301,7 @@ SIM_LIBRARY::MODEL SIM_LIB_MGR::CreateModel( const wxString& aLibraryPath, path ) ); } - m_models.push_back( SIM_MODEL::Create( *baseModel, aSymbolPinCount, aFields ) ); + m_models.push_back( SIM_MODEL::Create( *baseModel, aPins, aFields ) ); return { aBaseModelName, *m_models.back() }; } diff --git a/eeschema/sim/sim_lib_mgr.h b/eeschema/sim/sim_lib_mgr.h index 77a4a16910..ee735469e1 100644 --- a/eeschema/sim/sim_lib_mgr.h +++ b/eeschema/sim/sim_lib_mgr.h @@ -48,23 +48,26 @@ public: SIM_LIBRARY& AddLibrary( const wxString& aLibraryPath, REPORTER* aReporter ); SIM_LIBRARY& SetLibrary( const wxString& aLibraryPath, REPORTER* aReporter ); - SIM_MODEL& CreateModel( SIM_MODEL::TYPE aType, int aSymbolPinCount ); + SIM_MODEL& CreateModel( SIM_MODEL::TYPE aType, const std::vector& aPins ); - SIM_MODEL& CreateModel( const SIM_MODEL& aBaseModel, int aSymbolPinCount ); + SIM_MODEL& CreateModel( const SIM_MODEL& aBaseModel, const std::vector& aPins ); template - SIM_MODEL& CreateModel( const SIM_MODEL& aBaseModel, int aSymbolPinCount, + SIM_MODEL& CreateModel( const SIM_MODEL& aBaseModel, const std::vector& aPins, const std::vector& aFields ); // TODO: The argument can be made const. SIM_LIBRARY::MODEL CreateModel( const SCH_SHEET_PATH* aSheetPath, SCH_SYMBOL& aSymbol ); template - SIM_LIBRARY::MODEL CreateModel( const std::vector& aFields, int aSymbolPinCount ); + SIM_LIBRARY::MODEL CreateModel( const std::vector& aFields, + const std::vector& aPins ); template - SIM_LIBRARY::MODEL CreateModel( const wxString& aLibraryPath, const std::string& aBaseModelName, - const std::vector& aFields, int aSymbolPinCount ); + SIM_LIBRARY::MODEL CreateModel( const wxString& aLibraryPath, + const std::string& aBaseModelName, + const std::vector& aFields, + const std::vector& aPins ); void SetModel( int aIndex, std::unique_ptr aModel ); diff --git a/eeschema/sim/sim_library_kibis.cpp b/eeschema/sim/sim_library_kibis.cpp index b2f257f466..0bedfa4a45 100644 --- a/eeschema/sim/sim_library_kibis.cpp +++ b/eeschema/sim/sim_library_kibis.cpp @@ -28,6 +28,7 @@ #include #include #include +#include void SIM_LIBRARY_KIBIS::ReadFile( const std::string& aFilePath ) @@ -36,16 +37,17 @@ void SIM_LIBRARY_KIBIS::ReadFile( const std::string& aFilePath ) m_kibis = KIBIS( aFilePath, m_reporter ); if( !m_kibis.m_valid ) - { THROW_IO_ERROR( wxString::Format( "Invalid ibis file" ) ); - return; - } - unsigned pinNumber = 2; + LIB_PIN pinA( nullptr ); + LIB_PIN pinB( nullptr ); + pinA.SetNumber( wxT( "1" ) ); + pinB.SetNumber( wxT( "2" ) ); + std::vector pins = { &pinA, &pinB }; for( KIBIS_COMPONENT& kcomp : m_kibis.m_components ) { - m_models.push_back( SIM_MODEL::Create( SIM_MODEL::TYPE::KIBIS_DEVICE, pinNumber ) ); + m_models.push_back( SIM_MODEL::Create( SIM_MODEL::TYPE::KIBIS_DEVICE, pins ) ); m_modelNames.emplace_back( kcomp.m_name ); SIM_MODEL_KIBIS* libcomp = dynamic_cast( m_models.back().get() ); diff --git a/eeschema/sim/sim_model.cpp b/eeschema/sim/sim_model.cpp index c0130ed1f7..5410072166 100644 --- a/eeschema/sim/sim_model.cpp +++ b/eeschema/sim/sim_model.cpp @@ -179,7 +179,7 @@ SIM_MODEL::INFO SIM_MODEL::TypeInfo( TYPE aType ) case TYPE::NMOS_HISIMHV2: return { DEVICE_T::NMOS, "HISIMHV2", "HiSIM_HV2" }; case TYPE::PMOS_HISIMHV2: return { DEVICE_T::PMOS, "HISIMHV2", "HiSIM_HV2" }; - case TYPE::V: return { DEVICE_T::V, "", "DC", }; + case TYPE::V: return { DEVICE_T::V, "DC", "DC", }; case TYPE::V_SIN: return { DEVICE_T::V, "SIN", "Sine" }; case TYPE::V_PULSE: return { DEVICE_T::V, "PULSE", "Pulse" }; case TYPE::V_EXP: return { DEVICE_T::V, "EXP", "Exponential" }; @@ -195,7 +195,7 @@ SIM_MODEL::INFO SIM_MODEL::TypeInfo( TYPE aType ) //case TYPE::V_RANDPOISSON: return { DEVICE_TYPE::V, "RANDPOISSON", "Random Poisson" }; case TYPE::V_BEHAVIORAL: return { DEVICE_T::V, "=", "Behavioral" }; - case TYPE::I: return { DEVICE_T::I, "", "DC", }; + case TYPE::I: return { DEVICE_T::I, "DC", "DC", }; case TYPE::I_SIN: return { DEVICE_T::I, "SIN", "Sine" }; case TYPE::I_PULSE: return { DEVICE_T::I, "PULSE", "Pulse" }; case TYPE::I_EXP: return { DEVICE_T::I, "EXP", "Exponential" }; @@ -312,12 +312,12 @@ SIM_MODEL::SPICE_INFO SIM_MODEL::SpiceInfo( TYPE aType ) case TYPE::NMOS_HISIMHV2: return { "M", "NMOS", "", "73", true, false, "2.2.0" }; case TYPE::PMOS_HISIMHV2: return { "M", "PMOS", "", "73", true, false, "2.2.0" }; - case TYPE::V: return { "V", "" }; + case TYPE::V: return { "V", "", "DC" }; case TYPE::V_SIN: return { "V", "", "SIN" }; case TYPE::V_PULSE: return { "V", "", "PULSE" }; case TYPE::V_EXP: return { "V", "", "EXP" }; - /*case TYPE::V_SFAM: return { "V", "", "AM" }; - case TYPE::V_SFFM: return { "V", "", "SFFM" };*/ + //case TYPE::V_SFAM: return { "V", "", "AM" }; + //case TYPE::V_SFFM: return { "V", "", "SFFM" }; case TYPE::V_PWL: return { "V", "", "PWL" }; case TYPE::V_WHITENOISE: return { "V", "", "TRNOISE" }; case TYPE::V_PINKNOISE: return { "V", "", "TRNOISE" }; @@ -325,15 +325,15 @@ SIM_MODEL::SPICE_INFO SIM_MODEL::SpiceInfo( TYPE aType ) case TYPE::V_RANDUNIFORM: return { "V", "", "TRRANDOM" }; case TYPE::V_RANDNORMAL: return { "V", "", "TRRANDOM" }; case TYPE::V_RANDEXP: return { "V", "", "TRRANDOM" }; - //case TYPE::V_RANDPOISSON: return { "V", "", "TRRANDOM" }; + //case TYPE::V_RANDPOISSON: return { "V", "", "TRRANDOM" }; case TYPE::V_BEHAVIORAL: return { "B" }; - case TYPE::I: return { "I", "" }; + case TYPE::I: return { "I", "", "DC" }; case TYPE::I_PULSE: return { "I", "", "PULSE" }; case TYPE::I_SIN: return { "I", "", "SIN" }; case TYPE::I_EXP: return { "I", "", "EXP" }; - /*case TYPE::I_SFAM: return { "V", "", "AM" }; - case TYPE::I_SFFM: return { "V", "", "SFFM" };*/ + //case TYPE::I_SFAM: return { "V", "", "AM" }; + //case TYPE::I_SFFM: return { "V", "", "SFFM" }; case TYPE::I_PWL: return { "I", "", "PWL" }; case TYPE::I_WHITENOISE: return { "I", "", "TRNOISE" }; case TYPE::I_PINKNOISE: return { "I", "", "TRNOISE" }; @@ -341,7 +341,7 @@ SIM_MODEL::SPICE_INFO SIM_MODEL::SpiceInfo( TYPE aType ) case TYPE::I_RANDUNIFORM: return { "I", "", "TRRANDOM" }; case TYPE::I_RANDNORMAL: return { "I", "", "TRRANDOM" }; case TYPE::I_RANDEXP: return { "I", "", "TRRANDOM" }; - //case TYPE::I_RANDPOISSON: return { "I", "", "TRRANDOM" }; + //case TYPE::I_RANDPOISSON: return { "I", "", "TRRANDOM" }; case TYPE::I_BEHAVIORAL: return { "B" }; case TYPE::SUBCKT: return { "X" }; @@ -412,83 +412,62 @@ TYPE SIM_MODEL::InferTypeFromLegacyFields( const std::vector& aFields ) } -template -void SIM_MODEL::ReadDataFields( unsigned aSymbolPinCount, const std::vector* aFields ) -{ - doReadDataFields( aSymbolPinCount, aFields ); -} - - template <> void SIM_MODEL::ReadDataFields( unsigned aSymbolPinCount, const std::vector* aFields ) { - ReadDataSchFields( aSymbolPinCount, aFields ); + doReadDataFields( aSymbolPinCount, aFields ); } template <> void SIM_MODEL::ReadDataFields( unsigned aSymbolPinCount, const std::vector* aFields ) -{ - ReadDataLibFields( aSymbolPinCount, aFields ); -} - - -void SIM_MODEL::ReadDataSchFields( unsigned aSymbolPinCount, const std::vector* aFields ) { doReadDataFields( aSymbolPinCount, aFields ); } -void SIM_MODEL::ReadDataLibFields( unsigned aSymbolPinCount, const std::vector* aFields ) +template <> +void SIM_MODEL::ReadDataFields( const std::vector* aFields, + const std::vector& aPins ) { - doReadDataFields( aSymbolPinCount, aFields ); + doReadDataFields( aFields, aPins ); } -template -void SIM_MODEL::WriteFields( std::vector& aFields ) const +template <> +void SIM_MODEL::ReadDataFields( const std::vector* aFields, + const std::vector& aPins ) { - doWriteFields( aFields ); + doReadDataFields( aFields, aPins ); } template <> void SIM_MODEL::WriteFields( std::vector& aFields ) const { - WriteDataSchFields( aFields ); + doWriteFields( aFields ); } template <> void SIM_MODEL::WriteFields( std::vector& aFields ) const -{ - WriteDataLibFields( aFields ); -} - - -void SIM_MODEL::WriteDataSchFields( std::vector& aFields ) const -{ - doWriteFields( aFields ); -} - - -void SIM_MODEL::WriteDataLibFields( std::vector& aFields ) const { doWriteFields( aFields ); } -std::unique_ptr SIM_MODEL::Create( TYPE aType, unsigned aSymbolPinCount ) +std::unique_ptr SIM_MODEL::Create( TYPE aType, const std::vector& aPins ) { std::unique_ptr model = Create( aType ); // Passing nullptr to ReadDataFields will make it act as if all fields were empty. - model->ReadDataFields( aSymbolPinCount, static_cast*>( nullptr ) ); + model->ReadDataFields( static_cast*>( nullptr ), aPins ); return model; } -std::unique_ptr SIM_MODEL::Create( const SIM_MODEL& aBaseModel, unsigned aSymbolPinCount ) +std::unique_ptr SIM_MODEL::Create( const SIM_MODEL& aBaseModel, + const std::vector& aPins) { std::unique_ptr model = Create( aBaseModel.GetType() ); @@ -501,13 +480,14 @@ std::unique_ptr SIM_MODEL::Create( const SIM_MODEL& aBaseModel, unsig DisplayErrorMessage( nullptr, err.What() ); } - model->ReadDataFields( aSymbolPinCount, static_cast*>( nullptr ) ); + model->ReadDataFields( static_cast*>( nullptr ), aPins ); return model; } template -std::unique_ptr SIM_MODEL::Create( const SIM_MODEL& aBaseModel, unsigned aSymbolPinCount, +std::unique_ptr SIM_MODEL::Create( const SIM_MODEL& aBaseModel, + const std::vector& aPins, const std::vector& aFields ) { TYPE type = ReadTypeFromFields( aFields ); @@ -526,34 +506,35 @@ std::unique_ptr SIM_MODEL::Create( const SIM_MODEL& aBaseModel, unsig { DisplayErrorMessage( nullptr, err.What() ); } - model->ReadDataFields( aSymbolPinCount, &aFields ); + + model->ReadDataFields( &aFields, aPins ); return model; } template std::unique_ptr SIM_MODEL::Create( const SIM_MODEL& aBaseModel, - unsigned aSymbolPinCount, + const std::vector& aPins, const std::vector& aFields ); template std::unique_ptr SIM_MODEL::Create( const SIM_MODEL& aBaseModel, - unsigned aSymbolPinCount, + const std::vector& aPins, const std::vector& aFields ); template -std::unique_ptr SIM_MODEL::Create( unsigned aSymbolPinCount, - const std::vector& aFields ) +std::unique_ptr SIM_MODEL::Create( const std::vector& aFields, + const std::vector& aPins ) { TYPE type = ReadTypeFromFields( aFields ); std::unique_ptr model = SIM_MODEL::Create( type ); - model->ReadDataFields( aSymbolPinCount, &aFields ); + model->ReadDataFields( &aFields, aPins ); return model; } -template std::unique_ptr SIM_MODEL::Create( unsigned aSymbolPinCount, - const std::vector& aFields ); -template std::unique_ptr SIM_MODEL::Create( unsigned aSymbolPinCount, - const std::vector& aFields ); +template std::unique_ptr SIM_MODEL::Create( const std::vector& aFields, + const std::vector& aPins ); +template std::unique_ptr SIM_MODEL::Create( const std::vector& aFields, + const std::vector& aPins ); template @@ -619,12 +600,21 @@ void SIM_MODEL::SetFieldValue( std::vector& aFields, const std::string& aFiel aFields.emplace_back( wxPoint(), aFields.size(), parent, aFieldName ); } else if constexpr( std::is_same::value ) + { aFields.emplace_back( aFields.size(), aFieldName ); + } aFields.back().SetText( aValue ); } +template void SIM_MODEL::SetFieldValue( std::vector& aFields, + const std::string& aFieldName, + const std::string& aValue ); +template void SIM_MODEL::SetFieldValue( std::vector& aFields, + const std::string& aFieldName, + const std::string& aValue ); + SIM_MODEL::~SIM_MODEL() = default; @@ -1012,9 +1002,39 @@ void SIM_MODEL::CreatePins( unsigned aSymbolPinCount ) } +void SIM_MODEL::CreatePins( const std::vector aSymbolPins ) +{ + // Default pin sequence: model pins are the same as symbol pins. + // Excess model pins are set as Not Connected. + // Note that intentionally nothing is added if `getPinNames()` returns an empty vector. + + // SIM_MODEL pins must be ordered by symbol pin numbers -- this is assumed by the code that + // accesses them. + + for( unsigned modelPinIndex = 0; modelPinIndex < getPinNames().size(); ++modelPinIndex ) + { + if( modelPinIndex < aSymbolPins.size() ) + { + AddPin( { getPinNames().at( modelPinIndex ), + aSymbolPins[ modelPinIndex ]->GetNumber().ToStdString() } ); + } + else + { + AddPin( { getPinNames().at( modelPinIndex ), "" } ); + } + } +} + + +// TODO: remove this API. If we have symbol fields, then we have symbol pins and we should be +// creating a model with the real symbol pin names, not indexes... + template void SIM_MODEL::doReadDataFields( unsigned aSymbolPinCount, const std::vector* aFields ) { + bool diffMode = GetFieldValue( aFields, SIM_LIBRARY_KIBIS::DIFF_FIELD ) == "1"; + SwitchSingleEndedDiff( diffMode ); + try { m_serde->ParseEnable( GetFieldValue( aFields, ENABLE_FIELD ) ); @@ -1034,6 +1054,32 @@ void SIM_MODEL::doReadDataFields( unsigned aSymbolPinCount, const std::vector } +template +void SIM_MODEL::doReadDataFields( const std::vector* aFields, + const std::vector& aPins ) +{ + bool diffMode = GetFieldValue( aFields, SIM_LIBRARY_KIBIS::DIFF_FIELD ) == "1"; + SwitchSingleEndedDiff( diffMode ); + + try + { + m_serde->ParseEnable( GetFieldValue( aFields, ENABLE_FIELD ) ); + + CreatePins( aPins ); + m_serde->ParsePins( GetFieldValue( aFields, PINS_FIELD ) ); + + std::string paramsField = GetFieldValue( aFields, PARAMS_FIELD ); + + if( !m_serde->ParseParams( paramsField ) ) + m_serde->ParseValue( GetFieldValue( aFields, VALUE_FIELD ) ); + } + catch( IO_ERROR& err ) + { + DisplayErrorMessage( nullptr, err.What() ); + } +} + + template void SIM_MODEL::doWriteFields( std::vector& aFields ) const { @@ -1173,9 +1219,6 @@ void SIM_MODEL::MigrateSimModel( T_symbol& aSymbol, const PROJECT* aProject ) return; } - wxString prefix = aSymbol.GetPrefix(); - T_field* valueField = aSymbol.FindField( wxT( "Value" ) ); - auto getSIValue = []( T_field* aField ) { @@ -1191,13 +1234,23 @@ void SIM_MODEL::MigrateSimModel( T_symbol& aSymbol, const PROJECT* aProject ) return value; }; - wxString spiceType; + wxString prefix = aSymbol.GetPrefix(); + T_field* valueField = aSymbol.FindField( wxT( "Value" ) ); + std::vector sourcePins = aSymbol.GetAllLibPins(); + + std::sort( sourcePins.begin(), sourcePins.end(), + []( const LIB_PIN* lhs, const LIB_PIN* rhs ) + { + return StrNumCmp( lhs->GetNumber(), rhs->GetNumber(), true ) < 0; + } ); + + wxString spiceDeviceType; wxString spiceModel; + wxString spiceType; wxString spiceLib; wxString pinMap; wxString spiceParams; bool modelFromValueField = false; - bool modelFromLib = false; if( aSymbol.FindField( wxT( "Spice_Primitive" ) ) || aSymbol.FindField( wxT( "Spice_Node_Sequence" ) ) @@ -1207,7 +1260,7 @@ void SIM_MODEL::MigrateSimModel( T_symbol& aSymbol, const PROJECT* aProject ) { if( T_field* primitiveField = aSymbol.FindField( wxT( "Spice_Primitive" ) ) ) { - spiceType = primitiveField->GetText(); + spiceDeviceType = primitiveField->GetText(); aSymbol.RemoveField( primitiveField ); } @@ -1237,7 +1290,7 @@ void SIM_MODEL::MigrateSimModel( T_symbol& aSymbol, const PROJECT* aProject ) if( T_field* modelField = aSymbol.FindField( wxT( "Spice_Model" ) ) ) { - spiceModel = modelField->GetText(); + spiceModel = getSIValue( modelField ); aSymbol.RemoveField( modelField ); } else @@ -1267,14 +1320,8 @@ void SIM_MODEL::MigrateSimModel( T_symbol& aSymbol, const PROJECT* aProject ) { spiceLib = libFileField->GetText(); aSymbol.RemoveField( libFileField ); - modelFromLib = true; } } - else if( prefix == wxT( "V" ) || prefix == wxT( "I" ) ) - { - spiceModel = getSIValue( valueField ); - modelFromValueField = true; - } else { // Auto convert some legacy fields used in the middle of 7.0 development... @@ -1300,8 +1347,6 @@ void SIM_MODEL::MigrateSimModel( T_symbol& aSymbol, const PROJECT* aProject ) wxStringSplit( legacyPins->GetText(), pinIndexes, ' ' ); - std::vector sourcePins = aSymbol.GetAllLibPins(); - if( isPassive && pinIndexes.size() == 2 && sourcePins.size() == 2 ) { if( pinIndexes[0] == wxT( "2" ) ) @@ -1342,7 +1387,10 @@ void SIM_MODEL::MigrateSimModel( T_symbol& aSymbol, const PROJECT* aProject ) return; } - if( modelFromLib ) + bool libraryModel = false; + bool internalModel = false; + + if( !spiceLib.IsEmpty() ) { SIM_LIB_MGR libMgr( aProject ); @@ -1350,18 +1398,78 @@ void SIM_MODEL::MigrateSimModel( T_symbol& aSymbol, const PROJECT* aProject ) { std::vector emptyFields; SIM_LIBRARY::MODEL model = libMgr.CreateModel( spiceLib, spiceModel.ToStdString(), - emptyFields, aSymbol.GetFullPinCount() ); + emptyFields, sourcePins ); spiceParams = wxString( model.model.GetBaseModel()->Serde().GenerateParams() ); + libraryModel = true; + + if( pinMap.IsEmpty() ) + { + // Generate a default pin map + model.model.CreatePins( sourcePins ); + pinMap = wxString( model.model.Serde().GeneratePins() ); + } } catch( ... ) { // Fall back to raw spice model - modelFromLib = false; } } + else + { + // Convert functional SPICE model syntax to name=value pairs. For instance, "dc(1)" + // needs to go to "dc=1", while "sin(0, 1, 60)" needs to go to "dc=0 ampl=1 f=60". + + wxRegEx regex( wxT( "^[a-z]+\\(.*\\)$" ) ); + + if( regex.Matches( spiceModel ) ) + { + wxString paramSet; + + spiceType = spiceModel.BeforeFirst( '(', ¶mSet ); + paramSet = paramSet.BeforeLast( ')' ); + + wxStringTokenizer tokenizer( paramSet, wxT( " " ), wxTOKEN_STRTOK ); - if( modelFromLib ) + spiceType.MakeUpper(); + + for( SIM_MODEL::TYPE type : SIM_MODEL::TYPE_ITERATOR() ) + { + if( spiceDeviceType == SIM_MODEL::SpiceInfo( type ).itemType + && spiceType == SIM_MODEL::SpiceInfo( type ).inlineTypeString ) + { + try + { + std::unique_ptr model = SIM_MODEL::Create( type ); + + for( int ii = 0; tokenizer.HasMoreTokens(); ++ii ) + { + model->SetParamValue( ii, tokenizer.GetNextToken().ToStdString(), + SIM_VALUE_GRAMMAR::NOTATION::SPICE ); + } + + spiceParams = wxString( model->Serde().GenerateParams() ); + internalModel = true; + + if( pinMap.IsEmpty() ) + { + // Generate a default pin map + model->CreatePins( sourcePins ); + pinMap = wxString( model->Serde().GeneratePins() ); + } + } + catch( ... ) + { + // Fall back to raw spice model + } + + break; + } + } + } + } + + if( libraryModel ) { T_field libraryField( &aSymbol, -1, SIM_MODEL::LIBRARY_FIELD ); libraryField.SetText( spiceLib ); @@ -1378,18 +1486,33 @@ void SIM_MODEL::MigrateSimModel( T_symbol& aSymbol, const PROJECT* aProject ) if( modelFromValueField ) valueField->SetText( wxT( "${SIM.NAME}" ) ); } - else + else if( internalModel ) { - // Insert a raw spice model as a substitute. + T_field deviceTypeField( &aSymbol, -1, SIM_MODEL::DEVICE_TYPE_FIELD ); + deviceTypeField.SetText( spiceDeviceType ); + aSymbol.AddField( deviceTypeField ); + + T_field typeField( &aSymbol, -1, SIM_MODEL::TYPE_FIELD ); + typeField.SetText( spiceType ); + aSymbol.AddField( typeField ); + + T_field paramsField( &aSymbol, -1, SIM_MODEL::PARAMS_FIELD ); + paramsField.SetText( spiceParams ); + aSymbol.AddField( paramsField ); - if( spiceType.IsEmpty() && spiceLib.IsEmpty() ) + if( modelFromValueField ) + valueField->SetText( wxT( "${SIM.PARAMS}" ) ); + } + else // Insert a raw spice model as a substitute. + { + if( spiceDeviceType.IsEmpty() && spiceLib.IsEmpty() ) { spiceParams = spiceModel; } else { spiceParams.Printf( wxT( "type=\"%s\" model=\"%s\" lib=\"%s\"" ), - spiceType, spiceModel, spiceLib ); + spiceDeviceType, spiceModel, spiceLib ); } T_field deviceTypeField( &aSymbol, -1, SIM_MODEL::DEVICE_TYPE_FIELD ); @@ -1408,41 +1531,25 @@ void SIM_MODEL::MigrateSimModel( T_symbol& aSymbol, const PROJECT* aProject ) if( valueField ) valueField->SetText( wxT( "${SIM.PARAMS}" ) ); } - } - if( !pinMap.IsEmpty() ) - { - T_field pinsField( &aSymbol, -1, SIM_MODEL::PINS_FIELD ); - - pinsField.SetText( pinMap ); - aSymbol.AddField( pinsField ); - } - else - { - // Generate a 1:1 pin map. We don't necessarily know the SPICE model pinNames, so just - // use indexes. - std::vector sourcePins = aSymbol.GetAllLibPins(); - - std::sort( sourcePins.begin(), sourcePins.end(), - []( const LIB_PIN* lhs, const LIB_PIN* rhs ) - { - return StrNumCmp( lhs->GetNumber(), rhs->GetNumber(), true ) < 0; - } ); - - for( unsigned ii = 0; ii < sourcePins.size(); ++ii ) + if( pinMap.IsEmpty() ) { - if( ii > 0 ) - pinMap.Append( wxS( " " ) ); + // Generate a 1:1 pin map. We don't know the SPICE model pinNames, so just use indexes. + for( unsigned ii = 0; ii < sourcePins.size(); ++ii ) + { + if( ii > 0 ) + pinMap.Append( wxS( " " ) ); - pinMap.Append( wxString::Format( wxT( "%s=%u" ), - sourcePins[ii]->GetNumber(), - ii + 1 ) ); + pinMap.Append( wxString::Format( wxT( "%s=%u" ), + sourcePins[ii]->GetNumber(), + ii + 1 ) ); + } } - - T_field pinsField( &aSymbol, aSymbol.GetFieldCount(), SIM_MODEL::PINS_FIELD ); - pinsField.SetText( pinMap ); - aSymbol.AddField( pinsField ); } + + T_field pinsField( &aSymbol, -1, SIM_MODEL::PINS_FIELD ); + pinsField.SetText( pinMap ); + aSymbol.AddField( pinsField ); } diff --git a/eeschema/sim/sim_model.h b/eeschema/sim/sim_model.h index 9647fe484d..93f8bc21d6 100644 --- a/eeschema/sim/sim_model.h +++ b/eeschema/sim/sim_model.h @@ -400,16 +400,19 @@ public: static TYPE InferTypeFromLegacyFields( const std::vector& aFields ); - static std::unique_ptr Create( TYPE aType, unsigned aSymbolPinCount ); - static std::unique_ptr Create( const SIM_MODEL& aBaseModel, unsigned aSymbolPinCount ); + static std::unique_ptr Create( TYPE aType, const std::vector& aPins ); + + static std::unique_ptr Create( const SIM_MODEL& aBaseModel, + const std::vector& aPins ); template - static std::unique_ptr Create( const SIM_MODEL& aBaseModel, unsigned aSymbolPinCount, + static std::unique_ptr Create( const SIM_MODEL& aBaseModel, + const std::vector& aPins, const std::vector& aFields ); template - static std::unique_ptr Create( unsigned aSymbolPinCount, - const std::vector& aFields ); + static std::unique_ptr Create( const std::vector& aFields, + const std::vector& aPins ); template static std::string GetFieldValue( const std::vector* aFields, const std::string& aFieldName ); @@ -433,18 +436,12 @@ public: template void ReadDataFields( unsigned aSymbolPinCount, const std::vector* aFields ); - virtual void ReadDataSchFields( unsigned aSymbolPinCount, - const std::vector* aFields ); - virtual void ReadDataLibFields( unsigned aSymbolPinCount, - const std::vector* aFields ); + template + void ReadDataFields( const std::vector* aFields, const std::vector& aPins ); template void WriteFields( std::vector& aFields ) const; - virtual void WriteDataSchFields( std::vector& aFields ) const; - virtual void WriteDataLibFields( std::vector& aFields ) const; - - virtual bool HasToIncludeSpiceLibrary() const { return GetBaseModel() && !HasOverrides(); } SPICE_INFO GetSpiceInfo() const { return SpiceInfo( GetType() ); } @@ -522,6 +519,8 @@ public: } bool IsStoredInValue() const { return m_isStoredInValue; } + virtual void SwitchSingleEndedDiff( bool aDiff ) { }; + template static bool InferPassiveSimModel( T& aSymbol, bool aResolve, SIM_VALUE_GRAMMAR::NOTATION aNotation, wxString* aModelType, @@ -539,11 +538,15 @@ protected: std::unique_ptr aSerde ); virtual void CreatePins( unsigned aSymbolPinCount ); + virtual void CreatePins( const std::vector aSymbolPins ); private: template void doReadDataFields( unsigned aSymbolPinCount, const std::vector* aFields ); + template + void doReadDataFields( const std::vector* aFields, const std::vector& aPins ); + template void doWriteFields( std::vector& aFields ) const; diff --git a/eeschema/sim/sim_model_kibis.cpp b/eeschema/sim/sim_model_kibis.cpp index 4b04c13f9f..877f4ecedc 100644 --- a/eeschema/sim/sim_model_kibis.cpp +++ b/eeschema/sim/sim_model_kibis.cpp @@ -499,20 +499,3 @@ std::vector SIM_MODEL_KIBIS::makePrbsWaveformParamInfos( return paramInfos; } - -void SIM_MODEL_KIBIS::ReadDataSchFields( unsigned aSymbolPinCount, const std::vector* aFields ) -{ - bool diffMode = SIM_MODEL::GetFieldValue( aFields, SIM_LIBRARY_KIBIS::DIFF_FIELD ) == "1"; - SwitchSingleEndedDiff( diffMode ); - - SIM_MODEL::ReadDataSchFields( aSymbolPinCount, aFields ); -} - - -void SIM_MODEL_KIBIS::ReadDataLibFields( unsigned aSymbolPinCount, const std::vector* aFields ) -{ - bool diffMode = SIM_MODEL::GetFieldValue( aFields, SIM_LIBRARY_KIBIS::DIFF_FIELD ) == "1"; - SwitchSingleEndedDiff( diffMode ); - - SIM_MODEL::ReadDataLibFields( aSymbolPinCount, aFields ); -} diff --git a/eeschema/sim/sim_model_kibis.h b/eeschema/sim/sim_model_kibis.h index 50b3f4f874..210b79fd8b 100644 --- a/eeschema/sim/sim_model_kibis.h +++ b/eeschema/sim/sim_model_kibis.h @@ -87,15 +87,10 @@ public: void SetBaseModel( const SIM_MODEL& aBaseModel ) override; - void SwitchSingleEndedDiff( bool aDiff ); + void SwitchSingleEndedDiff( bool aDiff ) override; bool CanDifferential() const { return m_enableDiff; } ; bool m_enableDiff; - void ReadDataSchFields( unsigned aSymbolPinCount, - const std::vector* aFields ) override; - void ReadDataLibFields( unsigned aSymbolPinCount, - const std::vector* aFields ) override; - protected: void CreatePins( unsigned aSymbolPinCount ) override; diff --git a/eeschema/sim/sim_model_source.cpp b/eeschema/sim/sim_model_source.cpp index 47582b4703..1e50ce2cba 100644 --- a/eeschema/sim/sim_model_source.cpp +++ b/eeschema/sim/sim_model_source.cpp @@ -185,10 +185,14 @@ std::string SPICE_GENERATOR_SOURCE::ItemLine( const SPICE_ITEM& aItem ) const break; } - item.modelName.append( fmt::format( "{}( {})", m_model.GetSpiceInfo().inlineTypeString, args ) ); + item.modelName.append( fmt::format( "{}( {})", + m_model.GetSpiceInfo().inlineTypeString, + args ) ); } else + { item.modelName.append( m_model.GetParam( 0 ).value->ToSpiceString() ); + } return SPICE_GENERATOR::ItemLine( item ); }