Browse Source

Fix issue converting legacy SPICE models.

1) if a legacy model references a library then we need to see if said
   libraray exists and read model from it if so
2) legacy node ordering is by index, not pin name
3) we can't auto-generate a pin map when we don't know the pin names,
   so don't try
7.0
Jeff Young 3 years ago
parent
commit
50ccc4e6da
  1. 4
      eeschema/dialogs/dialog_sim_model.cpp
  2. 2
      eeschema/netlist_exporters/netlist_exporter_spice.cpp
  3. 2
      eeschema/sch_screen.cpp
  4. 9
      eeschema/sim/sim_lib_mgr.cpp
  5. 6
      eeschema/sim/sim_lib_mgr.h
  6. 144
      eeschema/sim/sim_model.cpp
  7. 7
      eeschema/sim/sim_model.h
  8. 2
      eeschema/sim/sim_model_kibis.cpp
  9. 2
      eeschema/sim/sim_plot_frame.cpp
  10. 4
      eeschema/sim/sim_serde.cpp
  11. 2
      eeschema/symbol_lib_table.cpp
  12. 2
      eeschema/symbol_library.cpp
  13. 2
      eeschema/tools/sch_editor_control.cpp
  14. 2
      qa/unittests/eeschema/sim/test_library_spice.cpp

4
eeschema/dialogs/dialog_sim_model.cpp

@ -51,8 +51,8 @@ DIALOG_SIM_MODEL<T_symbol, T_field>::DIALOG_SIM_MODEL( wxWindow* aParent, T_symb
: DIALOG_SIM_MODEL_BASE( aParent ),
m_symbol( aSymbol ),
m_fields( aFields ),
m_libraryModelsMgr( Prj() ),
m_builtinModelsMgr( Prj() ),
m_libraryModelsMgr( &Prj() ),
m_builtinModelsMgr( &Prj() ),
m_prevModel( nullptr ),
m_curModelType( SIM_MODEL::TYPE::NONE ),
m_scintillaTricks( nullptr ),

2
eeschema/netlist_exporters/netlist_exporter_spice.cpp

@ -99,7 +99,7 @@ std::string NAME_GENERATOR::Generate( const std::string& aProposedName )
NETLIST_EXPORTER_SPICE::NETLIST_EXPORTER_SPICE( SCHEMATIC_IFACE* aSchematic ) :
NETLIST_EXPORTER_BASE( aSchematic ),
m_libMgr( aSchematic->Prj() )
m_libMgr( &aSchematic->Prj() )
{
}

2
eeschema/sch_screen.cpp

@ -1856,6 +1856,6 @@ void SCH_SCREEN::MigrateSimModels()
for( SCH_ITEM* item : Items().OfType( SCH_SYMBOL_T ) )
{
SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
SIM_MODEL::MigrateSimModel<SCH_SYMBOL, SCH_FIELD>( *symbol );
SIM_MODEL::MigrateSimModel<SCH_SYMBOL, SCH_FIELD>( *symbol, &Schematic()->Prj() );
}
}

9
eeschema/sim/sim_lib_mgr.cpp

@ -34,7 +34,8 @@
#include <sim/sim_model.h>
#include <sim/sim_model_ideal.h>
SIM_LIB_MGR::SIM_LIB_MGR( const PROJECT& aPrj ) : m_project( aPrj )
SIM_LIB_MGR::SIM_LIB_MGR( const PROJECT* aPrj ) :
m_project( aPrj )
{
}
@ -46,15 +47,15 @@ void SIM_LIB_MGR::Clear()
}
wxString SIM_LIB_MGR::ResolveLibraryPath( const wxString& aLibraryPath, const PROJECT& aProject )
wxString SIM_LIB_MGR::ResolveLibraryPath( const wxString& aLibraryPath, const PROJECT* aProject )
{
wxString expandedPath = ExpandEnvVarSubstitutions( aLibraryPath, &aProject );
wxString expandedPath = ExpandEnvVarSubstitutions( aLibraryPath, aProject );
wxFileName fn( expandedPath );
if( fn.IsAbsolute() )
return fn.GetFullPath();
wxFileName projectFn( aProject.AbsolutePath( expandedPath ) );
wxFileName projectFn( aProject ? aProject->AbsolutePath( expandedPath ) : expandedPath );
if( projectFn.Exists() )
return projectFn.GetFullPath();

6
eeschema/sim/sim_lib_mgr.h

@ -40,7 +40,7 @@ class SCH_SYMBOL;
class SIM_LIB_MGR
{
public:
SIM_LIB_MGR( const PROJECT& aPrj );
SIM_LIB_MGR( const PROJECT* aPrj );
virtual ~SIM_LIB_MGR() = default;
void Clear();
@ -71,10 +71,10 @@ public:
std::map<wxString, std::reference_wrapper<const SIM_LIBRARY>> GetLibraries() const;
std::vector<std::reference_wrapper<SIM_MODEL>> GetModels() const;
static wxString ResolveLibraryPath( const wxString& aLibraryPath, const PROJECT& aProject );
static wxString ResolveLibraryPath( const wxString& aLibraryPath, const PROJECT* aProject );
private:
const PROJECT& m_project;
const PROJECT* m_project;
std::map<wxString, std::unique_ptr<SIM_LIBRARY>> m_libraries;
std::vector<std::unique_ptr<SIM_MODEL>> m_models;
};

144
eeschema/sim/sim_model.cpp

@ -41,7 +41,7 @@
#include <sim/sim_model_switch.h>
#include <sim/sim_model_tline.h>
#include <sim/sim_model_xspice.h>
#include <sim/sim_lib_mgr.h>
#include <sim/sim_library_kibis.h>
#include <boost/algorithm/string/case_conv.hpp>
@ -665,22 +665,39 @@ void SIM_MODEL::SetPinSymbolPinNumber( int aPinIndex, const std::string& aSymbol
void SIM_MODEL::SetPinSymbolPinNumber( const std::string& aPinName,
const std::string& aSymbolPinNumber )
{
int aPinIndex = -1;
const std::vector<std::reference_wrapper<const PIN>> pins = GetPins();
auto it = std::find_if( pins.begin(), pins.end(),
[aPinName]( const PIN& aPin )
{
return aPin.name == aPinName;
} );
for( int ii = 0; ii < (int) pins.size(); ++ii )
{
if( pins.at( ii ).get().name == aPinName )
{
aPinIndex = ii;
break;
}
}
if( aPinIndex < 0 )
{
// If aPinName wasn't in fact a name, see if it's a raw (1-based) index. This is
// required for legacy files which didn't use pin names.
aPinIndex = (int) strtol( aPinName.c_str(), nullptr, 10 );
if( it == pins.end() )
// Convert to 0-based. (Note that this will also convert the error state to -1, which
// means we don't have to check for it separately.)
aPinIndex--;
}
if( aPinIndex < 0 )
{
THROW_IO_ERROR( wxString::Format( _( "Could not find a pin named '%s' in simulation model of type '%s'" ),
THROW_IO_ERROR( wxString::Format( _( "Could not find a pin named '%s' in "
"simulation model of type '%s'" ),
aPinName,
GetTypeInfo().fieldValue ) );
}
SetPinSymbolPinNumber( static_cast<int>( it - pins.begin() ), aSymbolPinNumber );
SetPinSymbolPinNumber( aPinIndex, aSymbolPinNumber );
}
@ -721,7 +738,7 @@ std::vector<std::reference_wrapper<const SIM_MODEL::PARAM>> SIM_MODEL::GetParams
}
const SIM_MODEL::PARAM& SIM_MODEL::GetUnderlyingParam( unsigned aParamIndex ) const
const SIM_MODEL::PARAM& SIM_MODEL::GetParamOverride( unsigned aParamIndex ) const
{
return m_params.at( aParamIndex );
}
@ -762,7 +779,8 @@ void SIM_MODEL::SetParamValue( const std::string& aParamName, const SIM_VALUE& a
if( it == params.end() )
{
THROW_IO_ERROR( wxString::Format( _( "Could not find a parameter named '%s' in simulation model of type '%s'" ),
THROW_IO_ERROR( wxString::Format( _( "Could not find a parameter named '%s' in "
"simulation model of type '%s'" ),
aParamName,
GetTypeInfo().fieldValue ) );
}
@ -778,7 +796,8 @@ void SIM_MODEL::SetParamValue( const std::string& aParamName, const std::string&
if( !param )
{
THROW_IO_ERROR( wxString::Format( _( "Could not find a parameter named '%s' in simulation model of type '%s'" ),
THROW_IO_ERROR( wxString::Format( _( "Could not find a parameter named '%s' in "
"simulation model of type '%s'" ),
aParamName,
GetTypeInfo().fieldValue ) );
}
@ -1055,7 +1074,7 @@ std::pair<wxString, wxString> SIM_MODEL::InferSimModel( const wxString& aPrefix,
template <typename T_symbol, typename T_field>
void SIM_MODEL::MigrateSimModel( T_symbol& aSymbol )
void SIM_MODEL::MigrateSimModel( T_symbol& aSymbol, const PROJECT* aProject )
{
if( aSymbol.FindField( SIM_MODEL::DEVICE_TYPE_FIELD )
|| aSymbol.FindField( SIM_MODEL::TYPE_FIELD )
@ -1085,6 +1104,9 @@ void SIM_MODEL::MigrateSimModel( T_symbol& aSymbol )
wxString spiceModel;
wxString spiceLib;
wxString pinMap;
wxString spiceParams;
bool modelFromValueField = false;
bool modelFromLib = false;
if( aSymbol.FindField( wxT( "Spice_Primitive" ) )
|| aSymbol.FindField( wxT( "Spice_Node_Sequence" ) )
@ -1130,7 +1152,7 @@ void SIM_MODEL::MigrateSimModel( T_symbol& aSymbol )
else
{
spiceModel = getSIValue( valueField );
valueField->SetText( wxT( "${SIM.PARAMS}" ) );
modelFromValueField = true;
}
if( T_field* netlistEnabledField = aSymbol.FindField( wxT( "Spice_Netlist_Enabled" ) ) )
@ -1149,12 +1171,13 @@ void SIM_MODEL::MigrateSimModel( T_symbol& aSymbol )
{
spiceLib = libFileField->GetText();
aSymbol.RemoveField( libFileField );
modelFromLib = true;
}
}
else if( prefix == wxT( "V" ) || prefix == wxT( "I" ) )
{
spiceModel = getSIValue( valueField );
valueField->SetText( wxT( "${SIM.PARAMS}" ) );
modelFromValueField = true;
}
else
{
@ -1205,60 +1228,87 @@ void SIM_MODEL::MigrateSimModel( T_symbol& aSymbol )
legacyPins->SetText( pins );
}
if( T_field* legacyPins = aSymbol.FindField( wxT( "Sim_Params" ) ) )
if( T_field* legacyParams = aSymbol.FindField( wxT( "Sim_Params" ) ) )
{
legacyPins->SetName( SIM_MODEL::PARAMS_FIELD );
legacyParams->SetName( SIM_MODEL::PARAMS_FIELD );
}
return;
}
// Insert a plaintext model as a substitute.
T_field deviceTypeField( &aSymbol, -1, SIM_MODEL::DEVICE_TYPE_FIELD );
deviceTypeField.SetText( SIM_MODEL::DeviceInfo( SIM_MODEL::DEVICE_T::SPICE ).fieldValue );
aSymbol.AddField( deviceTypeField );
if( modelFromLib )
{
SIM_LIB_MGR libMgr( aProject );
T_field paramsField( &aSymbol, -1, SIM_MODEL::PARAMS_FIELD );
try
{
std::vector<T_field> emptyFields;
SIM_LIBRARY::MODEL model = libMgr.CreateModel( spiceLib, spiceModel.ToStdString(),
emptyFields, aSymbol.GetPinCount() );
if( spiceType.IsEmpty() && spiceLib.IsEmpty() )
{
paramsField.SetText( spiceModel );
spiceParams = wxString( model.model.GetBaseModel()->Serde().GenerateParams() );
}
catch( ... )
{
// Fall back to raw spice model
modelFromLib = false;
}
}
else
if( modelFromLib )
{
paramsField.SetText( wxString::Format( "type=\"%s\" model=\"%s\" lib=\"%s\"",
spiceType, spiceModel, spiceLib ) );
}
T_field libraryField( &aSymbol, -1, SIM_MODEL::LIBRARY_FIELD );
libraryField.SetText( spiceLib );
aSymbol.AddField( libraryField );
aSymbol.AddField( paramsField );
T_field nameField( &aSymbol, -1, SIM_MODEL::NAME_FIELD );
nameField.SetText( spiceModel );
aSymbol.AddField( nameField );
// Legacy models by default get linear pin mapping.
if( pinMap != "" )
{
T_field pinsField( &aSymbol, -1, SIM_MODEL::PINS_FIELD );
T_field paramsField( &aSymbol, -1, SIM_MODEL::PARAMS_FIELD );
paramsField.SetText( spiceParams );
aSymbol.AddField( paramsField );
pinsField.SetText( pinMap );
aSymbol.AddField( pinsField );
if( modelFromValueField )
valueField->SetText( wxT( "${SIM.NAME}" ) );
}
else
{
wxString pins;
// Insert a raw spice model as a substitute.
for( unsigned ii = 0; ii < aSymbol.GetPinCount(); ++ii )
if( spiceType.IsEmpty() && spiceLib.IsEmpty() )
{
if( ii > 0 )
pins.Append( wxS( " " ) );
pins.Append( wxString::Format( wxT( "%u=%u" ), ii + 1, ii + 1 ) );
spiceParams = spiceModel;
}
else
{
spiceParams.Printf( wxT( "type=\"%s\" model=\"%s\" lib=\"%s\"" ),
spiceType, spiceModel, spiceLib );
}
T_field pinsField( &aSymbol, aSymbol.GetFieldCount(), SIM_MODEL::PINS_FIELD );
pinsField.SetText( pins );
T_field deviceTypeField( &aSymbol, -1, SIM_MODEL::DEVICE_TYPE_FIELD );
deviceTypeField.SetText( SIM_MODEL::DeviceInfo( SIM_MODEL::DEVICE_T::SPICE ).fieldValue );
aSymbol.AddField( deviceTypeField );
T_field paramsField( &aSymbol, -1, SIM_MODEL::PARAMS_FIELD );
paramsField.SetText( spiceParams );
aSymbol.AddField( paramsField );
if( modelFromValueField )
valueField->SetText( wxT( "${SIM.PARAMS}" ) );
}
if( !pinMap.IsEmpty() )
{
T_field pinsField( &aSymbol, -1, SIM_MODEL::PINS_FIELD );
pinsField.SetText( pinMap );
aSymbol.AddField( pinsField );
}
}
template void SIM_MODEL::MigrateSimModel<SCH_SYMBOL, SCH_FIELD>( SCH_SYMBOL& aSymbol );
template void SIM_MODEL::MigrateSimModel<LIB_SYMBOL, LIB_FIELD>( LIB_SYMBOL& aSymbol );
template void SIM_MODEL::MigrateSimModel<SCH_SYMBOL, SCH_FIELD>( SCH_SYMBOL& aSymbol,
const PROJECT* aProject );
template void SIM_MODEL::MigrateSimModel<LIB_SYMBOL, LIB_FIELD>( LIB_SYMBOL& aSymbol,
const PROJECT* aProject );

7
eeschema/sim/sim_model.h

@ -41,6 +41,7 @@
class SIM_LIBRARY;
class SPICE_GENERATOR;
class SIM_SERDE;
class PROJECT;
class SIM_MODEL
@ -60,6 +61,8 @@ public:
static constexpr auto PINS_FIELD = "Sim.Pins";
static constexpr auto PARAMS_FIELD = "Sim.Params";
static constexpr auto ENABLE_FIELD = "Sim.Enable";
static constexpr auto LIBRARY_FIELD = "Sim.Library";
static constexpr auto NAME_FIELD = "Sim.Name";
// There's a trailing '_' because `DEVICE_TYPE` collides with something in Windows headers.
@ -490,7 +493,7 @@ public:
std::vector<std::reference_wrapper<const PARAM>> GetParams() const;
const PARAM& GetUnderlyingParam( unsigned aParamIndex ) const; // Return the actual parameter.
const PARAM& GetParamOverride( unsigned aParamIndex ) const; // Return the actual parameter.
const PARAM& GetBaseParam( unsigned aParamIndex ) const; // Always return base parameter if it exists.
@ -527,7 +530,7 @@ public:
SIM_VALUE_GRAMMAR::NOTATION aNotation );
template <class T_symbol, class T_field>
static void MigrateSimModel( T_symbol& aSymbol );
static void MigrateSimModel( T_symbol& aSymbol, const PROJECT* aProject );
protected:
static std::unique_ptr<SIM_MODEL> Create( TYPE aType );

2
eeschema/sim/sim_model_kibis.cpp

@ -68,7 +68,7 @@ std::string SPICE_GENERATOR_KIBIS::IbisDevice( const SPICE_ITEM& aItem, const PR
std::string ibisModelName = SIM_MODEL::GetFieldValue( &aItem.fields, SIM_LIBRARY_KIBIS::MODEL_FIELD );
bool diffMode = SIM_MODEL::GetFieldValue( &aItem.fields, SIM_LIBRARY_KIBIS::DIFF_FIELD ) == "1";
wxString path = SIM_LIB_MGR::ResolveLibraryPath( ibisLibFilename, aProject );
wxString path = SIM_LIB_MGR::ResolveLibraryPath( ibisLibFilename, &aProject );
KIBIS kibis( std::string( path.c_str() ) );
kibis.m_cacheDir = std::string( aCacheDir.c_str() );

2
eeschema/sim/sim_plot_frame.cpp

@ -607,7 +607,7 @@ void SIM_PLOT_FRAME::UpdateTunerValue( SCH_SYMBOL* aSymbol, const wxString& aVal
{
if( item == aSymbol )
{
SIM_LIB_MGR mgr( Prj() );
SIM_LIB_MGR mgr( &Prj() );
SIM_MODEL& model = mgr.CreateModel( &m_schematicFrame->GetCurrentSheet(),
*aSymbol ).model;

4
eeschema/sim/sim_serde.cpp

@ -66,7 +66,7 @@ std::string SIM_SERDE::GenerateType() const
std::string SIM_SERDE::GenerateValue() const
{
const SIM_MODEL::PARAM& param = m_model.GetUnderlyingParam( 0 );
const SIM_MODEL::PARAM& param = m_model.GetParamOverride( 0 );
std::string result = param.value->ToString();
if( result == "" )
@ -86,7 +86,7 @@ std::string SIM_SERDE::GenerateParams() const
if( i == 0 && m_model.IsStoredInValue() )
continue;
const SIM_MODEL::PARAM& param = m_model.GetUnderlyingParam( i );
const SIM_MODEL::PARAM& param = m_model.GetParamOverride( i );
if( param.value->ToString() == ""
&& !( i == 0 && m_model.HasPrimaryValue() && !m_model.IsStoredInValue() ) )

2
eeschema/symbol_lib_table.cpp

@ -406,7 +406,7 @@ LIB_SYMBOL* SYMBOL_LIB_TABLE::LoadSymbol( const wxString& aNickname, const wxStr
id.SetLibNickname( row->GetNickName() );
symbol->SetLibId( id );
SIM_MODEL::MigrateSimModel<LIB_SYMBOL, LIB_FIELD>( *symbol );
SIM_MODEL::MigrateSimModel<LIB_SYMBOL, LIB_FIELD>( *symbol, nullptr );
}
return symbol;

2
eeschema/symbol_library.cpp

@ -169,7 +169,7 @@ LIB_SYMBOL* SYMBOL_LIB::FindSymbol( const wxString& aName ) const
if( !symbol->GetLib() )
symbol->SetLib( const_cast<SYMBOL_LIB*>( this ) );
SIM_MODEL::MigrateSimModel<LIB_SYMBOL, LIB_FIELD>( *symbol );
SIM_MODEL::MigrateSimModel<LIB_SYMBOL, LIB_FIELD>( *symbol, nullptr );
}
return symbol;

2
eeschema/tools/sch_editor_control.cpp

@ -876,7 +876,7 @@ int SCH_EDITOR_CONTROL::SimProbe( const TOOL_EVENT& aEvent )
SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item->GetParent() );
std::vector<LIB_PIN*> pins = symbol->GetLibPins();
SIM_LIB_MGR mgr( m_frame->Prj() );
SIM_LIB_MGR mgr( &m_frame->Prj() );
SIM_MODEL& model = mgr.CreateModel( &sheet, *symbol ).model;
SPICE_ITEM spiceItem;

2
qa/unittests/eeschema/sim/test_library_spice.cpp

@ -79,7 +79,7 @@ public:
{
BOOST_TEST_CONTEXT( "Param name: " << aModel.GetParam( i ).info.name )
{
BOOST_CHECK_EQUAL( aModel.GetUnderlyingParam( i ).value->ToString(), "" );
BOOST_CHECK_EQUAL( aModel.GetParamOverride( i ).value->ToString(), "" );
}
}
}

Loading…
Cancel
Save