Manual cherry-pick of much of 6d296038f3

This commit is contained in:
Jeff Young 2023-03-17 14:12:58 +00:00
parent c41b1e2f06
commit 70e86434ef
7 changed files with 89 additions and 111 deletions

View File

@ -136,6 +136,9 @@ bool DIALOG_SIM_MODEL<T_symbol, T_field>::TransferDataToWindow()
wxString pinMap;
bool storeInValue = false;
wxString msg;
WX_STRING_REPORTER reporter( &msg );
// Infer RLC and VI models if they aren't specified
if( SIM_MODEL::InferSimModel( m_symbol, &m_fields, false, SIM_VALUE_GRAMMAR::NOTATION::SI,
&deviceType, &modelType, &modelParams, &pinMap ) )
@ -180,7 +183,7 @@ bool DIALOG_SIM_MODEL<T_symbol, T_field>::TransferDataToWindow()
if( !loadLibrary( libraryFilename ) )
{
m_libraryPathText->ChangeValue( libraryFilename );
m_curModelType = SIM_MODEL::ReadTypeFromFields( m_fields );
m_curModelType = SIM_MODEL::ReadTypeFromFields( m_fields, &reporter );
m_libraryModelsMgr.CreateModel( nullptr, sourcePins, m_fields );
m_modelNameChoice->Append( _( "<unknown>" ) );
@ -256,26 +259,33 @@ bool DIALOG_SIM_MODEL<T_symbol, T_field>::TransferDataToWindow()
{
// The model is sourced from the instance.
m_useInstanceModelRadioButton->SetValue( true );
m_curModelType = SIM_MODEL::ReadTypeFromFields( m_fields );
}
for( SIM_MODEL::TYPE type : SIM_MODEL::TYPE_ITERATOR() )
{
wxString msg;
WX_STRING_REPORTER reporter( &msg );
msg.clear();
m_curModelType = SIM_MODEL::ReadTypeFromFields( m_fields, &reporter );
if( reporter.HasMessage() )
DisplayErrorMessage( this, msg );
}
m_builtinModelsMgr.SetReporter( &reporter );
for( SIM_MODEL::TYPE type : SIM_MODEL::TYPE_ITERATOR() )
{
if( m_useInstanceModelRadioButton->GetValue() && type == m_curModelType )
{
msg.clear();
m_builtinModelsMgr.CreateModel( m_fields, sourcePins, false );
else
m_builtinModelsMgr.CreateModel( type, sourcePins );
if( reporter.HasMessage() )
{
DisplayErrorMessage( this, _( "Failed to read simulation model from fields." )
+ wxT( "\n\n" ) + msg );
}
}
else
{
m_builtinModelsMgr.CreateModel( type, sourcePins );
}
SIM_MODEL::DEVICE_T deviceTypeT = SIM_MODEL::TypeInfo( type ).deviceType;
@ -698,7 +708,7 @@ bool DIALOG_SIM_MODEL<T_symbol, T_field>::loadLibrary( const wxString& aLibraryP
std::string modelName = SIM_MODEL::GetFieldValue( &m_fields, SIM_LIBRARY::NAME_FIELD );
for( auto& [baseModelName, baseModel] : library()->GetModels() )
for( const auto& [baseModelName, baseModel] : library()->GetModels() )
{
if( baseModelName == modelName )
m_libraryModelsMgr.CreateModel( &baseModel, sourcePins, m_fields );
@ -714,7 +724,7 @@ bool DIALOG_SIM_MODEL<T_symbol, T_field>::loadLibrary( const wxString& aLibraryP
wxArrayString modelNames;
for( auto& [name, model] : library()->GetModels() )
for( const auto& [name, model] : library()->GetModels() )
modelNames.Add( name );
m_modelNameChoice->Clear();
@ -1407,22 +1417,16 @@ void DIALOG_SIM_MODEL<T_symbol, T_field>::adjustParamGridColumns( int aWidth, bo
for( size_t ii = 0; ii < grid->GetColumnCount(); ii++ )
{
if( ii == 0 )
if( ii == PARAM_COLUMN::DESCRIPTION )
colWidths.push_back( grid->GetState()->GetColumnWidth( ii ) + margin + indent );
else if( ii == 1 )
colWidths.push_back( grid->GetState()->GetColumnWidth( ii ) + margin );
else if( ii == PARAM_COLUMN::VALUE )
colWidths.push_back( std::max( 72, grid->GetState()->GetColumnWidth( ii ) ) + margin );
else
colWidths.push_back( 50 );
colWidths.push_back( 60 + margin );
aWidth -= colWidths[ ii ];
}
// Account for scroll bars
aWidth -= ( grid->GetSize().x - grid->GetClientSize().x );
if( aWidth > 0 )
colWidths[ PARAM_COLUMN::VALUE ] += aWidth;
for( size_t ii = 0; ii < grid->GetColumnCount(); ii++ )
grid->SetColumnProportion( ii, colWidths[ ii ] );

View File

@ -83,20 +83,13 @@ namespace NETLIST_EXPORTER_SPICE_PARSER
std::string NAME_GENERATOR::Generate( const std::string& aProposedName )
{
if( !m_names.count( aProposedName ) )
return aProposedName;
std::string name = aProposedName;
int ii = 1;
for( uint64_t i = 1; i < UINT64_MAX; ++i )
{
std::string name = fmt::format( "{}#{}", aProposedName, i );
while( m_names.count( name ) )
name = fmt::format( "{}#{}", aProposedName, ii++ );
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 ) );
}
@ -126,8 +119,7 @@ bool NETLIST_EXPORTER_SPICE::DoWriteNetlist( OUTPUTFORMATTER& aFormatter, unsign
// Cleanup list to avoid duplicate if the netlist exporter is run more than once.
m_rawIncludes.clear();
if( !ReadSchematicAndLibraries( aNetlistOptions, aReporter ) )
return false;
bool result = ReadSchematicAndLibraries( aNetlistOptions, aReporter );
WriteHead( aFormatter, aNetlistOptions );
@ -142,7 +134,7 @@ bool NETLIST_EXPORTER_SPICE::DoWriteNetlist( OUTPUTFORMATTER& aFormatter, unsign
WriteTail( aFormatter, aNetlistOptions );
return true;
return result;
}
@ -165,6 +157,8 @@ bool NETLIST_EXPORTER_SPICE::ReadSchematicAndLibraries( unsigned aNetlistOptions
std::set<std::string> refNames; // Set of reference names to check for duplication.
int ncCounter = 1;
m_libMgr.SetReporter( &aReporter );
ReadDirectives( aNetlistOptions );
m_nets.clear();
@ -240,31 +234,6 @@ bool NETLIST_EXPORTER_SPICE::ReadSchematicAndLibraries( unsigned aNetlistOptions
wxString modelParams;
wxString pinMap;
// JEY TODO: readModel() below will also do the inference, so I don't think this
// accomplishes anything....
// Infer RLC and VI models if they aren't specified
if( SIM_MODEL::InferSimModel( *symbol, &spiceItem.fields, true,
SIM_VALUE_GRAMMAR::NOTATION::SPICE, &deviceType,
&modelType, &modelParams, &pinMap ) )
{
spiceItem.fields.emplace_back( symbol, -1, SIM_DEVICE_TYPE_FIELD );
spiceItem.fields.back().SetText( deviceType );
if( !modelType.IsEmpty() )
{
spiceItem.fields.emplace_back( symbol, -1, SIM_TYPE_FIELD );
spiceItem.fields.back().SetText( modelType );
}
spiceItem.fields.emplace_back( symbol, -1, SIM_PARAMS_FIELD );
spiceItem.fields.back().SetText( modelParams );
spiceItem.fields.emplace_back( symbol, -1, SIM_PINS_FIELD );
spiceItem.fields.back().SetText( pinMap );
}
try
{
readRefName( sheet, *symbol, spiceItem, refNames );
readModel( sheet, *symbol, spiceItem );
readPinNumbers( *symbol, spiceItem, pins );
@ -274,16 +243,10 @@ bool NETLIST_EXPORTER_SPICE::ReadSchematicAndLibraries( unsigned aNetlistOptions
m_items.push_back( std::move( spiceItem ) );
}
catch( const IO_ERROR& e )
{
msg.Printf( _( "Error reading simulation model from symbol '%s':\n%s" ),
symbol->GetRef( &sheet ),
e.Problem() );
aReporter.Report( msg, RPT_SEVERITY_ERROR );
}
}
}
m_libMgr.SetReporter( nullptr );
return !aReporter.HasMessage();
}
@ -595,7 +558,7 @@ void NETLIST_EXPORTER_SPICE::writeInclude( OUTPUTFORMATTER& aFormatter, unsigned
void NETLIST_EXPORTER_SPICE::writeIncludes( OUTPUTFORMATTER& aFormatter, unsigned aNetlistOptions )
{
for( auto& [path, library] : m_libMgr.GetLibraries() )
for( const auto& [path, library] : m_libMgr.GetLibraries() )
{
if( dynamic_cast<const SIM_LIBRARY_SPICE*>( &library.get() ) )
writeInclude( aFormatter, aNetlistOptions, path );

View File

@ -49,7 +49,7 @@ void SIM_LIBRARY_KIBIS::ReadFile( const std::string& aFilePath, REPORTER* aRepor
for( KIBIS_COMPONENT& kcomp : m_kibis.m_components )
{
m_models.push_back( SIM_MODEL::Create( SIM_MODEL::TYPE::KIBIS_DEVICE, pins, nullptr ) );
m_models.push_back( SIM_MODEL::Create( SIM_MODEL::TYPE::KIBIS_DEVICE, pins, aReporter ) );
m_modelNames.emplace_back( kcomp.m_name );
SIM_MODEL_KIBIS* libcomp = dynamic_cast<SIM_MODEL_KIBIS*>( m_models.back().get() );

View File

@ -361,11 +361,13 @@ SIM_MODEL::SPICE_INFO SIM_MODEL::SpiceInfo( TYPE aType )
}
template TYPE SIM_MODEL::ReadTypeFromFields( const std::vector<SCH_FIELD>& aFields );
template TYPE SIM_MODEL::ReadTypeFromFields( const std::vector<LIB_FIELD>& aFields );
template TYPE SIM_MODEL::ReadTypeFromFields( const std::vector<SCH_FIELD>& aFields,
REPORTER* aReporter );
template TYPE SIM_MODEL::ReadTypeFromFields( const std::vector<LIB_FIELD>& aFields,
REPORTER* aReporter );
template <typename T>
TYPE SIM_MODEL::ReadTypeFromFields( const std::vector<T>& aFields )
TYPE SIM_MODEL::ReadTypeFromFields( const std::vector<T>& aFields, REPORTER* aReporter )
{
std::string deviceTypeFieldValue = GetFieldValue( &aFields, SIM_DEVICE_TYPE_FIELD );
std::string typeFieldValue = GetFieldValue( &aFields, SIM_TYPE_FIELD );
@ -392,6 +394,17 @@ TYPE SIM_MODEL::ReadTypeFromFields( const std::vector<T>& aFields )
if( typeFromLegacyFields != TYPE::NONE )
return typeFromLegacyFields;
if( aReporter )
{
if( aFields.size() > REFERENCE_FIELD )
{
aReporter->Report( wxString::Format( _( "Error reading simulation model from symbol '%s':\n%s" ),
aFields[REFERENCE_FIELD].GetText(),
_( "Failed to read simulation model from fields." ) ),
RPT_SEVERITY_ERROR );
}
}
return TYPE::NONE;
}
@ -506,7 +519,7 @@ std::unique_ptr<SIM_MODEL> SIM_MODEL::Create( const SIM_MODEL* aBaseModel,
const std::vector<T>& aFields,
REPORTER* aReporter )
{
TYPE type = ReadTypeFromFields( aFields );
TYPE type = ReadTypeFromFields( aFields, aReporter );
// If the model has a specified type, it takes priority over the type of its base class.
if( type == TYPE::NONE && aBaseModel )
@ -533,9 +546,13 @@ std::unique_ptr<SIM_MODEL> SIM_MODEL::Create( const SIM_MODEL* aBaseModel,
catch( IO_ERROR& err )
{
if( aReporter )
aReporter->Report( err.What(), RPT_SEVERITY_ERROR );
else
DisplayErrorMessage( nullptr, err.What() );
{
aReporter->Report( wxString::Format( _( "Error reading simulation model from "
"symbol '%s':\n%s" ),
aFields[REFERENCE_FIELD].GetText(),
err.Problem() ),
RPT_SEVERITY_ERROR );
}
}
return model;
@ -557,7 +574,7 @@ std::unique_ptr<SIM_MODEL> SIM_MODEL::Create( const std::vector<T>& aFields,
const std::vector<LIB_PIN*>& aPins,
bool aResolved, REPORTER* aReporter )
{
TYPE type = ReadTypeFromFields( aFields );
TYPE type = ReadTypeFromFields( aFields, aReporter );
std::unique_ptr<SIM_MODEL> model = SIM_MODEL::Create( type );
try
@ -589,11 +606,15 @@ std::unique_ptr<SIM_MODEL> SIM_MODEL::Create( const std::vector<T>& aFields,
}
catch( const IO_ERROR& err )
{
// We own the pin syntax, so if we can't parse it then there's an error, full stop.
// We own the pin syntax, so if we can't parse it then there's an error.
if( aReporter )
aReporter->Report( err.Problem(), RPT_SEVERITY_ERROR );
else
THROW_IO_ERROR( err.Problem() );
{
aReporter->Report( wxString::Format( _( "Error reading simulation model from "
"symbol '%s':\n%s" ),
aFields[REFERENCE_FIELD].GetText(),
err.Problem() ),
RPT_SEVERITY_ERROR );
}
}
}
@ -726,21 +747,8 @@ void SIM_MODEL::AddParam( const PARAM::INFO& aInfo )
void SIM_MODEL::SetBaseModel( const SIM_MODEL& aBaseModel )
{
auto describe =
[]( const SIM_MODEL* aModel )
{
return fmt::format( "{} ({})",
aModel->GetDeviceInfo().fieldValue,
aModel->GetTypeInfo().description );
};
if( GetType() != aBaseModel.GetType() )
{
THROW_IO_ERROR( wxString::Format( _( "Simulation model type must be the same as of its "
"base class: '%s', but is '%s'" ),
describe( &aBaseModel ),
describe( this ) ) );
}
wxASSERT_MSG( GetType() == aBaseModel.GetType(),
wxS( "Simulation model type must be the same as its base class!" ) );
m_baseModel = &aBaseModel;
}

View File

@ -384,7 +384,7 @@ public:
template <typename T>
static TYPE ReadTypeFromFields( const std::vector<T>& aFields );
static TYPE ReadTypeFromFields( const std::vector<T>& aFields, REPORTER* aReporter );
template <typename T>
static TYPE InferTypeFromLegacyFields( const std::vector<T>& aFields );

View File

@ -55,7 +55,6 @@ std::vector<std::string> SPICE_GENERATOR_NGSPICE::CurrentNames( const SPICE_ITEM
return SPICE_GENERATOR::CurrentNames( aItem );
default:
wxFAIL_MSG( "Unhandled model device type in SIM_MODEL_NGSPICE" );
return {};
}
}

View File

@ -95,6 +95,10 @@ std::string SPICE_GENERATOR::ModelLine( const SPICE_ITEM& aItem ) const
value ) );
}
// Don't send SPICE empty models.
if( result.length() == indentLength + 1 /* line ending */ )
result.clear();
return result;
}