Don't allow writing "//" to spice netlist.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/18161
This commit is contained in:
parent
0d2838518b
commit
2e38fa84bf
|
@ -108,7 +108,7 @@ DIALOG_SIM_COMMAND::DIALOG_SIM_COMMAND( SIMULATOR_FRAME* aParent,
|
|||
// NoiseRef is optional
|
||||
m_noiseRef->Append( wxEmptyString );
|
||||
|
||||
for( const std::string& net : m_circuitModel->GetNets() )
|
||||
for( const wxString& net : m_circuitModel->GetNets() )
|
||||
{
|
||||
m_pzInput->Append( net );
|
||||
m_pzInputRef->Append( net );
|
||||
|
@ -287,7 +287,7 @@ wxString DIALOG_SIM_COMMAND::evaluateDCControls( wxChoice* aDcSource, wxTextCtrl
|
|||
|
||||
// pick device name from exporter when something different than temperature is selected
|
||||
if( dcSource.Cmp( "TEMP" ) )
|
||||
dcSource = m_circuitModel->GetItemName( std::string( dcSource.ToUTF8() ) );
|
||||
dcSource = m_circuitModel->GetItemName( dcSource );
|
||||
|
||||
return wxString::Format( "%s %s %s %s", dcSource,
|
||||
SPICE_VALUE( aDcStart->GetValue() ).ToSpiceString(),
|
||||
|
@ -423,10 +423,7 @@ bool DIALOG_SIM_COMMAND::TransferDataFromWindow()
|
|||
}
|
||||
|
||||
if( !ref.IsEmpty() )
|
||||
{
|
||||
ref = wxS( "," )
|
||||
+ wxString( m_circuitModel->GetItemName( std::string( ref.ToUTF8() ) ) );
|
||||
}
|
||||
ref = wxS( "," ) + m_circuitModel->GetItemName( ref );
|
||||
|
||||
m_simCommand.Printf( ".noise v(%s%s) %s %s %s %s %s %s",
|
||||
output,
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* Copyright (C) 1992-2013 jp.charras at wanadoo.fr
|
||||
* Copyright (C) 2013 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
|
||||
* Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.TXT for contributors.
|
||||
* Copyright (C) 1992-2024 KiCad Developers, see AUTHORS.TXT for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
@ -239,11 +239,10 @@ bool NETLIST_EXPORTER_SPICE::ReadSchematicAndLibraries( unsigned aNetlistOptions
|
|||
}
|
||||
|
||||
|
||||
void NETLIST_EXPORTER_SPICE::ConvertToSpiceMarkup( std::string& aNetName )
|
||||
void NETLIST_EXPORTER_SPICE::ConvertToSpiceMarkup( wxString* aNetName )
|
||||
{
|
||||
MARKUP::MARKUP_PARSER markupParser( aNetName );
|
||||
MARKUP::MARKUP_PARSER markupParser( aNetName->ToStdString() );
|
||||
std::unique_ptr<MARKUP::NODE> root = markupParser.Parse();
|
||||
std::string converted;
|
||||
|
||||
std::function<void( const std::unique_ptr<MARKUP::NODE>&)> convertMarkup =
|
||||
[&]( const std::unique_ptr<MARKUP::NODE>& aNode )
|
||||
|
@ -255,7 +254,7 @@ void NETLIST_EXPORTER_SPICE::ConvertToSpiceMarkup( std::string& aNetName )
|
|||
if( aNode->isOverbar() )
|
||||
{
|
||||
// ~{CLK} is a different signal than CLK
|
||||
converted += '~';
|
||||
*aNetName += '~';
|
||||
}
|
||||
else if( aNode->isSubscript() || aNode->isSuperscript() )
|
||||
{
|
||||
|
@ -263,7 +262,7 @@ void NETLIST_EXPORTER_SPICE::ConvertToSpiceMarkup( std::string& aNetName )
|
|||
}
|
||||
|
||||
if( aNode->has_content() )
|
||||
converted += aNode->string();
|
||||
*aNetName += aNode->string();
|
||||
}
|
||||
|
||||
for( const std::unique_ptr<MARKUP::NODE>& child : aNode->children )
|
||||
|
@ -271,43 +270,46 @@ void NETLIST_EXPORTER_SPICE::ConvertToSpiceMarkup( std::string& aNetName )
|
|||
}
|
||||
};
|
||||
|
||||
*aNetName = wxEmptyString;
|
||||
convertMarkup( root );
|
||||
|
||||
// Replace all ngspice-disallowed chars in netnames by a '_'
|
||||
std::replace( converted.begin(), converted.end(), '%', '_' );
|
||||
std::replace( converted.begin(), converted.end(), '(', '_' );
|
||||
std::replace( converted.begin(), converted.end(), ')', '_' );
|
||||
std::replace( converted.begin(), converted.end(), ',', '_' );
|
||||
std::replace( converted.begin(), converted.end(), '[', '_' );
|
||||
std::replace( converted.begin(), converted.end(), ']', '_' );
|
||||
std::replace( converted.begin(), converted.end(), '<', '_' );
|
||||
std::replace( converted.begin(), converted.end(), '>', '_' );
|
||||
std::replace( converted.begin(), converted.end(), '~', '_' );
|
||||
std::replace( converted.begin(), converted.end(), ' ', '_' );
|
||||
aNetName->Replace( '%', '_' );
|
||||
aNetName->Replace( '(', '_' );
|
||||
aNetName->Replace( ')', '_' );
|
||||
aNetName->Replace( ',', '_' );
|
||||
aNetName->Replace( '[', '_' );
|
||||
aNetName->Replace( ']', '_' );
|
||||
aNetName->Replace( '<', '_' );
|
||||
aNetName->Replace( '>', '_' );
|
||||
aNetName->Replace( '~', '_' );
|
||||
aNetName->Replace( ' ', '_' );
|
||||
|
||||
aNetName = converted;
|
||||
// A net name on the root sheet with a label '/foo' is going to get titled "//foo". This
|
||||
// will trip up ngspice as "//" opens a line comment.
|
||||
if( aNetName->StartsWith( wxS( "//" ) ) )
|
||||
aNetName->Replace( wxS( "//" ), wxS( "/root/" ), false /* replace all */ );
|
||||
}
|
||||
|
||||
|
||||
std::string NETLIST_EXPORTER_SPICE::GetItemName( const std::string& aRefName ) const
|
||||
wxString NETLIST_EXPORTER_SPICE::GetItemName( const wxString& aRefName ) const
|
||||
{
|
||||
const SPICE_ITEM* item = FindItem( aRefName );
|
||||
if( const SPICE_ITEM* item = FindItem( aRefName ) )
|
||||
return item->model->SpiceGenerator().ItemName( *item );
|
||||
|
||||
if( !item )
|
||||
return "";
|
||||
|
||||
return item->model->SpiceGenerator().ItemName( *item );
|
||||
return wxEmptyString;
|
||||
}
|
||||
|
||||
|
||||
const SPICE_ITEM* NETLIST_EXPORTER_SPICE::FindItem( const std::string& aRefName ) const
|
||||
const SPICE_ITEM* NETLIST_EXPORTER_SPICE::FindItem( const wxString& aRefName ) const
|
||||
{
|
||||
const std::string refName = aRefName.ToStdString();
|
||||
const std::list<SPICE_ITEM>& spiceItems = GetItems();
|
||||
|
||||
auto it = std::find_if( spiceItems.begin(), spiceItems.end(),
|
||||
[aRefName]( const SPICE_ITEM& item )
|
||||
[refName]( const SPICE_ITEM& item )
|
||||
{
|
||||
return item.refName == aRefName;
|
||||
return item.refName == refName;
|
||||
} );
|
||||
|
||||
if( it != spiceItems.end() )
|
||||
|
@ -502,12 +504,14 @@ void NETLIST_EXPORTER_SPICE::readPinNetNames( SCH_SYMBOL& aSymbol, SPICE_ITEM& a
|
|||
{
|
||||
for( const PIN_INFO& pinInfo : aPins )
|
||||
{
|
||||
std::string netName = GenerateItemPinNetName( pinInfo.netName.ToStdString(), aNcCounter );
|
||||
wxString netName = GenerateItemPinNetName( pinInfo.netName, aNcCounter );
|
||||
|
||||
aItem.pinNetNames.push_back( netName );
|
||||
aItem.pinNetNames.push_back( netName.ToStdString() );
|
||||
m_nets.insert( netName );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void NETLIST_EXPORTER_SPICE::getNodePattern( SPICE_ITEM& aItem,
|
||||
std::vector<std::string>& aModifiers )
|
||||
{
|
||||
|
@ -710,16 +714,15 @@ void NETLIST_EXPORTER_SPICE::WriteDirectives( const wxString& aSimCommand, unsig
|
|||
}
|
||||
|
||||
|
||||
std::string NETLIST_EXPORTER_SPICE::GenerateItemPinNetName( const std::string& aNetName,
|
||||
int& aNcCounter ) const
|
||||
wxString NETLIST_EXPORTER_SPICE::GenerateItemPinNetName( const wxString& aNetName,
|
||||
int& aNcCounter ) const
|
||||
{
|
||||
std::string netName = aNetName;
|
||||
wxString netName = UnescapeString( aNetName );
|
||||
|
||||
ConvertToSpiceMarkup( netName );
|
||||
netName = std::string( UnescapeString( netName ).ToUTF8() );
|
||||
ConvertToSpiceMarkup( &netName );
|
||||
|
||||
if( netName == "" )
|
||||
netName = fmt::format( "NC-{}", aNcCounter++ );
|
||||
if( netName.IsEmpty() )
|
||||
netName.Printf( wxS( "NC-%d" ), aNcCounter++ );
|
||||
|
||||
return netName;
|
||||
}
|
||||
|
|
|
@ -102,12 +102,12 @@ public:
|
|||
/**
|
||||
* Remove formatting wrappers and replace illegal spice net name characters with underscores.
|
||||
*/
|
||||
static void ConvertToSpiceMarkup( std::string& aNetName );
|
||||
static void ConvertToSpiceMarkup( wxString* aNetName );
|
||||
|
||||
/**
|
||||
* Return the list of nets.
|
||||
*/
|
||||
std::set<std::string> GetNets() const { return m_nets; }
|
||||
std::set<wxString> GetNets() const { return m_nets; }
|
||||
|
||||
/**
|
||||
* Return name of Spice device corresponding to a schematic symbol.
|
||||
|
@ -118,7 +118,7 @@ public:
|
|||
* corresponds to the assigned device model type or a reference prefixed with a character
|
||||
* defining the device model type.
|
||||
*/
|
||||
std::string GetItemName( const std::string& aRefName ) const;
|
||||
wxString GetItemName( const wxString& aRefName ) const;
|
||||
|
||||
/**
|
||||
* Return the list of items representing schematic symbols in the Spice world.
|
||||
|
@ -128,7 +128,7 @@ public:
|
|||
/**
|
||||
* Find and return the item corresponding to \a aRefName.
|
||||
*/
|
||||
const SPICE_ITEM* FindItem( const std::string& aRefName ) const;
|
||||
const SPICE_ITEM* FindItem( const wxString& aRefName ) const;
|
||||
|
||||
const std::vector<wxString>& GetDirectives() { return m_directives; }
|
||||
|
||||
|
@ -137,8 +137,7 @@ protected:
|
|||
virtual void WriteDirectives( const wxString& aSimCommand, unsigned aSimOptions,
|
||||
OUTPUTFORMATTER& candidate ) const;
|
||||
|
||||
virtual std::string GenerateItemPinNetName( const std::string& aNetName,
|
||||
int& aNcCounter ) const;
|
||||
virtual wxString GenerateItemPinNetName( const wxString& aNetName, int& aNcCounter ) const;
|
||||
|
||||
/**
|
||||
* Return the paths of exported sheets (either all or the current one).
|
||||
|
@ -167,11 +166,9 @@ private:
|
|||
SIM_LIB_MGR m_libMgr; ///< Holds libraries and models
|
||||
NAME_GENERATOR m_modelNameGenerator; ///< Generates unique model names
|
||||
|
||||
///< Generates unique net names (only unique for NC nets for now)
|
||||
NAME_GENERATOR m_netNameGenerator;
|
||||
std::vector<wxString> m_directives; ///< Spice directives found in the schematic sheet
|
||||
std::set<wxString> m_rawIncludes; ///< include directives found in symbols
|
||||
std::set<std::string> m_nets;
|
||||
std::set<wxString> m_nets;
|
||||
|
||||
///< Items representing schematic symbols in Spice world.
|
||||
std::list<SPICE_ITEM> m_items;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2022 Mikolaj Wielgus.
|
||||
* Copyright (C) 2022 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2022-2024 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
@ -24,7 +24,6 @@
|
|||
|
||||
#include "netlist_exporter_spice_model.h"
|
||||
#include <sch_screen.h>
|
||||
#include <sch_label.h>
|
||||
#include <string_utils.h>
|
||||
|
||||
|
||||
|
@ -37,22 +36,19 @@ void NETLIST_EXPORTER_SPICE_MODEL::WriteHead( OUTPUTFORMATTER& aFormatter,
|
|||
|
||||
for( auto const& [key, port] : m_ports )
|
||||
{
|
||||
std::string portDir;
|
||||
wxString portDir;
|
||||
|
||||
switch( port.dir )
|
||||
switch( port.m_dir )
|
||||
{
|
||||
case L_INPUT: portDir = "input"; break;
|
||||
case L_OUTPUT: portDir = "output"; break;
|
||||
case L_BIDI: portDir = "inout"; break;
|
||||
case L_TRISTATE: portDir = "tristate"; break;
|
||||
case L_UNSPECIFIED: portDir = "passive"; break;
|
||||
|
||||
default:
|
||||
wxFAIL_MSG( "Invalid port direction" );
|
||||
break;
|
||||
case L_INPUT: portDir = "input"; break;
|
||||
case L_OUTPUT: portDir = "output"; break;
|
||||
case L_BIDI: portDir = "inout"; break;
|
||||
case L_TRISTATE: portDir = "tristate"; break;
|
||||
case L_UNSPECIFIED: portDir = "passive"; break;
|
||||
default: wxFAIL_MSG( "Invalid port direction" ); break;
|
||||
}
|
||||
|
||||
aFormatter.Print( 0, "+ %s ; %s\n", port.name.c_str(), portDir.c_str() );
|
||||
aFormatter.Print( 0, "+ %s ; %s\n", TO_UTF8( port.m_name ), TO_UTF8( portDir ) );
|
||||
}
|
||||
|
||||
aFormatter.Print( 0, "\n\n" );
|
||||
|
@ -75,13 +71,13 @@ bool NETLIST_EXPORTER_SPICE_MODEL::ReadSchematicAndLibraries( unsigned aNetlistO
|
|||
}
|
||||
|
||||
|
||||
std::string NETLIST_EXPORTER_SPICE_MODEL::GenerateItemPinNetName( const std::string& aNetName,
|
||||
int& aNcCounter ) const
|
||||
wxString NETLIST_EXPORTER_SPICE_MODEL::GenerateItemPinNetName( const wxString& aNetName,
|
||||
int& aNcCounter ) const
|
||||
{
|
||||
std::string netName = aNetName;
|
||||
wxString netName = aNetName;
|
||||
|
||||
if( m_ports.count( netName ) )
|
||||
netName = m_ports.at( netName ).name;
|
||||
netName = m_ports.at( netName).m_name;
|
||||
|
||||
return NETLIST_EXPORTER_SPICE::GenerateItemPinNetName( netName, aNcCounter );
|
||||
}
|
||||
|
@ -98,10 +94,7 @@ void NETLIST_EXPORTER_SPICE_MODEL::readPorts( unsigned aNetlistOptions )
|
|||
if( SCH_CONNECTION* conn = label->Connection( &sheet ) )
|
||||
{
|
||||
wxString labelText = label->GetShownText( &sheet, false );
|
||||
m_ports.insert( {
|
||||
std::string( conn->Name().ToUTF8() ),
|
||||
PORT_INFO{ std::string( labelText.ToUTF8() ), label->GetShape() }
|
||||
} );
|
||||
m_ports.insert( { conn->Name(), PORT_INFO{ labelText, label->GetShape() } } );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,18 +42,18 @@ public:
|
|||
bool ReadSchematicAndLibraries( unsigned aNetlistOptions, REPORTER& aReporter ) override;
|
||||
|
||||
protected:
|
||||
std::string GenerateItemPinNetName( const std::string& aNetName, int& aNcCounter ) const override;
|
||||
wxString GenerateItemPinNetName( const wxString& aNetName, int& aNcCounter ) const override;
|
||||
|
||||
private:
|
||||
struct PORT_INFO
|
||||
{
|
||||
std::string name;
|
||||
LABEL_FLAG_SHAPE dir;
|
||||
wxString m_name;
|
||||
LABEL_FLAG_SHAPE m_dir;
|
||||
};
|
||||
|
||||
void readPorts( unsigned aNetlistOptions );
|
||||
|
||||
std::map<std::string, PORT_INFO> m_ports;
|
||||
std::map<wxString, PORT_INFO> m_ports;
|
||||
};
|
||||
|
||||
#endif // NETLIST_EXPORTER_SPICE_MODEL_H
|
||||
|
|
|
@ -706,10 +706,10 @@ void SCHEMATIC::RecomputeIntersheetRefs( const std::function<void( SCH_GLOBALLAB
|
|||
wxString SCHEMATIC::GetOperatingPoint( const wxString& aNetName, int aPrecision,
|
||||
const wxString& aRange )
|
||||
{
|
||||
std::string spiceNetName( aNetName.Lower().ToStdString() );
|
||||
NETLIST_EXPORTER_SPICE::ConvertToSpiceMarkup( spiceNetName );
|
||||
wxString spiceNetName( aNetName.Lower() );
|
||||
NETLIST_EXPORTER_SPICE::ConvertToSpiceMarkup( &spiceNetName );
|
||||
|
||||
if( spiceNetName == "gnd" || spiceNetName == "0" )
|
||||
if( spiceNetName == wxS( "gnd" ) || spiceNetName == wxS( "0" ) )
|
||||
return wxEmptyString;
|
||||
|
||||
auto it = m_operatingPoints.find( spiceNetName );
|
||||
|
|
|
@ -884,10 +884,11 @@ void SIMULATOR_FRAME_UI::rebuildSignalsList()
|
|||
if( ( options & NETLIST_EXPORTER_SPICE::OPTION_SAVE_ALL_VOLTAGES )
|
||||
&& ( simType == ST_TRAN || simType == ST_DC || simType == ST_AC || simType == ST_FFT) )
|
||||
{
|
||||
for( const std::string& net : circuitModel()->GetNets() )
|
||||
for( const wxString& net : circuitModel()->GetNets() )
|
||||
{
|
||||
// netnames are escaped (can contain "{slash}" for '/') Unscape them:
|
||||
wxString netname = UnescapeString( net );
|
||||
NETLIST_EXPORTER_SPICE::ConvertToSpiceMarkup( &netname );
|
||||
|
||||
if( netname == "GND" || netname == "0" || netname.StartsWith( unconnected ) )
|
||||
continue;
|
||||
|
@ -1425,7 +1426,7 @@ void SIMULATOR_FRAME_UI::AddTuner( const SCH_SHEET_PATH& aSheetPath, SCH_SYMBOL*
|
|||
return;
|
||||
}
|
||||
|
||||
const SPICE_ITEM* item = GetExporter()->FindItem( std::string( ref.ToUTF8() ) );
|
||||
const SPICE_ITEM* item = GetExporter()->FindItem( ref );
|
||||
|
||||
// Do nothing if the symbol is not tunable.
|
||||
if( !item || !item->model->GetTunerParam() )
|
||||
|
@ -1874,7 +1875,7 @@ void SIMULATOR_FRAME_UI::applyTuners()
|
|||
continue;
|
||||
}
|
||||
|
||||
const SPICE_ITEM* item = GetExporter()->FindItem( tuner->GetSymbolRef().ToStdString() );
|
||||
const SPICE_ITEM* item = GetExporter()->FindItem( tuner->GetSymbolRef() );
|
||||
|
||||
if( !item || !item->model->GetTunerParam() )
|
||||
{
|
||||
|
|
|
@ -618,8 +618,8 @@ int SCH_EDITOR_CONTROL::SimProbe( const TOOL_EVENT& aEvent )
|
|||
{
|
||||
if( SCH_CONNECTION* conn = static_cast<SCH_ITEM*>( item )->Connection() )
|
||||
{
|
||||
std::string spiceNet = UnescapeString( conn->Name() ).ToStdString();
|
||||
NETLIST_EXPORTER_SPICE::ConvertToSpiceMarkup( spiceNet );
|
||||
wxString spiceNet = UnescapeString( conn->Name() );
|
||||
NETLIST_EXPORTER_SPICE::ConvertToSpiceMarkup( &spiceNet );
|
||||
|
||||
simFrame->AddVoltageTrace( wxString::Format( "V(%s)", spiceNet ) );
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@ TUNER_SLIDER::TUNER_SLIDER( SIMULATOR_FRAME_UI* aFrame, wxWindow* aParent,
|
|||
m_value( 0.0 ),
|
||||
m_frame( aFrame )
|
||||
{
|
||||
const SPICE_ITEM* item = m_frame->GetExporter()->FindItem( std::string( m_ref.ToUTF8() ) );
|
||||
const SPICE_ITEM* item = m_frame->GetExporter()->FindItem( m_ref );
|
||||
|
||||
if( !item )
|
||||
throw KI_PARAM_ERROR( wxString::Format( _( "%s not found" ), m_ref ) );
|
||||
|
|
Loading…
Reference in New Issue