diff --git a/eeschema/dialogs/dialog_sim_command.cpp b/eeschema/dialogs/dialog_sim_command.cpp index 164a79d22f..4af6e4ac92 100644 --- a/eeschema/dialogs/dialog_sim_command.cpp +++ b/eeschema/dialogs/dialog_sim_command.cpp @@ -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, diff --git a/eeschema/netlist_exporters/netlist_exporter_spice.cpp b/eeschema/netlist_exporters/netlist_exporter_spice.cpp index cce018af9f..05135dc24c 100644 --- a/eeschema/netlist_exporters/netlist_exporter_spice.cpp +++ b/eeschema/netlist_exporters/netlist_exporter_spice.cpp @@ -3,7 +3,7 @@ * * Copyright (C) 1992-2013 jp.charras at wanadoo.fr * Copyright (C) 2013 SoftPLC Corporation, Dick Hollenbeck - * 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 root = markupParser.Parse(); - std::string converted; std::function&)> convertMarkup = [&]( const std::unique_ptr& 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& 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& 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& 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; } diff --git a/eeschema/netlist_exporters/netlist_exporter_spice.h b/eeschema/netlist_exporters/netlist_exporter_spice.h index d437536628..814e4f1da9 100644 --- a/eeschema/netlist_exporters/netlist_exporter_spice.h +++ b/eeschema/netlist_exporters/netlist_exporter_spice.h @@ -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 GetNets() const { return m_nets; } + std::set 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& 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 m_directives; ///< Spice directives found in the schematic sheet std::set m_rawIncludes; ///< include directives found in symbols - std::set m_nets; + std::set m_nets; ///< Items representing schematic symbols in Spice world. std::list m_items; diff --git a/eeschema/netlist_exporters/netlist_exporter_spice_model.cpp b/eeschema/netlist_exporters/netlist_exporter_spice_model.cpp index ffff200043..49bad7dbd5 100644 --- a/eeschema/netlist_exporters/netlist_exporter_spice_model.cpp +++ b/eeschema/netlist_exporters/netlist_exporter_spice_model.cpp @@ -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 -#include #include @@ -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() } } ); } } } diff --git a/eeschema/netlist_exporters/netlist_exporter_spice_model.h b/eeschema/netlist_exporters/netlist_exporter_spice_model.h index 80492cc295..bb3aeb7b51 100644 --- a/eeschema/netlist_exporters/netlist_exporter_spice_model.h +++ b/eeschema/netlist_exporters/netlist_exporter_spice_model.h @@ -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 m_ports; + std::map m_ports; }; #endif // NETLIST_EXPORTER_SPICE_MODEL_H diff --git a/eeschema/schematic.cpp b/eeschema/schematic.cpp index b1853c1632..0eb08b6b4c 100644 --- a/eeschema/schematic.cpp +++ b/eeschema/schematic.cpp @@ -706,10 +706,10 @@ void SCHEMATIC::RecomputeIntersheetRefs( const std::functionGetNets() ) + 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() ) { diff --git a/eeschema/tools/sch_editor_control.cpp b/eeschema/tools/sch_editor_control.cpp index c537c5d1ed..3602026099 100644 --- a/eeschema/tools/sch_editor_control.cpp +++ b/eeschema/tools/sch_editor_control.cpp @@ -618,8 +618,8 @@ int SCH_EDITOR_CONTROL::SimProbe( const TOOL_EVENT& aEvent ) { if( SCH_CONNECTION* conn = static_cast( 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 ) ); } diff --git a/eeschema/widgets/tuner_slider.cpp b/eeschema/widgets/tuner_slider.cpp index e312d97986..71818281a7 100644 --- a/eeschema/widgets/tuner_slider.cpp +++ b/eeschema/widgets/tuner_slider.cpp @@ -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 ) );