Sim: Override base model type if there's a Sim_Type field

This commit is contained in:
Mikolaj Wielgus 2022-10-09 20:44:03 +02:00
parent 79c301800a
commit 72402cf687
5 changed files with 144 additions and 119 deletions

View File

@ -326,7 +326,7 @@ void NETLIST_EXPORTER_SPICE::readModel( SCH_SHEET_PATH& aSheet, SCH_SYMBOL& aSym
aItem.modelName = ( modelName != "" ) ? modelName : ( "__" + aItem.refName );
aItem.model = &model;
// Special cases for raw Spice models and KIBIS.
// FIXME: Special cases for raw Spice models and KIBIS.
if( auto rawSpiceModel = dynamic_cast<const SIM_MODEL_RAW_SPICE*>( aItem.model ) )
{
int libParamIndex = static_cast<int>( SIM_MODEL_RAW_SPICE::SPICE_PARAM::LIB );
@ -356,7 +356,9 @@ void NETLIST_EXPORTER_SPICE::readModel( SCH_SHEET_PATH& aSheet, SCH_SYMBOL& aSym
libraryPath ) );
}
std::string modelData = kibisModel->GenerateSpiceDriver( aSymbol.GetFields() );
auto spiceGenerator = static_cast<const SPICE_GENERATOR_KIBIS&>( kibisModel->SpiceGenerator() );
std::string modelData = spiceGenerator.IbisDevice( aSymbol.GetFields() );
cacheFile.Write( wxString( modelData ) );
m_rawIncludes.insert( libraryPath );
}

View File

@ -644,7 +644,13 @@ template <typename T>
std::unique_ptr<SIM_MODEL> SIM_MODEL::Create( const SIM_MODEL& aBaseModel, unsigned aSymbolPinCount,
const std::vector<T>& aFields )
{
std::unique_ptr<SIM_MODEL> model = Create( aBaseModel.GetType() );
TYPE type = ReadTypeFromFields( aFields );
// If the model has a specified type, it takes priority over the type of its base class.
if( type == TYPE::NONE )
type = aBaseModel.GetType();
std::unique_ptr<SIM_MODEL> model = Create( type );
model->SetBaseModel( aBaseModel );
model->ReadDataFields( aSymbolPinCount, &aFields );

View File

@ -509,7 +509,18 @@ public:
TYPE GetType() const { return m_type; }
const SIM_MODEL* GetBaseModel() const { return m_baseModel; }
virtual void SetBaseModel( const SIM_MODEL& aBaseModel ) { m_baseModel = &aBaseModel; }
virtual void SetBaseModel( const SIM_MODEL& aBaseModel )
{
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'" ),
aBaseModel.GetTypeInfo().fieldValue,
GetTypeInfo().fieldValue ) );
}
m_baseModel = &aBaseModel;
}
int GetPinCount() const { return static_cast<int>( m_pins.size() ); }
const PIN& GetPin( unsigned aIndex ) const { return m_pins.at( aIndex ); }

View File

@ -50,6 +50,119 @@ std::vector<std::string> SPICE_GENERATOR_KIBIS::CurrentNames( const std::string&
return currentNames;
}
std::string SPICE_GENERATOR_KIBIS::IbisDevice( const std::vector<SCH_FIELD>& aFields ) const
{
std::string ibisLibFilename = SIM_MODEL::GetFieldValue( &aFields, SIM_LIBRARY::LIBRARY_FIELD );
std::string ibisCompName = SIM_MODEL::GetFieldValue( &aFields, SIM_LIBRARY::NAME_FIELD );
std::string ibisPinName = SIM_MODEL::GetFieldValue( &aFields, SIM_LIBRARY_KIBIS::PIN_FIELD );
std::string ibisModelName = SIM_MODEL::GetFieldValue( &aFields, SIM_LIBRARY_KIBIS::MODEL_FIELD );
KIBIS kibis( ibisLibFilename );
KIBIS_COMPONENT* kcomp = kibis.GetComponent( std::string( ibisCompName ) );
if( !kcomp )
THROW_IO_ERROR( wxString::Format( _( "Could not find IBIS component '%s'" ), ibisCompName ) );
KIBIS_PIN* kpin = kcomp->GetPin( ibisPinName );
if( !kpin )
{
THROW_IO_ERROR( wxString::Format( _( "Could not find IBIS pin '%s' in component '%s'" ),
ibisPinName,
ibisCompName ) );
}
if( !kpin->m_valid )
{
THROW_IO_ERROR( wxString::Format( _( "Invalid IBIS pin '%s' in component '%s'" ),
ibisPinName,
ibisCompName ) );
}
KIBIS_MODEL* kmodel = kibis.GetModel( ibisModelName );
if( !kmodel )
THROW_IO_ERROR( wxString::Format( _( "Could not find IBIS model '%s'" ), ibisModelName ) );
if( !kmodel->m_valid )
THROW_IO_ERROR( wxString::Format( _( "Invalid IBIS model '%s'" ), ibisModelName ) );
KIBIS_PARAMETER kparams;
kparams.SetCornerFromString( kparams.m_supply, m_model.FindParam( "vcc" )->value->ToString() );
kparams.SetCornerFromString( kparams.m_Rpin, m_model.FindParam( "rpin" )->value->ToString() );
kparams.SetCornerFromString( kparams.m_Lpin, m_model.FindParam( "lpin" )->value->ToString() );
kparams.SetCornerFromString( kparams.m_Cpin, m_model.FindParam( "cpin" )->value->ToString() );
//kparams.SetCornerFromString( kparams.m_Ccomp, FindParam( "ccomp" )->value->ToString() );
std::string result;
switch( m_model.GetType() )
{
case SIM_MODEL::TYPE::KIBIS_DEVICE:
kpin->writeSpiceDevice( &result, ibisModelName, *kmodel, kparams );
break;
case SIM_MODEL::TYPE::KIBIS_DRIVER_DC:
{
std::string paramValue = m_model.FindParam( "dc" )->value->ToString();
if( paramValue == "hi-Z" )
{
kparams.m_waveform =
static_cast<KIBIS_WAVEFORM*>( new KIBIS_WAVEFORM_HIGH_Z() );
}
else if( paramValue == "low" )
{
kparams.m_waveform =
static_cast<KIBIS_WAVEFORM*>( new KIBIS_WAVEFORM_STUCK_LOW() );
}
else if( paramValue == "high" )
{
kparams.m_waveform =
static_cast<KIBIS_WAVEFORM*>( new KIBIS_WAVEFORM_STUCK_HIGH() );
}
kpin->writeSpiceDriver( &result, ibisModelName, *kmodel, kparams );
break;
}
case SIM_MODEL::TYPE::KIBIS_DRIVER_RECT:
{
KIBIS_WAVEFORM_RECTANGULAR* waveform = new KIBIS_WAVEFORM_RECTANGULAR();
waveform->m_ton = static_cast<SIM_VALUE_FLOAT&>( *m_model.FindParam( "ton" )->value ).Get().value_or( 1 );
waveform->m_toff = static_cast<SIM_VALUE_FLOAT&>( *m_model.FindParam( "toff" )->value ).Get().value_or( 1 );
waveform->m_delay = static_cast<SIM_VALUE_FLOAT&>( *m_model.FindParam( "delay" )->value ).Get().value_or( 0 );
kparams.m_waveform = waveform;
kpin->writeSpiceDriver( &result, ibisModelName, *kmodel, kparams );
break;
}
case SIM_MODEL::TYPE::KIBIS_DRIVER_PRBS:
{
KIBIS_WAVEFORM_PRBS* waveform = new KIBIS_WAVEFORM_PRBS();
waveform->m_bitrate = static_cast<SIM_VALUE_FLOAT&>( *m_model.FindParam( "f0" )->value ).Get().value_or( 0 );
waveform->m_bits = static_cast<SIM_VALUE_FLOAT&>( *m_model.FindParam( "bits" )->value ).Get().value_or( 0 );
waveform->m_delay = static_cast<SIM_VALUE_FLOAT&>( *m_model.FindParam( "delay" )->value ).Get().value_or( 0 );
kparams.m_waveform = waveform;
kpin->writeSpiceDriver( &result, ibisModelName, *kmodel, kparams );
break;
}
default:
wxFAIL_MSG( "Unknown IBIS model type" );
return "";
}
return result;
}
SIM_MODEL_KIBIS::SIM_MODEL_KIBIS( TYPE aType ) :
SIM_MODEL( aType, std::make_unique<SPICE_GENERATOR_KIBIS>( *this ) )
{
@ -156,119 +269,11 @@ bool SIM_MODEL_KIBIS::ChangePin( SIM_LIBRARY_KIBIS& aLib, std::string aPinNumber
void SIM_MODEL_KIBIS::SetBaseModel( const SIM_MODEL& aBaseModel )
{
}
std::string SIM_MODEL_KIBIS::GenerateSpiceDriver( const std::vector<SCH_FIELD>& aFields ) const
{
std::string ibisLibFilename = SIM_MODEL::GetFieldValue( &aFields, SIM_LIBRARY::LIBRARY_FIELD );
std::string ibisCompName = SIM_MODEL::GetFieldValue( &aFields, SIM_LIBRARY::NAME_FIELD );
std::string ibisPinName = SIM_MODEL::GetFieldValue( &aFields, SIM_LIBRARY_KIBIS::PIN_FIELD );
std::string ibisModelName = SIM_MODEL::GetFieldValue( &aFields, SIM_LIBRARY_KIBIS::MODEL_FIELD );
KIBIS kibis( ibisLibFilename );
KIBIS_COMPONENT* kcomp = kibis.GetComponent( std::string( ibisCompName ) );
if( !kcomp )
THROW_IO_ERROR( wxString::Format( _( "Could not find IBIS component '%s'" ), ibisCompName ) );
KIBIS_PIN* kpin = kcomp->GetPin( ibisPinName );
if( !kpin )
{
THROW_IO_ERROR( wxString::Format( _( "Could not find IBIS pin '%s' in component '%s'" ),
ibisPinName,
ibisCompName ) );
}
if( !kpin->m_valid )
{
THROW_IO_ERROR( wxString::Format( _( "Invalid IBIS pin '%s' in component '%s'" ),
ibisPinName,
ibisCompName ) );
}
KIBIS_MODEL* kmodel = kibis.GetModel( ibisModelName );
if( !kmodel )
THROW_IO_ERROR( wxString::Format( _( "Could not find IBIS model '%s'" ), ibisModelName ) );
if( !kmodel->m_valid )
THROW_IO_ERROR( wxString::Format( _( "Invalid IBIS model '%s'" ), ibisModelName ) );
KIBIS_PARAMETER kparams;
kparams.SetCornerFromString( kparams.m_supply, FindParam( "vcc" )->value->ToString() );
kparams.SetCornerFromString( kparams.m_Rpin, FindParam( "rpin" )->value->ToString() );
kparams.SetCornerFromString( kparams.m_Lpin, FindParam( "lpin" )->value->ToString() );
kparams.SetCornerFromString( kparams.m_Cpin, FindParam( "cpin" )->value->ToString() );
//kparams.SetCornerFromString( kparams.m_Ccomp, FindParam( "ccomp" )->value->ToString() );
std::string result;
switch( GetType() )
{
case SIM_MODEL::TYPE::KIBIS_DEVICE:
kpin->writeSpiceDevice( &result, ibisModelName, *kmodel, kparams );
break;
case SIM_MODEL::TYPE::KIBIS_DRIVER_DC:
{
std::string paramValue = FindParam( "dc" )->value->ToString();
if( paramValue == "hi-Z" )
{
kparams.m_waveform =
static_cast<KIBIS_WAVEFORM*>( new KIBIS_WAVEFORM_HIGH_Z() );
}
else if( paramValue == "low" )
{
kparams.m_waveform =
static_cast<KIBIS_WAVEFORM*>( new KIBIS_WAVEFORM_STUCK_LOW() );
}
else if( paramValue == "high" )
{
kparams.m_waveform =
static_cast<KIBIS_WAVEFORM*>( new KIBIS_WAVEFORM_STUCK_HIGH() );
}
kpin->writeSpiceDriver( &result, ibisModelName, *kmodel, kparams );
break;
}
case SIM_MODEL::TYPE::KIBIS_DRIVER_RECT:
{
KIBIS_WAVEFORM_RECTANGULAR* waveform = new KIBIS_WAVEFORM_RECTANGULAR();
waveform->m_ton = static_cast<SIM_VALUE_FLOAT&>( *FindParam( "ton" )->value ).Get().value_or( 1 );
waveform->m_toff = static_cast<SIM_VALUE_FLOAT&>( *FindParam( "toff" )->value ).Get().value_or( 1 );
waveform->m_delay = static_cast<SIM_VALUE_FLOAT&>( *FindParam( "delay" )->value ).Get().value_or( 0 );
kparams.m_waveform = waveform;
kpin->writeSpiceDriver( &result, ibisModelName, *kmodel, kparams );
break;
}
case SIM_MODEL::TYPE::KIBIS_DRIVER_PRBS:
{
KIBIS_WAVEFORM_PRBS* waveform = new KIBIS_WAVEFORM_PRBS();
waveform->m_bitrate = static_cast<SIM_VALUE_FLOAT&>( *FindParam( "f0" )->value ).Get().value_or( 0 );
waveform->m_bits = static_cast<SIM_VALUE_FLOAT&>( *FindParam( "bits" )->value ).Get().value_or( 0 );
waveform->m_delay = static_cast<SIM_VALUE_FLOAT&>( *FindParam( "delay" )->value ).Get().value_or( 0 );
kparams.m_waveform = waveform;
kpin->writeSpiceDriver( &result, ibisModelName, *kmodel, kparams );
break;
}
default:
wxFAIL_MSG( "Unknown IBIS model type" );
return "";
}
return result;
// Actual base models can only be of the same type, which is not the case here, as in addition
// to IBIS device model type we have multiple types of drivers available for the same sourced
// model. And we don't want to inherit the default values anyway. So we just store these models
// and use the only for Spice code generation.
m_sourceModel = &aBaseModel;
}

View File

@ -40,6 +40,8 @@ public:
std::string ModelLine( const std::string& aModelName ) const override;
std::vector<std::string> CurrentNames( const std::string& aRefName ) const override;
std::string IbisDevice( const std::vector<SCH_FIELD>& aFields ) const;
protected:
std::vector<std::reference_wrapper<const SIM_MODEL::PARAM>> GetInstanceParams() const override;
};
@ -89,8 +91,6 @@ public:
void SetBaseModel( const SIM_MODEL& aBaseModel ) override;
std::string GenerateSpiceDriver( const std::vector<SCH_FIELD>& aFields ) const;
protected:
void CreatePins( unsigned aSymbolPinCount ) override;
@ -102,6 +102,7 @@ private:
static std::vector<PARAM::INFO> makeRectWaveformParamInfos();
static std::vector<PARAM::INFO> makePrbsWaveformParamInfos();
const SIM_MODEL* m_sourceModel;
std::vector<std::string> m_ibisModels;
std::vector<std::pair<std::string, std::string>> m_ibisPins;
std::string m_componentName;