From 4931b8006672074f72dad0be2dbc181328fa514b Mon Sep 17 00:00:00 2001 From: Mikolaj Wielgus Date: Mon, 10 Oct 2022 13:35:18 +0200 Subject: [PATCH] Sim: Resolve name collisions for generated model names --- .../netlist_exporter_spice.cpp | 34 +++++++++++++++---- .../netlist_exporter_spice.h | 22 +++++++++--- eeschema/sim/sim_model_kibis.cpp | 18 +++++++--- eeschema/sim/sim_model_kibis.h | 5 ++- eeschema/sim/spice_generator.cpp | 14 ++++++++ eeschema/sim/spice_generator.h | 2 ++ 6 files changed, 77 insertions(+), 18 deletions(-) diff --git a/eeschema/netlist_exporters/netlist_exporter_spice.cpp b/eeschema/netlist_exporters/netlist_exporter_spice.cpp index 0577ecc9ba..3deaa1bcf3 100644 --- a/eeschema/netlist_exporters/netlist_exporter_spice.cpp +++ b/eeschema/netlist_exporters/netlist_exporter_spice.cpp @@ -75,6 +75,25 @@ namespace NETLIST_EXPORTER_SPICE_PARSER } +std::string NAME_GENERATOR::Generate( const std::string& aProposedName ) +{ + if( !m_names.count( aProposedName ) ) + return aProposedName; + + for( uint64_t i = 1; i < UINT64_MAX; ++i ) + { + std::string name = fmt::format( "{}#{}", aProposedName, i ); + + if( !m_names.count( name ) ) + return name; + } + + // Should never happen. + THROW_IO_ERROR( wxString::Format( _( "Failed to generate a name for '%s': exceeded UINT64_MAX" ), + aProposedName ) ); +} + + NETLIST_EXPORTER_SPICE::NETLIST_EXPORTER_SPICE( SCHEMATIC_IFACE* aSchematic ) : NETLIST_EXPORTER_BASE( aSchematic ), m_libMgr( aSchematic->Prj() ) @@ -322,11 +341,15 @@ bool NETLIST_EXPORTER_SPICE::readRefName( SCH_SHEET_PATH& aSheet, SCH_SYMBOL& aS void NETLIST_EXPORTER_SPICE::readModel( SCH_SHEET_PATH& aSheet, SCH_SYMBOL& aSymbol, ITEM& aItem ) { - auto [modelName, model] = m_libMgr.CreateModel( aSymbol ); - aItem.modelName = ( modelName != "" ) ? modelName : ( "__" + aItem.refName ); + auto [baseModelName, model] = m_libMgr.CreateModel( aSymbol ); aItem.model = &model; - // FIXME: Special cases for raw Spice models and KIBIS. + std::string modelName = aItem.model->SpiceGenerator().ModelName( aItem.refName, + baseModelName ); + // Resolve model name collisions. + aItem.modelName = m_modelNameGenerator.Generate( modelName ); + + // FIXME: Don't have special cases for raw Spice models and KIBIS. if( auto rawSpiceModel = dynamic_cast( aItem.model ) ) { int libParamIndex = static_cast( SIM_MODEL_RAW_SPICE::SPICE_PARAM::LIB ); @@ -337,9 +360,6 @@ void NETLIST_EXPORTER_SPICE::readModel( SCH_SHEET_PATH& aSheet, SCH_SYMBOL& aSym } else if( auto kibisModel = dynamic_cast( aItem.model ) ) { - aItem.modelName = aItem.model->GetFieldValue( &aSymbol.GetFields(), - SIM_LIBRARY_KIBIS::MODEL_FIELD ); - wxFileName cacheDir; cacheDir.AssignDir( PATHS::GetUserCachePath() ); cacheDir.AppendDir( wxT( "ibis" ) ); @@ -357,7 +377,7 @@ void NETLIST_EXPORTER_SPICE::readModel( SCH_SHEET_PATH& aSheet, SCH_SYMBOL& aSym } auto spiceGenerator = static_cast( kibisModel->SpiceGenerator() ); - std::string modelData = spiceGenerator.IbisDevice( aSymbol.GetFields() ); + std::string modelData = spiceGenerator.IbisDevice( aSymbol.GetFields(), aItem.modelName ); cacheFile.Write( wxString( modelData ) ); m_rawIncludes.insert( libraryPath ); diff --git a/eeschema/netlist_exporters/netlist_exporter_spice.h b/eeschema/netlist_exporters/netlist_exporter_spice.h index 901c8d7030..16f127db4e 100644 --- a/eeschema/netlist_exporters/netlist_exporter_spice.h +++ b/eeschema/netlist_exporters/netlist_exporter_spice.h @@ -32,6 +32,16 @@ #include +class NAME_GENERATOR +{ +public: + std::string Generate( const std::string& aProposedName ); + +private: + std::unordered_set m_names; +}; + + class NETLIST_EXPORTER_SPICE : public NETLIST_EXPORTER_BASE { public: @@ -141,13 +151,15 @@ private: void writeModels( OUTPUTFORMATTER& aFormatter ); void writeItems( OUTPUTFORMATTER& aFormatter ); - SIM_LIB_MGR m_libMgr; ///< Holds libraries and models - std::string m_title; ///< Spice simulation title found in the schematic sheet - std::vector m_directives; ///< Spice directives found in the schematic sheet + SIM_LIB_MGR m_libMgr; ///< Holds libraries and models + NAME_GENERATOR m_modelNameGenerator; ///< Generates unique model names + NAME_GENERATOR m_netNameGenerator; ///< Generates unique net names (only unique for NC nets for now) + std::string m_title; ///< Spice simulation title found in the schematic sheet + std::vector m_directives; ///< Spice directives found in the schematic sheet //std::map> m_libraries; ///< Spice libraries - std::set m_rawIncludes; ///< include directives found in symbols + std::set m_rawIncludes; ///< include directives found in symbols std::set m_nets; - std::list m_items; ///< Items representing schematic symbols in Spice world + std::list m_items; ///< Items representing schematic symbols in Spice world }; diff --git a/eeschema/sim/sim_model_kibis.cpp b/eeschema/sim/sim_model_kibis.cpp index 4276697bbf..4fd85025e8 100644 --- a/eeschema/sim/sim_model_kibis.cpp +++ b/eeschema/sim/sim_model_kibis.cpp @@ -28,6 +28,13 @@ #include +std::string SPICE_GENERATOR_KIBIS::ModelName( const std::string& aRefName, + const std::string& aBaseModelName ) const +{ + return fmt::format( "{}.{}", aRefName, aBaseModelName ); +} + + std::string SPICE_GENERATOR_KIBIS::ModelLine( const std::string& aModelName ) const { return ""; @@ -51,7 +58,8 @@ std::vector SPICE_GENERATOR_KIBIS::CurrentNames( const std::string& } -std::string SPICE_GENERATOR_KIBIS::IbisDevice( const std::vector& aFields ) const +std::string SPICE_GENERATOR_KIBIS::IbisDevice( const std::vector& aFields, + const std::string& aModelName ) const { std::string ibisLibFilename = SIM_MODEL::GetFieldValue( &aFields, SIM_LIBRARY::LIBRARY_FIELD ); std::string ibisCompName = SIM_MODEL::GetFieldValue( &aFields, SIM_LIBRARY::NAME_FIELD ); @@ -101,7 +109,7 @@ std::string SPICE_GENERATOR_KIBIS::IbisDevice( const std::vector& aFi switch( m_model.GetType() ) { case SIM_MODEL::TYPE::KIBIS_DEVICE: - kpin->writeSpiceDevice( &result, ibisModelName, *kmodel, kparams ); + kpin->writeSpiceDevice( &result, aModelName, *kmodel, kparams ); break; case SIM_MODEL::TYPE::KIBIS_DRIVER_DC: @@ -124,7 +132,7 @@ std::string SPICE_GENERATOR_KIBIS::IbisDevice( const std::vector& aFi static_cast( new KIBIS_WAVEFORM_STUCK_HIGH() ); } - kpin->writeSpiceDriver( &result, ibisModelName, *kmodel, kparams ); + kpin->writeSpiceDriver( &result, aModelName, *kmodel, kparams ); break; } @@ -137,7 +145,7 @@ std::string SPICE_GENERATOR_KIBIS::IbisDevice( const std::vector& aFi waveform->m_delay = static_cast( *m_model.FindParam( "delay" )->value ).Get().value_or( 0 ); kparams.m_waveform = waveform; - kpin->writeSpiceDriver( &result, ibisModelName, *kmodel, kparams ); + kpin->writeSpiceDriver( &result, aModelName, *kmodel, kparams ); break; } @@ -150,7 +158,7 @@ std::string SPICE_GENERATOR_KIBIS::IbisDevice( const std::vector& aFi waveform->m_delay = static_cast( *m_model.FindParam( "delay" )->value ).Get().value_or( 0 ); kparams.m_waveform = waveform; - kpin->writeSpiceDriver( &result, ibisModelName, *kmodel, kparams ); + kpin->writeSpiceDriver( &result, aModelName, *kmodel, kparams ); break; } diff --git a/eeschema/sim/sim_model_kibis.h b/eeschema/sim/sim_model_kibis.h index 8232b315ba..7bd426a29b 100644 --- a/eeschema/sim/sim_model_kibis.h +++ b/eeschema/sim/sim_model_kibis.h @@ -37,10 +37,13 @@ class SPICE_GENERATOR_KIBIS : public SPICE_GENERATOR public: using SPICE_GENERATOR::SPICE_GENERATOR; + std::string ModelName( const std::string& aRefName, + const std::string& aBaseModelName ) const override; std::string ModelLine( const std::string& aModelName ) const override; std::vector CurrentNames( const std::string& aRefName ) const override; - std::string IbisDevice( const std::vector& aFields ) const; + std::string IbisDevice( const std::vector& aFields, + const std::string& aModelName ) const; protected: std::vector> GetInstanceParams() const override; diff --git a/eeschema/sim/spice_generator.cpp b/eeschema/sim/spice_generator.cpp index 4f9420a38a..706856af8c 100644 --- a/eeschema/sim/spice_generator.cpp +++ b/eeschema/sim/spice_generator.cpp @@ -29,6 +29,20 @@ #include +std::string SPICE_GENERATOR::ModelName( const std::string& aRefName, + const std::string& aBaseModelName ) const +{ + if( aBaseModelName == "" ) + return fmt::format( "__{}", aRefName ); + + // FIXME: This ModelLine() call is relatively expensive. + if( ModelLine( aBaseModelName ) != "" ) + return fmt::format( "{}.{}", aRefName, aBaseModelName ); + + return aBaseModelName; +} + + std::string SPICE_GENERATOR::ModelLine( const std::string& aModelName ) const { if( !m_model.HasSpiceNonInstanceOverrides() && !m_model.requiresSpiceModelLine() ) diff --git a/eeschema/sim/spice_generator.h b/eeschema/sim/spice_generator.h index e8f2f8a85b..6cd6ebaec9 100644 --- a/eeschema/sim/spice_generator.h +++ b/eeschema/sim/spice_generator.h @@ -34,6 +34,8 @@ public: SPICE_GENERATOR( const SIM_MODEL& aModel ) : m_model( aModel ) {} virtual ~SPICE_GENERATOR() = default; + virtual std::string ModelName( const std::string& aRefName, + const std::string& aBaseModelName ) const; virtual std::string ModelLine( const std::string& aModelName ) const; std::string ItemLine( const std::string& aRefName,