Allow mapping sim model pins to arbitrary string symbol pin numbers

This change removes the incorrect assumption that symbol pin numbers are
integers and are the same as indexes in the vector storing the symbol
pins.

"~" is now used to denote a floating sim model pin.
This commit is contained in:
Mikolaj Wielgus 2022-08-22 07:40:23 +02:00
parent 73cfea892c
commit 6fad25f8ed
18 changed files with 273 additions and 190 deletions

View File

@ -51,7 +51,7 @@ DIALOG_SIM_MODEL<T>::DIALOG_SIM_MODEL( wxWindow* aParent, SCH_SYMBOL& aSymbol,
for( SIM_MODEL::TYPE type : SIM_MODEL::TYPE_ITERATOR() )
{
m_models.push_back( SIM_MODEL::Create( type, m_symbol.GetAllPins().size() ) );
m_models.push_back( SIM_MODEL::Create( type, m_symbol.GetLibPins().size() ) );
SIM_MODEL::DEVICE_TYPE_ deviceType = SIM_MODEL::TypeInfo( type ).deviceType;
@ -129,7 +129,7 @@ bool DIALOG_SIM_MODEL<T>::TransferDataToWindow()
try
{
m_models.at( static_cast<int>( SIM_MODEL::ReadTypeFromFields( m_fields ) ) )
= SIM_MODEL::Create( m_symbol.GetAllPins().size(), m_fields );
= SIM_MODEL::Create( m_symbol.GetLibPins().size(), m_fields );
}
catch( const IO_ERROR& e )
{
@ -266,7 +266,7 @@ void DIALOG_SIM_MODEL<T>::updateModelParamsTab()
m_paramGrid->CollapseAll();
for( unsigned i = 0; i < curModel().GetParamCount(); ++i )
for( int i = 0; i < curModel().GetParamCount(); ++i )
addParamPropertyIfRelevant( i );
m_paramGrid->CollapseAll();
@ -285,10 +285,10 @@ void DIALOG_SIM_MODEL<T>::updateModelParamsTab()
wxColour bgCol = m_paramGrid->GetGrid()->GetPropertyDefaultCell().GetBgCol();
wxColour fgCol = m_paramGrid->GetGrid()->GetPropertyDefaultCell().GetFgCol();
for( int i = 0; i < m_paramGridMgr->GetColumnCount(); ++i )
for( int col = 0; col < m_paramGridMgr->GetColumnCount(); ++col )
{
prop->GetCell( i ).SetBgCol( bgCol );
prop->GetCell( i ).SetFgCol( fgCol );
prop->GetCell( col ).SetBgCol( bgCol );
prop->GetCell( col ).SetFgCol( fgCol );
}
// Model values other than the currently edited value may have changed. Update them.
@ -329,38 +329,36 @@ void DIALOG_SIM_MODEL<T>::updatePinAssignmentsTab()
// First reset the grid.
m_pinAssignmentsGrid->ClearRows();
std::vector<SCH_PIN*> pinList = m_symbol.GetAllPins();
m_pinAssignmentsGrid->AppendRows( static_cast<int>( m_symbol.GetLibPins().size() ) );
m_pinAssignmentsGrid->AppendRows( static_cast<int>( pinList.size() ) );
for( int i = 0; i < m_pinAssignmentsGrid->GetNumberRows(); ++i )
for( int row = 0; row < m_pinAssignmentsGrid->GetNumberRows(); ++row )
{
m_pinAssignmentsGrid->SetCellValue( i, static_cast<int>( PIN_COLUMN::MODEL ),
m_pinAssignmentsGrid->SetCellValue( row, static_cast<int>( PIN_COLUMN::MODEL ),
"Not Connected" );
}
// Now set the grid values.
for( unsigned i = 0; i < curModel().GetPinCount(); ++i )
// Now set up the grid values in the Model column.
for( int modelPinIndex = 0; modelPinIndex < curModel().GetPinCount(); ++modelPinIndex )
{
unsigned symbolPinNumber = curModel().GetPin( i ).symbolPinNumber;
wxString symbolPinNumber = curModel().GetPin( modelPinIndex ).symbolPinNumber;
if( symbolPinNumber == SIM_MODEL::PIN::NOT_CONNECTED )
if( symbolPinNumber == "" )
continue;
wxString modelPinString = getModelPinString( i + 1 );
wxString modelPinString = getModelPinString( modelPinIndex );
wxArrayString choices;
m_pinAssignmentsGrid->SetCellValue( static_cast<int>( symbolPinNumber - 1 ),
m_pinAssignmentsGrid->SetCellValue( findSymbolPinRow( symbolPinNumber ),
static_cast<int>( PIN_COLUMN::MODEL ),
modelPinString );
}
wxArrayString modelPinChoices = getModelPinChoices();
// Now set up cell editors, including dropdown options.
// Set up the Symbol column grid values and Model column cell editors with dropdown options.
for( int i = 0; i < m_pinAssignmentsGrid->GetNumberRows(); ++i )
{
wxString symbolPinString = getSymbolPinString( i + 1 );
wxString symbolPinString = getSymbolPinString( i );
m_pinAssignmentsGrid->SetReadOnly( i, static_cast<int>( PIN_COLUMN::SYMBOL ) );
m_pinAssignmentsGrid->SetCellValue( i, static_cast<int>( PIN_COLUMN::SYMBOL ),
@ -421,12 +419,12 @@ void DIALOG_SIM_MODEL<T>::loadLibrary( const wxString& aFilePath )
//TODO: it's not cur model.
m_libraryModels.push_back(
SIM_MODEL::Create( baseModel, m_symbol.GetAllPins().size(), m_fields ) );
SIM_MODEL::Create( baseModel, m_symbol.GetLibPins().size(), m_fields ) );
}
else
{
m_libraryModels.push_back(
SIM_MODEL::Create( baseModel, m_symbol.GetAllPins().size() ) );
SIM_MODEL::Create( baseModel, m_symbol.GetLibPins().size() ) );
}
}
}
@ -600,6 +598,21 @@ wxPGProperty* DIALOG_SIM_MODEL<T>::newParamProperty( int aParamIndex ) const
}
template <typename T>
int DIALOG_SIM_MODEL<T>::findSymbolPinRow( const wxString& aSymbolPinNumber ) const
{
for( int row = 0; row < static_cast<int>( m_symbol.GetLibPins().size() ); ++row )
{
LIB_PIN* pin = m_symbol.GetLibPins()[row];
if( pin->GetNumber() == aSymbolPinNumber )
return row;
}
return -1;
}
template <typename T>
SIM_MODEL& DIALOG_SIM_MODEL<T>::curModel() const
{
@ -621,35 +634,43 @@ std::shared_ptr<SIM_MODEL> DIALOG_SIM_MODEL<T>::curModelSharedPtr() const
template <typename T>
wxString DIALOG_SIM_MODEL<T>::getSymbolPinString( int symbolPinNumber ) const
wxString DIALOG_SIM_MODEL<T>::getSymbolPinString( int symbolPinIndex ) const
{
wxString name = "";
SCH_PIN* symbolPin = m_symbol.GetAllPins().at( symbolPinNumber - 1 );
LIB_PIN* pin = m_symbol.GetLibPins().at( symbolPinIndex );
wxString number;
wxString name;
if( symbolPin )
name = symbolPin->GetShownName();
if( pin )
{
number = pin->GetShownNumber();
name = pin->GetShownName();
}
if( name.IsEmpty() )
return wxString::Format( "%d", symbolPinNumber );
LOCALE_IO toggle;
if( name == "" )
return wxString::Format( "%s", number );
else
return wxString::Format( "%d (%s)", symbolPinNumber, name );
return wxString::Format( "%s (%s)", number, name );
}
template <typename T>
wxString DIALOG_SIM_MODEL<T>::getModelPinString( int modelPinNumber ) const
wxString DIALOG_SIM_MODEL<T>::getModelPinString( int aModelPinIndex ) const
{
const wxString& pinName = curModel().GetPin( modelPinNumber - 1 ).name;
const wxString& pinName = curModel().GetPin( aModelPinIndex ).name;
if( pinName.IsEmpty() )
return wxString::Format( "%d", modelPinNumber, pinName );
LOCALE_IO toggle;
if( pinName == "" )
return wxString::Format( "%d", aModelPinIndex + 1, pinName );
else
return wxString::Format( "%d (%s)", modelPinNumber, pinName );
return wxString::Format( "%d (%s)", aModelPinIndex + 1, pinName );
}
template <typename T>
unsigned DIALOG_SIM_MODEL<T>::getModelPinNumber( const wxString& aModelPinString ) const
int DIALOG_SIM_MODEL<T>::getModelPinIndex( const wxString& aModelPinString ) const
{
if( aModelPinString == "Not Connected" )
return SIM_MODEL::PIN::NOT_CONNECTED;
@ -662,7 +683,7 @@ unsigned DIALOG_SIM_MODEL<T>::getModelPinNumber( const wxString& aModelPinString
long result = 0;
aModelPinString.Mid( 0, length ).ToCLong( &result );
return static_cast<unsigned>( result );
return static_cast<int>( result - 1 );
}
@ -672,21 +693,20 @@ wxArrayString DIALOG_SIM_MODEL<T>::getModelPinChoices() const
wxArrayString modelPinChoices;
bool isFirst = true;
for( unsigned i = 0; i < curModel().GetPinCount(); ++i )
for( int i = 0; i < curModel().GetPinCount(); ++i )
{
const SIM_MODEL::PIN& modelPin = curModel().GetPin( i );
int modelPinNumber = static_cast<int>( i + 1 );
if( modelPin.symbolPinNumber != SIM_MODEL::PIN::NOT_CONNECTED )
if( modelPin.symbolPinNumber != "" )
continue;
if( isFirst )
{
modelPinChoices.Add( getModelPinString( modelPinNumber ) );
modelPinChoices.Add( getModelPinString( i ) );
isFirst = false;
}
else
modelPinChoices.Add( getModelPinString( modelPinNumber ) );
modelPinChoices.Add( getModelPinString( i ) );
}
modelPinChoices.Add( "Not Connected" );
@ -806,16 +826,19 @@ void DIALOG_SIM_MODEL<T>::onCodePreviewSetFocus( wxFocusEvent& aEvent )
template <typename T>
void DIALOG_SIM_MODEL<T>::onPinAssignmentsGridCellChange( wxGridEvent& aEvent )
{
int symbolPinNumber = aEvent.GetRow() + 1;
unsigned oldModelPinNumber = getModelPinNumber( aEvent.GetString() );
unsigned modelPinNumber = getModelPinNumber(
int symbolPinIndex = aEvent.GetRow();
int oldModelPinIndex = getModelPinIndex( aEvent.GetString() );
int modelPinIndex = getModelPinIndex(
m_pinAssignmentsGrid->GetCellValue( aEvent.GetRow(), aEvent.GetCol() ) );
if( oldModelPinNumber != SIM_MODEL::PIN::NOT_CONNECTED )
curModel().SetPinSymbolPinNumber( oldModelPinNumber - 1, SIM_MODEL::PIN::NOT_CONNECTED );
if( oldModelPinIndex != SIM_MODEL::PIN::NOT_CONNECTED )
curModel().SetPinSymbolPinNumber( oldModelPinIndex, "" );
if( modelPinNumber != SIM_MODEL::PIN::NOT_CONNECTED )
curModel().SetPinSymbolPinNumber( modelPinNumber - 1, symbolPinNumber );
if( modelPinIndex != SIM_MODEL::PIN::NOT_CONNECTED )
{
curModel().SetPinSymbolPinNumber( modelPinIndex,
m_symbol.GetLibPins().at( symbolPinIndex )->GetShownNumber() );
}
updatePinAssignmentsTab();

View File

@ -85,12 +85,14 @@ private:
void addParamPropertyIfRelevant( int aParamIndex );
wxPGProperty* newParamProperty( int aParamIndex ) const;
int findSymbolPinRow( const wxString& aSymbolPinNumber ) const;
SIM_MODEL& curModel() const;
std::shared_ptr<SIM_MODEL> curModelSharedPtr() const;
wxString getSymbolPinString( int aSymbolPinNumber ) const;
wxString getModelPinString( int aModelPinNumber ) const;
unsigned getModelPinNumber( const wxString& aModelPinString ) const;
wxString getModelPinString( int aModelPinIndex ) const;
int getModelPinIndex( const wxString& aModelPinString ) const;
wxArrayString getModelPinChoices() const;
void onRadioButton( wxCommandEvent& aEvent ) override;

View File

@ -37,6 +37,7 @@
#include <string_utils.h>
#include <pegtl.hpp>
#include <pegtl/contrib/parse_tree.hpp>
#include <locale_io.h>
namespace NETLIST_EXPORTER_SPICE_PARSER
@ -94,7 +95,7 @@ bool NETLIST_EXPORTER_SPICE::GenerateNetlist( OUTPUTFORMATTER& aFormatter, unsig
bool NETLIST_EXPORTER_SPICE::ReadSchematicAndLibraries( unsigned aNetlistOptions )
{
std::set<wxString> refNames; // Set of reference names to check for duplication.
int notConnectedCounter = 1;
int NCCounter = 1;
ReadDirectives();
@ -126,7 +127,8 @@ bool NETLIST_EXPORTER_SPICE::ReadSchematicAndLibraries( unsigned aNetlistOptions
if( !readModel( *symbol, spiceItem ) )
continue;
readPins( *symbol, spiceItem, notConnectedCounter );
readPinNumbers( *symbol, spiceItem );
readPinNetNames( *symbol, spiceItem, NCCounter );
// TODO: transmission line handling?
@ -211,8 +213,8 @@ void NETLIST_EXPORTER_SPICE::ReadDirectives()
catch( const IO_ERROR& e )
{
DisplayErrorMessage( nullptr,
wxString::Format( "Failed reading model library '%s'.", path ),
e.What() );
wxString::Format( "Failed reading model library '%s'.", path ),
e.What() );
}
}
else
@ -326,9 +328,9 @@ bool NETLIST_EXPORTER_SPICE::readModel( SCH_SYMBOL& aSymbol, SPICE_ITEM& aItem )
}
}
// Special case for legacy models.
if( auto model = dynamic_cast<const SIM_MODEL_SPICE*>( aItem.model.get() ) )
{
// Special case for legacy models.
unsigned libParamIndex = static_cast<unsigned>( SIM_MODEL_SPICE::SPICE_PARAM::LIB );
wxString path = model->GetParam( libParamIndex ).value->ToString();
@ -340,19 +342,28 @@ bool NETLIST_EXPORTER_SPICE::readModel( SCH_SYMBOL& aSymbol, SPICE_ITEM& aItem )
}
void NETLIST_EXPORTER_SPICE::readPins( SCH_SYMBOL& aSymbol, SPICE_ITEM& aItem,
int& notConnectedCounter )
void NETLIST_EXPORTER_SPICE::readPinNumbers( SCH_SYMBOL& aSymbol, SPICE_ITEM& aItem )
{
for( const PIN_INFO& pin : m_sortedSymbolPinList )
for( const LIB_PIN* pin : aSymbol.GetLibPins() )
aItem.pinNumbers.push_back( pin->GetShownNumber() );
}
void NETLIST_EXPORTER_SPICE::readPinNetNames( SCH_SYMBOL& aSymbol, SPICE_ITEM& aItem,
int& aNCCounter )
{
for( const PIN_INFO& pinInfo : m_sortedSymbolPinList )
{
wxString netName = pin.netName;
wxString netName = pinInfo.netName;
ReplaceForbiddenChars( netName );
netName = UnescapeString( netName );
if( netName.IsEmpty() )
netName = wxString::Format( wxT( "NC_%.2u" ), notConnectedCounter++ );
LOCALE_IO toggle;
aItem.pins.push_back( netName );
if( netName == "" )
netName = wxString::Format( wxT( "__NC_%.2u" ), aNCCounter++ );
aItem.pinNetNames.push_back( netName );
m_nets.insert( netName );
}
}
@ -415,9 +426,11 @@ void NETLIST_EXPORTER_SPICE::writeItems( OUTPUTFORMATTER& aFormatter )
if( !item.model->IsEnabled() )
continue;
aFormatter.Print( 0, "%s", TO_UTF8( item.model->GenerateSpiceItemLine( item.refName,
item.modelName,
item.pins ) ) );
aFormatter.Print( 0, "%s",
TO_UTF8( item.model->GenerateSpiceItemLine( item.refName,
item.modelName,
item.pinNumbers,
item.pinNetNames ) ) );
}
}

View File

@ -35,7 +35,8 @@ struct SPICE_ITEM
{
wxString refName;
wxString libraryPath;
std::vector<wxString> pins;
std::vector<wxString> pinNumbers;
std::vector<wxString> pinNetNames;
std::unique_ptr<const SIM_MODEL> model;
wxString modelName;
};
@ -112,7 +113,8 @@ private:
bool readRefName( SCH_SHEET_PATH& aSheet, SCH_SYMBOL& aSymbol, SPICE_ITEM& aItem,
std::set<wxString>& aRefNames );
bool readModel( SCH_SYMBOL& aSymbol, SPICE_ITEM& aItem );
void readPins( SCH_SYMBOL& aSymbol, SPICE_ITEM& aItem, int& notConnectedCounter );
void readPinNumbers( SCH_SYMBOL& aSymbol, SPICE_ITEM& aItem );
void readPinNetNames( SCH_SYMBOL& aSymbol, SPICE_ITEM& aItem, int& aNCCounter );
void writeInclude( OUTPUTFORMATTER& aFormatter, unsigned aNetlistOptions,
const wxString& aPath );

View File

@ -920,6 +920,15 @@ void SCH_SYMBOL::GetLibPins( std::vector<LIB_PIN*>& aPinsList ) const
}
std::vector<LIB_PIN*> SCH_SYMBOL::GetLibPins() const
{
std::vector<LIB_PIN*> pinList;
GetLibPins( pinList );
return pinList;
}
SCH_PIN* SCH_SYMBOL::GetPin( LIB_PIN* aLibPin ) const
{
wxASSERT( m_pinMap.count( aLibPin ) );
@ -952,17 +961,6 @@ std::vector<SCH_PIN*> SCH_SYMBOL::GetPins( const SCH_SHEET_PATH* aSheet ) const
}
std::vector<SCH_PIN*> SCH_SYMBOL::GetAllPins() const
{
std::vector<SCH_PIN*> pins;
for( const auto& p : m_pins )
pins.push_back( p.get() );
return pins;
}
void SCH_SYMBOL::SwapData( SCH_ITEM* aItem )
{
wxCHECK_RET( (aItem != nullptr) && (aItem->Type() == SCH_SYMBOL_T),

View File

@ -467,6 +467,13 @@ public:
*/
void GetLibPins( std::vector<LIB_PIN*>& aPinsList ) const;
/**
* Return a vector with all the pins from the library object.
*
* @return List of the pins
*/
std::vector<LIB_PIN*> GetLibPins() const;
SCH_PIN* GetPin( LIB_PIN* aLibPin ) const;
/**

View File

@ -117,7 +117,7 @@ SIM_MODEL::DEVICE_INFO SIM_MODEL::DeviceTypeInfo( DEVICE_TYPE_ aDeviceType )
SIM_MODEL::INFO SIM_MODEL::TypeInfo( TYPE aType )
{
switch( aType )
{
{
case TYPE::NONE: return { DEVICE_TYPE_::NONE, "", "" };
case TYPE::R: return { DEVICE_TYPE_::R, "", "Ideal" };
@ -139,7 +139,7 @@ SIM_MODEL::INFO SIM_MODEL::TypeInfo( TYPE aType )
case TYPE::SW_I: return { DEVICE_TYPE_::SW, "I", "Current-controlled" };
case TYPE::D: return { DEVICE_TYPE_::D, "", "" };
case TYPE::NPN_GUMMELPOON: return { DEVICE_TYPE_::NPN, "GUMMELPOON", "Gummel-Poon" };
case TYPE::PNP_GUMMELPOON: return { DEVICE_TYPE_::PNP, "GUMMELPOON", "Gummel-Poon" };
case TYPE::NPN_VBIC: return { DEVICE_TYPE_::NPN, "VBIC", "VBIC" };
@ -261,7 +261,7 @@ SIM_MODEL::SPICE_INFO SIM_MODEL::SpiceInfo( TYPE aType )
case TYPE::L: return { "L", "" };
//case TYPE::L_ADV: return { "L", "l" };
case TYPE::L_BEHAVIORAL: return { "L", "", "", "0", false, true };
case TYPE::TLINE_Z0: return { "T" };
case TYPE::TLINE_RLGC: return { "O", "ltra" };
@ -602,7 +602,7 @@ TYPE SIM_MODEL::InferTypeFromRefAndValue( const wxString& aRef, const wxString&
}
}
}
catch( const tao::pegtl::parse_error& )
catch( const tao::pegtl::parse_error& e )
{
}
@ -853,8 +853,6 @@ void SIM_MODEL::ReadSpiceCode( const wxString& aSpiceCode )
}
catch( tao::pegtl::parse_error& e )
{
wxString msg;
msg.Printf( _( "Error parsing spice code <%s>\n%s" ), aSpiceCode, e.what() );
THROW_IO_ERROR( e.what() );
}
@ -925,18 +923,18 @@ wxString SIM_MODEL::GenerateSpiceModelLine( const wxString& aModelName ) const
wxString valueStr = param.value->ToSpiceString();
if( valueStr.IsEmpty() )
if( valueStr == "" )
continue;
wxString appendix = " " + param.info.name + "=" + valueStr;
wxString append = " " + param.info.name + "=" + valueStr;
if( line.Length() + append.Length() > 60 )
if( line.Length() + appendix.Length() > 60 )
{
result << line + "\n";
line = "+" + append;
result << line << "\n";
line = "+" + appendix;
}
else
line << append;
line << appendix;
}
result << line + " )\n";
@ -956,16 +954,33 @@ wxString SIM_MODEL::GenerateSpiceItemName( const wxString& aRefName ) const
wxString SIM_MODEL::GenerateSpiceItemLine( const wxString& aRefName,
const wxString& aModelName ) const
{
std::vector<wxString> pinNames;
for( const PIN& pin : GetPins() )
pinNames.push_back( pin.name );
// Use linear symbol pin numbers enumeration. Used in model preview.
return GenerateSpiceItemLine( aRefName, aModelName, pinNames );
std::vector<wxString> pinNumbers;
for( int i = 0; i < GetPinCount(); ++i )
pinNumbers.push_back( wxString::FromCDouble( i + 1 ) );
return GenerateSpiceItemLine( aRefName, aModelName, pinNumbers );
}
wxString SIM_MODEL::GenerateSpiceItemLine( const wxString& aRefName,
const wxString& aModelName,
const std::vector<wxString>& aSymbolPinNumbers ) const
{
std::vector<wxString> pinNames;
for( const PIN& pin : GetPins() )
pinNames.push_back( pin.name );
return GenerateSpiceItemLine( aRefName, aModelName, aSymbolPinNumbers, pinNames );
}
wxString SIM_MODEL::GenerateSpiceItemLine( const wxString& aRefName,
const wxString& aModelName,
const std::vector<wxString>& aSymbolPinNumbers,
const std::vector<wxString>& aPinNetNames ) const
{
wxString result = "";
@ -973,12 +988,20 @@ wxString SIM_MODEL::GenerateSpiceItemLine( const wxString& aRefName,
for( const PIN& pin : GetPins() )
{
for( unsigned i = 0; i < aPinNetNames.size(); ++i )
{
unsigned symbolPinNumber = i + 1;
int ncCounter = 0;
auto it = std::find( aSymbolPinNumbers.begin(),
aSymbolPinNumbers.end(),
pin.symbolPinNumber );
if( symbolPinNumber == pin.symbolPinNumber )
result << aPinNetNames[i] << " ";
if( it == aSymbolPinNumbers.end() )
{
LOCALE_IO toggle;
result << wxString::Format( "__NC_%s_%s_%.2u", aRefName, aModelName, ncCounter++ );
}
else
{
long symbolPinIndex = std::distance( aSymbolPinNumbers.begin(), it );
result << aPinNetNames.at( symbolPinIndex ) << " ";
}
}
@ -992,7 +1015,7 @@ wxString SIM_MODEL::GenerateSpiceItemLine( const wxString& aRefName,
wxString name = ( param.info.spiceInstanceName == "" ) ?
param.info.name : param.info.spiceInstanceName;
wxString value = param.value->ToString( SIM_VALUE_GRAMMAR::NOTATION::SPICE );
wxString value = param.value->ToSpiceString();
if( value != "" )
result << name << "=" << value << " ";
@ -1042,15 +1065,15 @@ void SIM_MODEL::AddPin( const PIN& aPin )
}
unsigned SIM_MODEL::FindModelPinNumber( unsigned aSymbolPinNumber )
int SIM_MODEL::FindModelPinIndex( const wxString& aSymbolPinNumber )
{
for( unsigned i = 0; i < GetPinCount(); ++i )
for( int modelPinIndex = 0; modelPinIndex < GetPinCount(); ++modelPinIndex )
{
if( GetPin( i ).symbolPinNumber == aSymbolPinNumber )
return i + 1;
if( GetPin( modelPinIndex ).symbolPinNumber == aSymbolPinNumber )
return modelPinIndex;
}
return 0;
return PIN::NOT_CONNECTED;
}
@ -1064,8 +1087,8 @@ std::vector<std::reference_wrapper<const SIM_MODEL::PIN>> SIM_MODEL::GetPins() c
{
std::vector<std::reference_wrapper<const PIN>> pins;
for( unsigned i = 0; i < GetPinCount(); ++i )
pins.emplace_back( GetPin( i ) );
for( int modelPinIndex = 0; modelPinIndex < GetPinCount(); ++modelPinIndex )
pins.emplace_back( GetPin( modelPinIndex ) );
return pins;
}
@ -1101,8 +1124,8 @@ std::vector<std::reference_wrapper<const SIM_MODEL::PARAM>> SIM_MODEL::GetParams
{
std::vector<std::reference_wrapper<const PARAM>> params;
for( unsigned i = 0; i < GetParamCount(); ++i )
params.emplace_back( GetParam( i ) );
for( int i = 0; i < GetParamCount(); ++i )
params.push_back( GetParam( i ) );
return params;
}
@ -1144,7 +1167,7 @@ bool SIM_MODEL::SetParamValue( const wxString& aParamName, const wxString& aValu
{
return param.info.name == aParamName.Lower();
} );
if( it == params.end() )
return false;
@ -1199,12 +1222,12 @@ void SIM_MODEL::CreatePins( unsigned aSymbolPinCount )
// 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.
for( unsigned i = 0; i < getPinNames().size(); ++i )
for( unsigned modelPinIndex = 0; modelPinIndex < getPinNames().size(); ++modelPinIndex )
{
if( i < aSymbolPinCount )
AddPin( { getPinNames().at( i ), i + 1 } );
if( modelPinIndex < aSymbolPinCount )
AddPin( { getPinNames().at( modelPinIndex ), wxString::FromCDouble( modelPinIndex + 1 ) } );
else
AddPin( { getPinNames().at( i ), PIN::NOT_CONNECTED } );
AddPin( { getPinNames().at( modelPinIndex ), "" } );
}
}
@ -1218,8 +1241,8 @@ template <typename T>
void SIM_MODEL::WriteInferredDataFields( std::vector<T>& aFields, const wxString& aValue ) const
{
if( GetPinCount() == 2
&& GetPin( 0 ).symbolPinNumber == 1
&& GetPin( 1 ).symbolPinNumber == 2 )
&& GetPin( 0 ).symbolPinNumber == "1"
&& GetPin( 1 ).symbolPinNumber == "2" )
{
SetFieldValue( aFields, PINS_FIELD, "" );
}
@ -1276,13 +1299,14 @@ wxString SIM_MODEL::GenerateParamsField( const wxString& aPairSeparator ) const
void SIM_MODEL::ParseParamsField( const wxString& aParamsField )
{
LOCALE_IO toggle;
tao::pegtl::string_input<> in( aParamsField.ToUTF8(), "Sim_Params" );
std::unique_ptr<tao::pegtl::parse_tree::node> root;
try
{
// Using parse tree instead of actions because we don't care about performance that much,
// and having a tree greatly simplifies some things.
// and having a tree greatly simplifies some things.
root = tao::pegtl::parse_tree::parse<
SIM_MODEL_PARSER::fieldParamValuePairsGrammar,
SIM_MODEL_PARSER::fieldParamValuePairsSelector>
@ -1290,9 +1314,7 @@ void SIM_MODEL::ParseParamsField( const wxString& aParamsField )
}
catch( const tao::pegtl::parse_error& e )
{
wxString msg;
msg.Printf( _( "Error parsing param <%s>\n%s" ), aParamsField, e.what() );
THROW_IO_ERROR( msg );
THROW_IO_ERROR( e.what() );
}
wxString paramName = "";
@ -1303,7 +1325,7 @@ void SIM_MODEL::ParseParamsField( const wxString& aParamsField )
paramName = node->string();
// TODO: Do something with number<SIM_VALUE::TYPE_INT, ...>.
// It doesn't seem too useful?
else if( node->is_type<SIM_MODEL_PARSER::quotedStringContent>()
else if( node->is_type<SIM_MODEL_PARSER::quotedStringContent>()
|| node->is_type<SIM_MODEL_PARSER::unquotedString>() )
{
wxASSERT( paramName != "" );
@ -1347,12 +1369,10 @@ void SIM_MODEL::ParsePinsField( unsigned aSymbolPinCount, const wxString& aPinsF
}
catch( const tao::pegtl::parse_error& e )
{
wxString msg;
msg.Printf( _( "Error parsing pin field <%s>\n%s" ), aPinsField, e.what() );
THROW_IO_ERROR( e.what() );
}
if( root->children.size() != GetPinCount() )
if( static_cast<int>( root->children.size() ) != GetPinCount() )
{
THROW_IO_ERROR( wxString::Format( _( "%s describes %lu pins, expected %u" ),
PINS_FIELD,
@ -1360,13 +1380,12 @@ void SIM_MODEL::ParsePinsField( unsigned aSymbolPinCount, const wxString& aPinsF
GetPinCount() ) );
}
for( unsigned i = 0; i < root->children.size(); ++i )
for( int pinIndex = 0; pinIndex < static_cast<int>( root->children.size() ); ++pinIndex )
{
if( root->children.at( i )->string() == "X" )
SetPinSymbolPinNumber( static_cast<int>( i ), PIN::NOT_CONNECTED );
if( root->children.at( pinIndex )->string() == "~" )
SetPinSymbolPinNumber( pinIndex, "" );
else
SetPinSymbolPinNumber( static_cast<int>( i ),
std::stoi( root->children.at( i )->string() ) );
SetPinSymbolPinNumber( pinIndex, root->children.at( pinIndex )->string() );
}
}
@ -1405,7 +1424,7 @@ std::unique_ptr<SIM_MODEL> SIM_MODEL::create( TYPE aType )
case TYPE::V_BEHAVIORAL:
case TYPE::I_BEHAVIORAL:
return std::make_unique<SIM_MODEL_BEHAVIORAL>( aType );
case TYPE::TLINE_Z0:
case TYPE::TLINE_RLGC:
return std::make_unique<SIM_MODEL_TLINE>( aType );
@ -1548,17 +1567,17 @@ wxString SIM_MODEL::generatePinsField() const
wxString result = "";
bool isFirst = true;
for( unsigned i = 0; i < GetPinCount(); ++i )
for( int pinIndex = 0; pinIndex < GetPinCount(); ++pinIndex )
{
if( isFirst )
isFirst = false;
else
result << " ";
if( GetPin( i ).symbolPinNumber == PIN::NOT_CONNECTED )
result << "X";
if( GetPin( pinIndex ).symbolPinNumber == "" )
result << "~";
else
result << GetPin( i ).symbolPinNumber;
result << GetPin( pinIndex ).symbolPinNumber; // Note that it's numbered from 1.
}
return result;

View File

@ -51,10 +51,12 @@ namespace SIM_MODEL_GRAMMAR
star<sep,
legacyPinNumber>> {};
struct legacyPinSequenceGrammar : must<legacyPinSequence, tao::pegtl::eof> {};
struct legacyPinSequenceGrammar : must<legacyPinSequence,
tao::pegtl::eof> {};
struct pinNumber : sor<digits, one<'X'>> {};
struct pinNumber : plus<not_at<sep>,
any> {};
struct pinSequence : seq<opt<pinNumber>,
star<sep,
pinNumber>> {};
@ -64,16 +66,17 @@ namespace SIM_MODEL_GRAMMAR
opt<sep>,
tao::pegtl::eof> {};
struct unquotedString : plus<not_at<space>, any> {};
struct unquotedString : plus<not_at<sep>, any> {};
struct quotedStringContent : star<not_at<one<'"'>>, any> {}; // TODO: Allow escaping '"'.
struct quotedString : seq<one<'"'>,
quotedStringContent,
one<'"'>> {};
struct fieldFloatValue : seq<star<space>,
struct fieldFloatValue : seq<opt<sep>,
number<SIM_VALUE::TYPE_FLOAT, NOTATION::SI>,
star<not_at<space>, any>, // Garbage suffix.
star<space>> {};
star<not_at<sep>, any>, // Garbage suffix.
opt<sep>> {};
struct fieldFloatValueGrammar : must<fieldFloatValue,
tao::pegtl::eof> {};
@ -324,10 +327,10 @@ public:
struct PIN
{
static constexpr unsigned NOT_CONNECTED = 0;
const wxString name;
unsigned symbolPinNumber;
wxString symbolPinNumber;
static constexpr auto NOT_CONNECTED = -1;
};
@ -489,8 +492,12 @@ public:
virtual wxString GenerateSpiceItemName( const wxString& aRefName ) const;
wxString GenerateSpiceItemLine( const wxString& aRefName, const wxString& aModelName ) const;
wxString GenerateSpiceItemLine( const wxString& aRefName,
const wxString& aModelName,
const std::vector<wxString>& aSymbolPinNumbers ) const;
virtual wxString GenerateSpiceItemLine( const wxString& aRefName,
const wxString& aModelName,
const std::vector<wxString>& aSymbolPinNumbers,
const std::vector<wxString>& aPinNetNames ) const;
virtual wxString GenerateSpiceTuningLine( const wxString& aSymbol ) const;
@ -501,7 +508,7 @@ public:
virtual std::vector<wxString> GenerateSpiceCurrentNames( const wxString& aRefName ) const;
void AddPin( const PIN& aPin );
unsigned FindModelPinNumber( unsigned aSymbolPinNumber );
int FindModelPinIndex( const wxString& aSymbolPinNumber );
void AddParam( const PARAM::INFO& aInfo, bool aIsOtherVariant = false );
DEVICE_INFO GetDeviceTypeInfo() const { return DeviceTypeInfo( GetDeviceType() ); }
@ -513,18 +520,18 @@ public:
const SIM_MODEL* GetBaseModel() const { return m_baseModel; }
virtual void SetBaseModel( const SIM_MODEL& aBaseModel ) { m_baseModel = &aBaseModel; }
unsigned GetPinCount() const { return m_pins.size(); }
int GetPinCount() const { return static_cast<int>( m_pins.size() ); }
const PIN& GetPin( unsigned aIndex ) const { return m_pins.at( aIndex ); }
std::vector<std::reference_wrapper<const PIN>> GetPins() const;
void SetPinSymbolPinNumber( int aIndex, int aSymbolPinNumber )
void SetPinSymbolPinNumber( int aPinIndex, const wxString& aSymbolPinNumber )
{
m_pins.at( aIndex ).symbolPinNumber = aSymbolPinNumber;
m_pins.at( aPinIndex ).symbolPinNumber = aSymbolPinNumber;
}
unsigned GetParamCount() const { return m_params.size(); }
int GetParamCount() const { return static_cast<int>( m_params.size() ); }
const PARAM& GetParam( unsigned aParamIndex ) const; // Return base parameter unless it's overridden.
const PARAM* FindParam( const wxString& aParamName ) const;

View File

@ -95,6 +95,7 @@ wxString SIM_MODEL_BEHAVIORAL::GenerateSpiceModelLine( const wxString& aModelNam
wxString SIM_MODEL_BEHAVIORAL::GenerateSpiceItemLine( const wxString& aRefName,
const wxString& aModelName,
const std::vector<wxString>& aSymbolPinNumbers,
const std::vector<wxString>& aPinNetNames ) const
{
LOCALE_IO toggle;

View File

@ -45,6 +45,7 @@ public:
wxString GenerateSpiceItemLine( const wxString& aRefName,
const wxString& aModelName,
const std::vector<wxString>& aSymbolPinNumbers,
const std::vector<wxString>& aPinNetNames ) const override;
private:

View File

@ -104,12 +104,13 @@ wxString SIM_MODEL_IDEAL::GenerateSpiceModelLine( const wxString& aModelName ) c
wxString SIM_MODEL_IDEAL::GenerateSpiceItemLine( const wxString& aRefName,
const wxString& aModelName,
const std::vector<wxString>& aSymbolPinNumbers,
const std::vector<wxString>& aPinNetNames ) const
{
wxString valueStr = GetParam( 0 ).value->ToString( SIM_VALUE::NOTATION::SPICE );
if( valueStr != "" )
return SIM_MODEL::GenerateSpiceItemLine( aRefName, valueStr, aPinNetNames );
return SIM_MODEL::GenerateSpiceItemLine( aRefName, valueStr, aSymbolPinNumbers, aPinNetNames );
else
return "";
}

View File

@ -42,6 +42,7 @@ public:
wxString GenerateSpiceModelLine( const wxString& aModelName ) const override;
wxString GenerateSpiceItemLine( const wxString& aRefName,
const wxString& aModelName,
const std::vector<wxString>& aSymbolPinNumbers,
const std::vector<wxString>& aPinNetNames ) const override;

View File

@ -94,6 +94,7 @@ wxString SIM_MODEL_SOURCE::GenerateSpiceModelLine( const wxString& aModelName )
wxString SIM_MODEL_SOURCE::GenerateSpiceItemLine( const wxString& aRefName,
const wxString& aModelName,
const std::vector<wxString>& aSymbolPinNumbers,
const std::vector<wxString>& aPinNetNames ) const
{
wxString model;
@ -230,7 +231,7 @@ wxString SIM_MODEL_SOURCE::GenerateSpiceItemLine( const wxString& aRefName,
else
model << GetParam( 0 ).value->ToString( SIM_VALUE_GRAMMAR::NOTATION::SPICE );
return SIM_MODEL::GenerateSpiceItemLine( aRefName, model, aPinNetNames );
return SIM_MODEL::GenerateSpiceItemLine( aRefName, model, aSymbolPinNumbers, aPinNetNames );
}
@ -241,15 +242,15 @@ bool SIM_MODEL_SOURCE::SetParamValue( unsigned aParamIndex, const wxString& aVal
// them out automatically. If a value is nulled, delete everything after it.
if( aValue == "" )
{
for( unsigned i = aParamIndex; i < GetParamCount(); ++i )
SIM_MODEL::SetParamValue( i, "", aNotation );
for( int paramIndex = aParamIndex; paramIndex < GetParamCount(); ++paramIndex )
SIM_MODEL::SetParamValue( paramIndex, "", aNotation );
}
else
{
for( unsigned i = 0; i < aParamIndex; ++i )
for( unsigned paramIndex = 0; paramIndex < aParamIndex; ++paramIndex )
{
if( GetParam( i ).value->ToString() == "" )
SIM_MODEL::SetParamValue( i, "0", aNotation );
if( GetParam( paramIndex ).value->ToString() == "" )
SIM_MODEL::SetParamValue( paramIndex, "0", aNotation );
}
}

View File

@ -59,6 +59,7 @@ public:
wxString GenerateSpiceModelLine( const wxString& aModelName ) const override;
wxString GenerateSpiceItemLine( const wxString& aRefName,
const wxString& aModelName,
const std::vector<wxString>& aSymbolPinNumbers,
const std::vector<wxString>& aPinNetNames ) const override;
bool SetParamValue( unsigned aParamIndex, const wxString& aValue,

View File

@ -100,20 +100,20 @@ wxString SIM_MODEL_SPICE::GenerateSpiceItemName( const wxString& aRefName ) cons
wxString SIM_MODEL_SPICE::GenerateSpiceItemLine( const wxString& aRefName,
const wxString& aModelName,
const std::vector<wxString>& aSymbolPinNumbers,
const std::vector<wxString>& aPinNetNames ) const
{
wxString result = "";
wxString result;
result << GenerateSpiceItemName( aRefName ) << " ";
for( unsigned i = 0; i < GetPinCount(); ++i )
for( const PIN& pin : GetPins() )
{
for( unsigned j = 0; j < aPinNetNames.size(); ++j )
{
unsigned symbolPinNumber = j + 1;
auto it = std::find( aSymbolPinNumbers.begin(),
aSymbolPinNumbers.end(),
pin.symbolPinNumber );
long symbolPinIndex = std::distance( aSymbolPinNumbers.begin(), it );
if( symbolPinNumber == GetPin( i ).symbolPinNumber )
result << aPinNetNames[j] << " ";
}
result << aPinNetNames.at( symbolPinIndex ) << " ";
}
result << GetParam( static_cast<unsigned>( SPICE_PARAM::MODEL ) ).value->ToString() << "\n";
@ -123,8 +123,8 @@ wxString SIM_MODEL_SPICE::GenerateSpiceItemLine( const wxString& aRefName,
void SIM_MODEL_SPICE::CreatePins( unsigned aSymbolPinCount )
{
for( unsigned i = 0; i < aSymbolPinCount; ++i )
AddPin( { "", i + 1 } );
for( unsigned symbolPinIndex = 0; symbolPinIndex < aSymbolPinCount; ++symbolPinIndex )
AddPin( { "", wxString::FromCDouble( symbolPinIndex + 1 ) } );
}
@ -132,15 +132,15 @@ bool SIM_MODEL_SPICE::SetParamFromSpiceCode( const wxString& aParamName,
const wxString& aParamValue,
SIM_VALUE_GRAMMAR::NOTATION aNotation )
{
unsigned i = 0;
int paramIndex = 0;
for(; i < GetParamCount(); ++i )
for(; paramIndex < GetParamCount(); ++paramIndex )
{
if( GetParam( i ).info.name == aParamName.Lower() )
if( GetParam( paramIndex ).info.name == aParamName.Lower() )
break;
}
if( i == GetParamCount() )
if( paramIndex == GetParamCount() )
{
// No parameter with this name found. Create a new one.
std::unique_ptr<PARAM::INFO> paramInfo = std::make_unique<PARAM::INFO>();
@ -152,7 +152,7 @@ bool SIM_MODEL_SPICE::SetParamFromSpiceCode( const wxString& aParamName,
AddParam( *m_paramInfos.back() );
}
return GetParam( i ).value->FromString( wxString( aParamValue ), aNotation );
return GetParam( paramIndex ).value->FromString( wxString( aParamValue ), aNotation );
}
@ -250,8 +250,8 @@ void SIM_MODEL_SPICE::parseLegacyPinsField( unsigned aSymbolPinCount,
return;
// Initially set all pins to Not Connected to match the legacy behavior.
for( unsigned i = 0; i < GetPinCount(); ++i )
SetPinSymbolPinNumber( static_cast<int>( i ), PIN::NOT_CONNECTED );
for( int modelPinIndex = 0; modelPinIndex < GetPinCount(); ++modelPinIndex )
SetPinSymbolPinNumber( static_cast<int>( modelPinIndex ), "" );
tao::pegtl::string_input<> in( aLegacyPinsField.ToUTF8(), PINS_FIELD );
std::unique_ptr<tao::pegtl::parse_tree::node> root;
@ -267,9 +267,18 @@ void SIM_MODEL_SPICE::parseLegacyPinsField( unsigned aSymbolPinCount,
THROW_IO_ERROR( e.what() );
}
for( unsigned i = 0; i < root->children.size(); ++i )
for( int pinIndex = 0; pinIndex < static_cast<int>( root->children.size() ); ++pinIndex )
{
SetPinSymbolPinNumber( static_cast<int>( i ),
std::stoi( root->children.at( i )->string() ) );
std::string symbolPinStr = root->children.at( pinIndex )->string();
int symbolPinIndex = std::stoi( symbolPinStr ) - 1;
if( symbolPinIndex < 0 || symbolPinIndex >= static_cast<int>( aSymbolPinCount ) )
{
THROW_IO_ERROR( wxString::Format( _( "Invalid symbol pin index: '%s'" ),
symbolPinStr ) );
}
SetPinSymbolPinNumber( pinIndex, root->children.at( pinIndex )->string() );
}
}

View File

@ -58,6 +58,7 @@ public:
wxString GenerateSpiceItemName( const wxString& aRefName ) const override;
wxString GenerateSpiceItemLine( const wxString& aRefName,
const wxString& aModelName,
const std::vector<wxString>& aSymbolPinNumbers,
const std::vector<wxString>& aPinNetNames ) const override;
protected:

View File

@ -81,7 +81,7 @@ void SIM_MODEL_SUBCKT::ReadSpiceCode( const wxString& aSpiceCode )
}
else if( subnode->is_type<SIM_MODEL_SUBCKT_SPICE_PARSER::dotSubcktPinName>() )
{
AddPin( { subnode->string(), GetPinCount() + 1 } );
AddPin( { subnode->string(), wxString::FromCDouble( GetPinCount() ) } );
}
else if( !hadParamValuePairs
&& subnode->is_type<SIM_MODEL_SUBCKT_SPICE_PARSER::paramValuePairs>() )
@ -107,10 +107,10 @@ void SIM_MODEL_SUBCKT::ReadSpiceCode( const wxString& aSpiceCode )
}
else if( subnode->is_type<
SIM_MODEL_SUBCKT_SPICE_PARSER::number<SIM_VALUE::TYPE_INT,
SIM_MODEL_SUBCKT_SPICE_PARSER::NOTATION::SPICE>>()
SIM_MODEL_SUBCKT_SPICE_PARSER::NOTATION::SPICE>>()
|| subnode->is_type<
SIM_MODEL_SUBCKT_SPICE_PARSER::number<SIM_VALUE::TYPE_FLOAT,
SIM_MODEL_SUBCKT_SPICE_PARSER::NOTATION::SPICE>>() )
SIM_MODEL_SUBCKT_SPICE_PARSER::NOTATION::SPICE>>() )
{
wxASSERT( m_paramInfos.size() > 0 );
m_paramInfos.back()->defaultValue = subnode->string();

View File

@ -47,6 +47,7 @@
#include <sch_sheet.h>
#include <sch_sheet_pin.h>
#include <sch_view.h>
#include <pin_numbers.h>
#include <schematic.h>
#include <advanced_config.h>
#include <sim/sim_plot_frame.h>
@ -62,7 +63,6 @@
#include <drawing_sheet/ds_proxy_undo_item.h>
#include <dialog_update_from_pcb.h>
#include <eda_list_dialog.h>
#include <locale_io.h>
#include <wildcards_and_files_ext.h>
#include <wx_filename.h>
@ -733,7 +733,6 @@ void SCH_EDITOR_CONTROL::doCrossProbeSchToPcb( const TOOL_EVENT& aEvent, bool aF
int SCH_EDITOR_CONTROL::SimProbe( const TOOL_EVENT& aEvent )
{
LOCALE_IO toggle;
PICKER_TOOL* picker = m_toolMgr->GetTool<PICKER_TOOL>();
SIM_PLOT_FRAME* simFrame = (SIM_PLOT_FRAME*) m_frame->Kiway().Player( FRAME_SIMULATOR, false );
@ -760,12 +759,9 @@ int SCH_EDITOR_CONTROL::SimProbe( const TOOL_EVENT& aEvent )
if( item->Type() == SCH_PIN_T )
{
SCH_PIN* pin = static_cast<SCH_PIN*>( item );
LIB_PIN* pin = static_cast<SCH_PIN*>( item )->GetLibPin();
SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item->GetParent() );
std::vector<SCH_PIN*> pins = symbol->GetAllPins();
int symbolPinNumber = static_cast<int>( std::distance( pins.begin(),
std::find( pins.begin(), pins.end(), pin ) ) ) + 1;
std::vector<LIB_PIN*> pins = symbol->GetLibPins();
// TODO: We need to unify this library-model inheritance stuff into one
// abstraction.
@ -813,7 +809,7 @@ int SCH_EDITOR_CONTROL::SimProbe( const TOOL_EVENT& aEvent )
wxString ref = symbol->GetRef( &m_frame->GetCurrentSheet() );
std::vector<wxString> currentNames = model->GenerateSpiceCurrentNames( ref );
if( currentNames.size() == 0 )
return true;
else if( currentNames.size() == 1 )
@ -822,11 +818,11 @@ int SCH_EDITOR_CONTROL::SimProbe( const TOOL_EVENT& aEvent )
return true;
}
int modelPinNumber = model->FindModelPinNumber( symbolPinNumber );
int modelPinIndex = model->FindModelPinIndex( pin->GetNumber() );
if( modelPinNumber > 0 )
if( modelPinIndex != SIM_MODEL::PIN::NOT_CONNECTED )
{
wxString name = currentNames.at( modelPinNumber - 1 );
wxString name = currentNames.at( modelPinIndex );
simFrame->AddCurrentPlot( name );
}
}