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
This commit is contained in:
Jeff Young 2022-12-17 15:21:35 +00:00
parent 1047e7143a
commit 6b70c679cf
9 changed files with 306 additions and 178 deletions

View File

@ -240,14 +240,22 @@ bool DIALOG_SIM_MODEL<T_symbol, T_field>::TransferDataToWindow()
m_curModelType = SIM_MODEL::ReadTypeFromFields( m_fields );
}
std::vector<LIB_PIN*> 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<T_symbol, T_field>::loadLibrary( const wxString& aLibraryP
return;
}
std::vector<LIB_PIN*> 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<T_symbol, T_field>::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 )

View File

@ -24,6 +24,7 @@
#include <pgm_base.h>
#include <string>
#include <string_utils.h>
#include <common.h>
#include <functional>
#include <sch_symbol.h>
@ -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<LIB_PIN*>& 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<LIB_PIN*>& aPins )
{
m_models.push_back( SIM_MODEL::Create( aBaseModel, aSymbolPinCount ) );
m_models.push_back( SIM_MODEL::Create( aBaseModel, aPins ) );
return *m_models.back();
}
template <typename T>
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<LIB_PIN*>& aPins,
const std::vector<T>& 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<LIB_PIN*>& aPins,
const std::vector<SCH_FIELD>& 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<LIB_PIN*>& aPins,
const std::vector<LIB_FIELD>& aFields );
@ -220,37 +225,47 @@ SIM_LIBRARY::MODEL SIM_LIB_MGR::CreateModel( const SCH_SHEET_PATH* aSheetPath, S
}
}
return CreateModel( fields, static_cast<int>( aSymbol.GetRawPins().size() ) );
std::vector<LIB_PIN*> 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 <typename T>
SIM_LIBRARY::MODEL SIM_LIB_MGR::CreateModel( const std::vector<T>& aFields, int aSymbolPinCount )
SIM_LIBRARY::MODEL SIM_LIB_MGR::CreateModel( const std::vector<T>& aFields,
const std::vector<LIB_PIN*>& 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<SCH_FIELD>& aFields,
int aSymbolPinCount );
const std::vector<LIB_PIN*>& aPins );
template SIM_LIBRARY::MODEL SIM_LIB_MGR::CreateModel( const std::vector<LIB_FIELD>& aFields,
int aSymbolPinCount );
const std::vector<LIB_PIN*>& aPins );
template <typename T>
SIM_LIBRARY::MODEL SIM_LIB_MGR::CreateModel( const wxString& aLibraryPath,
const std::string& aBaseModelName,
const std::vector<T>& aFields,
int aSymbolPinCount )
const std::vector<LIB_PIN*>& 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() };
}

View File

@ -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<LIB_PIN*>& aPins );
SIM_MODEL& CreateModel( const SIM_MODEL& aBaseModel, int aSymbolPinCount );
SIM_MODEL& CreateModel( const SIM_MODEL& aBaseModel, const std::vector<LIB_PIN*>& aPins );
template <typename T>
SIM_MODEL& CreateModel( const SIM_MODEL& aBaseModel, int aSymbolPinCount,
SIM_MODEL& CreateModel( const SIM_MODEL& aBaseModel, const std::vector<LIB_PIN*>& aPins,
const std::vector<T>& aFields );
// TODO: The argument can be made const.
SIM_LIBRARY::MODEL CreateModel( const SCH_SHEET_PATH* aSheetPath, SCH_SYMBOL& aSymbol );
template <typename T>
SIM_LIBRARY::MODEL CreateModel( const std::vector<T>& aFields, int aSymbolPinCount );
SIM_LIBRARY::MODEL CreateModel( const std::vector<T>& aFields,
const std::vector<LIB_PIN*>& aPins );
template <typename T>
SIM_LIBRARY::MODEL CreateModel( const wxString& aLibraryPath, const std::string& aBaseModelName,
const std::vector<T>& aFields, int aSymbolPinCount );
SIM_LIBRARY::MODEL CreateModel( const wxString& aLibraryPath,
const std::string& aBaseModelName,
const std::vector<T>& aFields,
const std::vector<LIB_PIN*>& aPins );
void SetModel( int aIndex, std::unique_ptr<SIM_MODEL> aModel );

View File

@ -28,6 +28,7 @@
#include <locale_io.h>
#include <pegtl.hpp>
#include <pegtl/contrib/parse_tree.hpp>
#include <lib_pin.h>
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<LIB_PIN*> 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<SIM_MODEL_KIBIS*>( m_models.back().get() );

View File

@ -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<T>& aFields )
}
template <typename T>
void SIM_MODEL::ReadDataFields( unsigned aSymbolPinCount, const std::vector<T>* aFields )
{
doReadDataFields( aSymbolPinCount, aFields );
}
template <>
void SIM_MODEL::ReadDataFields( unsigned aSymbolPinCount, const std::vector<SCH_FIELD>* aFields )
{
ReadDataSchFields( aSymbolPinCount, aFields );
doReadDataFields( aSymbolPinCount, aFields );
}
template <>
void SIM_MODEL::ReadDataFields( unsigned aSymbolPinCount, const std::vector<LIB_FIELD>* aFields )
{
ReadDataLibFields( aSymbolPinCount, aFields );
}
void SIM_MODEL::ReadDataSchFields( unsigned aSymbolPinCount, const std::vector<SCH_FIELD>* aFields )
{
doReadDataFields( aSymbolPinCount, aFields );
}
void SIM_MODEL::ReadDataLibFields( unsigned aSymbolPinCount, const std::vector<LIB_FIELD>* aFields )
template <>
void SIM_MODEL::ReadDataFields( const std::vector<SCH_FIELD>* aFields,
const std::vector<LIB_PIN*>& aPins )
{
doReadDataFields( aSymbolPinCount, aFields );
doReadDataFields( aFields, aPins );
}
template <typename T>
void SIM_MODEL::WriteFields( std::vector<T>& aFields ) const
template <>
void SIM_MODEL::ReadDataFields( const std::vector<LIB_FIELD>* aFields,
const std::vector<LIB_PIN*>& aPins )
{
doWriteFields( aFields );
doReadDataFields( aFields, aPins );
}
template <>
void SIM_MODEL::WriteFields( std::vector<SCH_FIELD>& aFields ) const
{
WriteDataSchFields( aFields );
doWriteFields( aFields );
}
template <>
void SIM_MODEL::WriteFields( std::vector<LIB_FIELD>& aFields ) const
{
WriteDataLibFields( aFields );
}
void SIM_MODEL::WriteDataSchFields( std::vector<SCH_FIELD>& aFields ) const
{
doWriteFields( aFields );
}
void SIM_MODEL::WriteDataLibFields( std::vector<LIB_FIELD>& aFields ) const
{
doWriteFields( aFields );
}
std::unique_ptr<SIM_MODEL> SIM_MODEL::Create( TYPE aType, unsigned aSymbolPinCount )
std::unique_ptr<SIM_MODEL> SIM_MODEL::Create( TYPE aType, const std::vector<LIB_PIN*>& aPins )
{
std::unique_ptr<SIM_MODEL> model = Create( aType );
// Passing nullptr to ReadDataFields will make it act as if all fields were empty.
model->ReadDataFields( aSymbolPinCount, static_cast<const std::vector<void>*>( nullptr ) );
model->ReadDataFields( static_cast<const std::vector<SCH_FIELD>*>( nullptr ), aPins );
return model;
}
std::unique_ptr<SIM_MODEL> SIM_MODEL::Create( const SIM_MODEL& aBaseModel, unsigned aSymbolPinCount )
std::unique_ptr<SIM_MODEL> SIM_MODEL::Create( const SIM_MODEL& aBaseModel,
const std::vector<LIB_PIN*>& aPins)
{
std::unique_ptr<SIM_MODEL> model = Create( aBaseModel.GetType() );
@ -501,13 +480,14 @@ std::unique_ptr<SIM_MODEL> SIM_MODEL::Create( const SIM_MODEL& aBaseModel, unsig
DisplayErrorMessage( nullptr, err.What() );
}
model->ReadDataFields( aSymbolPinCount, static_cast<const std::vector<void>*>( nullptr ) );
model->ReadDataFields( static_cast<const std::vector<SCH_FIELD>*>( nullptr ), aPins );
return model;
}
template <typename T>
std::unique_ptr<SIM_MODEL> SIM_MODEL::Create( const SIM_MODEL& aBaseModel, unsigned aSymbolPinCount,
std::unique_ptr<SIM_MODEL> SIM_MODEL::Create( const SIM_MODEL& aBaseModel,
const std::vector<LIB_PIN*>& aPins,
const std::vector<T>& aFields )
{
TYPE type = ReadTypeFromFields( aFields );
@ -526,34 +506,35 @@ std::unique_ptr<SIM_MODEL> 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> SIM_MODEL::Create( const SIM_MODEL& aBaseModel,
unsigned aSymbolPinCount,
const std::vector<LIB_PIN*>& aPins,
const std::vector<SCH_FIELD>& aFields );
template std::unique_ptr<SIM_MODEL> SIM_MODEL::Create( const SIM_MODEL& aBaseModel,
unsigned aSymbolPinCount,
const std::vector<LIB_PIN*>& aPins,
const std::vector<LIB_FIELD>& aFields );
template <typename T>
std::unique_ptr<SIM_MODEL> SIM_MODEL::Create( unsigned aSymbolPinCount,
const std::vector<T>& aFields )
std::unique_ptr<SIM_MODEL> SIM_MODEL::Create( const std::vector<T>& aFields,
const std::vector<LIB_PIN*>& aPins )
{
TYPE type = ReadTypeFromFields( aFields );
std::unique_ptr<SIM_MODEL> model = SIM_MODEL::Create( type );
model->ReadDataFields( aSymbolPinCount, &aFields );
model->ReadDataFields( &aFields, aPins );
return model;
}
template std::unique_ptr<SIM_MODEL> SIM_MODEL::Create( unsigned aSymbolPinCount,
const std::vector<SCH_FIELD>& aFields );
template std::unique_ptr<SIM_MODEL> SIM_MODEL::Create( unsigned aSymbolPinCount,
const std::vector<LIB_FIELD>& aFields );
template std::unique_ptr<SIM_MODEL> SIM_MODEL::Create( const std::vector<SCH_FIELD>& aFields,
const std::vector<LIB_PIN*>& aPins );
template std::unique_ptr<SIM_MODEL> SIM_MODEL::Create( const std::vector<LIB_FIELD>& aFields,
const std::vector<LIB_PIN*>& aPins );
template <typename T>
@ -619,12 +600,21 @@ void SIM_MODEL::SetFieldValue( std::vector<T>& aFields, const std::string& aFiel
aFields.emplace_back( wxPoint(), aFields.size(), parent, aFieldName );
}
else if constexpr( std::is_same<T, LIB_FIELD>::value )
{
aFields.emplace_back( aFields.size(), aFieldName );
}
aFields.back().SetText( aValue );
}
template void SIM_MODEL::SetFieldValue<SCH_FIELD>( std::vector<SCH_FIELD>& aFields,
const std::string& aFieldName,
const std::string& aValue );
template void SIM_MODEL::SetFieldValue<LIB_FIELD>( std::vector<LIB_FIELD>& 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<LIB_PIN*> 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 <typename T>
void SIM_MODEL::doReadDataFields( unsigned aSymbolPinCount, const std::vector<T>* 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<T>
}
template <typename T>
void SIM_MODEL::doReadDataFields( const std::vector<T>* aFields,
const std::vector<LIB_PIN*>& 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 <typename T>
void SIM_MODEL::doWriteFields( std::vector<T>& 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<LIB_PIN*> 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<LIB_PIN*> 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<T_field> 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( '(', &paramSet );
paramSet = paramSet.BeforeLast( ')' );
wxStringTokenizer tokenizer( paramSet, wxT( " " ), wxTOKEN_STRTOK );
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<SIM_MODEL> 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( modelFromLib )
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 );
if( spiceType.IsEmpty() && spiceLib.IsEmpty() )
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( 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<LIB_PIN*> 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 );
}

View File

@ -400,16 +400,19 @@ public:
static TYPE InferTypeFromLegacyFields( const std::vector<T>& aFields );
static std::unique_ptr<SIM_MODEL> Create( TYPE aType, unsigned aSymbolPinCount );
static std::unique_ptr<SIM_MODEL> Create( const SIM_MODEL& aBaseModel, unsigned aSymbolPinCount );
static std::unique_ptr<SIM_MODEL> Create( TYPE aType, const std::vector<LIB_PIN*>& aPins );
static std::unique_ptr<SIM_MODEL> Create( const SIM_MODEL& aBaseModel,
const std::vector<LIB_PIN*>& aPins );
template <typename T>
static std::unique_ptr<SIM_MODEL> Create( const SIM_MODEL& aBaseModel, unsigned aSymbolPinCount,
static std::unique_ptr<SIM_MODEL> Create( const SIM_MODEL& aBaseModel,
const std::vector<LIB_PIN*>& aPins,
const std::vector<T>& aFields );
template <typename T>
static std::unique_ptr<SIM_MODEL> Create( unsigned aSymbolPinCount,
const std::vector<T>& aFields );
static std::unique_ptr<SIM_MODEL> Create( const std::vector<T>& aFields,
const std::vector<LIB_PIN*>& aPins );
template <typename T>
static std::string GetFieldValue( const std::vector<T>* aFields, const std::string& aFieldName );
@ -433,18 +436,12 @@ public:
template <typename T>
void ReadDataFields( unsigned aSymbolPinCount, const std::vector<T>* aFields );
virtual void ReadDataSchFields( unsigned aSymbolPinCount,
const std::vector<SCH_FIELD>* aFields );
virtual void ReadDataLibFields( unsigned aSymbolPinCount,
const std::vector<LIB_FIELD>* aFields );
template <typename T>
void ReadDataFields( const std::vector<T>* aFields, const std::vector<LIB_PIN*>& aPins );
template <typename T>
void WriteFields( std::vector<T>& aFields ) const;
virtual void WriteDataSchFields( std::vector<SCH_FIELD>& aFields ) const;
virtual void WriteDataLibFields( std::vector<LIB_FIELD>& 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 <class T>
static bool InferPassiveSimModel( T& aSymbol, bool aResolve,
SIM_VALUE_GRAMMAR::NOTATION aNotation, wxString* aModelType,
@ -539,11 +538,15 @@ protected:
std::unique_ptr<SIM_SERDE> aSerde );
virtual void CreatePins( unsigned aSymbolPinCount );
virtual void CreatePins( const std::vector<LIB_PIN*> aSymbolPins );
private:
template <typename T>
void doReadDataFields( unsigned aSymbolPinCount, const std::vector<T>* aFields );
template <typename T>
void doReadDataFields( const std::vector<T>* aFields, const std::vector<LIB_PIN*>& aPins );
template <typename T>
void doWriteFields( std::vector<T>& aFields ) const;

View File

@ -499,20 +499,3 @@ std::vector<SIM_MODEL::PARAM::INFO> SIM_MODEL_KIBIS::makePrbsWaveformParamInfos(
return paramInfos;
}
void SIM_MODEL_KIBIS::ReadDataSchFields( unsigned aSymbolPinCount, const std::vector<SCH_FIELD>* 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<LIB_FIELD>* aFields )
{
bool diffMode = SIM_MODEL::GetFieldValue( aFields, SIM_LIBRARY_KIBIS::DIFF_FIELD ) == "1";
SwitchSingleEndedDiff( diffMode );
SIM_MODEL::ReadDataLibFields( aSymbolPinCount, aFields );
}

View File

@ -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<SCH_FIELD>* aFields ) override;
void ReadDataLibFields( unsigned aSymbolPinCount,
const std::vector<LIB_FIELD>* aFields ) override;
protected:
void CreatePins( unsigned aSymbolPinCount ) override;

View File

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