From 300a1c41446fe9607c5b44557c50bd110501f165 Mon Sep 17 00:00:00 2001 From: Mikolaj Wielgus Date: Fri, 9 Sep 2022 15:34:56 +0200 Subject: [PATCH] Add a new schematic exporter to Spice .subckt model An option to use the current sheet as root is added to both the original and new (.subckt model) exporters. --- eeschema/CMakeLists.txt | 1 + eeschema/dialogs/dialog_netlist.cpp | 62 +++++++++--- eeschema/dialogs/dialog_sim_settings.cpp | 2 +- eeschema/netlist_exporters/netlist.h | 1 + .../netlist_exporter_spice.cpp | 92 ++++++++++++------ .../netlist_exporter_spice.h | 95 +++++++++++-------- .../netlist_exporters/netlist_generator.cpp | 5 + eeschema/schematic_settings.cpp | 2 + eeschema/schematic_settings.h | 3 + eeschema/sim/ngspice_helpers.h | 2 +- eeschema/sim/sim_plot_frame.cpp | 5 +- 11 files changed, 186 insertions(+), 84 deletions(-) diff --git a/eeschema/CMakeLists.txt b/eeschema/CMakeLists.txt index 4c6b9a59f9..4c686b7708 100644 --- a/eeschema/CMakeLists.txt +++ b/eeschema/CMakeLists.txt @@ -259,6 +259,7 @@ set( EESCHEMA_SRCS netlist_exporters/netlist_exporter_kicad.cpp netlist_exporters/netlist_exporter_orcadpcb2.cpp netlist_exporters/netlist_exporter_spice.cpp + netlist_exporters/netlist_exporter_spice_model.cpp netlist_exporters/netlist_exporter_xml.cpp netlist_exporters/netlist_generator.cpp diff --git a/eeschema/dialogs/dialog_netlist.cpp b/eeschema/dialogs/dialog_netlist.cpp index a64c112b7c..f93ab93c08 100644 --- a/eeschema/dialogs/dialog_netlist.cpp +++ b/eeschema/dialogs/dialog_netlist.cpp @@ -63,7 +63,8 @@ enum panel_netlist_index { PANELPCBNEW = 0, /* Handle Netlist format Pcbnew */ PANELORCADPCB2, /* Handle Netlist format OracdPcb2 */ PANELCADSTAR, /* Handle Netlist format CadStar */ - PANELSPICE, /* Handle Netlist format Pspice */ + PANELSPICE, /* Handle Netlist format Spice */ + PANELSPICEMODEL, /* Handle Netlist format Spice Model (subcircuit) */ PANELCUSTOMBASE /* First auxiliary panel (custom netlists). * others use PANELCUSTOMBASE+1, PANELCUSTOMBASE+2.. */ }; @@ -94,6 +95,7 @@ public: NETLIST_TYPE_ID m_IdNetType; // opt to reformat passive component values (e.g. 1M -> 1Meg): + wxCheckBox* m_CurSheetAsRoot; wxCheckBox* m_SaveAllVoltages; wxCheckBox* m_SaveAllCurrents; wxTextCtrl* m_CommandStringCtrl; @@ -127,6 +129,8 @@ private: const wxString & aCommandString, NETLIST_TYPE_ID aNetTypeId ); void InstallPageSpice(); + void InstallPageSpiceModel(); + bool TransferDataFromWindow() override; void NetlistUpdateOpt(); @@ -175,7 +179,7 @@ private: public: SCH_EDIT_FRAME* m_Parent; - NETLIST_PAGE_DIALOG* m_PanelNetType[4 + CUSTOMPANEL_COUNTMAX]; + NETLIST_PAGE_DIALOG* m_PanelNetType[5 + CUSTOMPANEL_COUNTMAX]; }; @@ -202,6 +206,7 @@ private: /* Event id for notebook page buttons: */ enum id_netlist { ID_CREATE_NETLIST = ID_END_EESCHEMA_ID_LIST + 1, + ID_CUR_SHEET_AS_ROOT, ID_SAVE_ALL_VOLTAGES, ID_SAVE_ALL_CURRENTS, ID_RUN_SIMULATOR @@ -265,6 +270,7 @@ NETLIST_DIALOG::NETLIST_DIALOG( SCH_EDIT_FRAME* parent ) : new NETLIST_PAGE_DIALOG( m_NoteBook, wxT( "CadStar" ), NET_TYPE_CADSTAR, false ); InstallPageSpice(); + InstallPageSpiceModel(); InstallCustomPages(); SetupStandardButtons( { { wxID_OK, _( "Export Netlist" ) }, @@ -334,21 +340,27 @@ void NETLIST_DIALOG::OnRunSpiceButtUI( wxUpdateUIEvent& aEvent ) void NETLIST_DIALOG::InstallPageSpice() { NETLIST_PAGE_DIALOG* page = m_PanelNetType[PANELSPICE] = - new NETLIST_PAGE_DIALOG( m_NoteBook, wxT( "Spice" ), NET_TYPE_SPICE, false ); + new NETLIST_PAGE_DIALOG( m_NoteBook, wxT( "Spice" ), NET_TYPE_SPICE, false ); SCHEMATIC_SETTINGS& settings = m_Parent->Schematic().Settings(); + page->m_CurSheetAsRoot = new wxCheckBox( page, ID_CUR_SHEET_AS_ROOT, + _( "Use current sheet as root" ) ); + page->m_CurSheetAsRoot->SetToolTip( _( "Export netlist only for the current sheet" ) ); + page->m_CurSheetAsRoot->SetValue( settings.m_SpiceCurSheetAsRoot ); + page->m_LeftBoxSizer->Add( page->m_CurSheetAsRoot, 0, wxGROW | wxBOTTOM | wxRIGHT, 5 ); + page->m_SaveAllVoltages = new wxCheckBox( page, ID_SAVE_ALL_VOLTAGES, _( "Save all voltages" ) ); page->m_SaveAllVoltages->SetToolTip( _( "Write a directive to save all voltages (.save all)" ) ); page->m_SaveAllVoltages->SetValue( settings.m_SpiceSaveAllVoltages ); - page->m_LeftBoxSizer->Add( page->m_SaveAllVoltages, 0, wxGROW | wxBOTTOM | wxRIGHT, 5 ); + page->m_RightBoxSizer->Add( page->m_SaveAllVoltages, 0, wxBOTTOM | wxRIGHT, 5 ); page->m_SaveAllCurrents = new wxCheckBox( page, ID_SAVE_ALL_CURRENTS, _( "Save all currents" ) ); page->m_SaveAllCurrents->SetToolTip( _( "Write a directive to save all currents (.probe alli)" ) ); page->m_SaveAllCurrents->SetValue( settings.m_SpiceSaveAllCurrents ); - page->m_RightBoxSizer->Add( page->m_SaveAllCurrents, 0, wxGROW | wxBOTTOM | wxLEFT, 5 ); + page->m_RightBoxSizer->Add( page->m_SaveAllCurrents, 0, wxBOTTOM | wxRIGHT, 5 ); wxString simulatorCommand = settings.m_SpiceCommandString; @@ -372,6 +384,21 @@ void NETLIST_DIALOG::InstallPageSpice() } +void NETLIST_DIALOG::InstallPageSpiceModel() +{ + NETLIST_PAGE_DIALOG* page = m_PanelNetType[PANELSPICEMODEL] = + new NETLIST_PAGE_DIALOG( m_NoteBook, wxT( "Spice Model" ), NET_TYPE_SPICE_MODEL, false ); + + SCHEMATIC_SETTINGS& settings = m_Parent->Schematic().Settings(); + + page->m_CurSheetAsRoot = new wxCheckBox( page, ID_CUR_SHEET_AS_ROOT, + _( "Use current sheet as root" ) ); + page->m_CurSheetAsRoot->SetToolTip( _( "Export netlist only for the current sheet" ) ); + page->m_CurSheetAsRoot->SetValue( settings.m_SpiceModelCurSheetAsRoot ); + page->m_LeftBoxSizer->Add( page->m_CurSheetAsRoot, 0, wxGROW | wxBOTTOM | wxRIGHT, 5 ); +} + + void NETLIST_DIALOG::InstallCustomPages() { NETLIST_PAGE_DIALOG* currPage; @@ -440,16 +467,20 @@ void NETLIST_DIALOG::OnNetlistTypeSelection( wxNotebookEvent& event ) void NETLIST_DIALOG::NetlistUpdateOpt() { - bool saveAllVoltages = m_PanelNetType[ PANELSPICE ]->m_SaveAllVoltages->IsChecked(); - bool saveAllCurrents = m_PanelNetType[ PANELSPICE ]->m_SaveAllCurrents->IsChecked(); - wxString spice_cmd_string = m_PanelNetType[ PANELSPICE ]->m_CommandStringCtrl->GetValue(); + bool saveAllVoltages = m_PanelNetType[ PANELSPICE ]->m_SaveAllVoltages->IsChecked(); + bool saveAllCurrents = m_PanelNetType[ PANELSPICE ]->m_SaveAllCurrents->IsChecked(); + wxString spiceCmdString = m_PanelNetType[ PANELSPICE ]->m_CommandStringCtrl->GetValue(); + bool curSheetAsRoot = m_PanelNetType[ PANELSPICE ]->m_CurSheetAsRoot->GetValue(); + bool spiceModelCurSheetAsRoot = m_PanelNetType[ PANELSPICEMODEL ]->m_CurSheetAsRoot->GetValue(); SCHEMATIC_SETTINGS& settings = m_Parent->Schematic().Settings(); - settings.m_SpiceSaveAllVoltages = saveAllVoltages; - settings.m_SpiceSaveAllCurrents = saveAllCurrents; - settings.m_SpiceCommandString = spice_cmd_string; - settings.m_NetFormatName = m_PanelNetType[m_NoteBook->GetSelection()]->GetPageNetFmtName(); + settings.m_SpiceSaveAllVoltages = saveAllVoltages; + settings.m_SpiceSaveAllCurrents = saveAllCurrents; + settings.m_SpiceCommandString = spiceCmdString; + settings.m_SpiceCurSheetAsRoot = curSheetAsRoot; + settings.m_SpiceModelCurSheetAsRoot = spiceModelCurSheetAsRoot; + settings.m_NetFormatName = m_PanelNetType[m_NoteBook->GetSelection()]->GetPageNetFmtName(); } @@ -480,6 +511,13 @@ bool NETLIST_DIALOG::TransferDataFromWindow() netlist_opt |= NETLIST_EXPORTER_SPICE::OPTION_SAVE_ALL_VOLTAGES; if( currPage->m_SaveAllCurrents->GetValue() ) netlist_opt |= NETLIST_EXPORTER_SPICE::OPTION_SAVE_ALL_CURRENTS; + if( currPage->m_CurSheetAsRoot->GetValue() ) + netlist_opt |= NETLIST_EXPORTER_SPICE::OPTION_CUR_SHEET_AS_ROOT; + break; + + case NET_TYPE_SPICE_MODEL: + if( currPage->m_CurSheetAsRoot->GetValue() ) + netlist_opt |= NETLIST_EXPORTER_SPICE::OPTION_CUR_SHEET_AS_ROOT; break; case NET_TYPE_CADSTAR: diff --git a/eeschema/dialogs/dialog_sim_settings.cpp b/eeschema/dialogs/dialog_sim_settings.cpp index 339e70c844..f2da1ef1f4 100644 --- a/eeschema/dialogs/dialog_sim_settings.cpp +++ b/eeschema/dialogs/dialog_sim_settings.cpp @@ -611,7 +611,7 @@ void DIALOG_SIM_SETTINGS::loadDirectives() void DIALOG_SIM_SETTINGS::updateNetlistOpts() { - m_netlistOpts = NETLIST_EXPORTER_SPICE::OPTION_ALL_FLAGS; + m_netlistOpts = NETLIST_EXPORTER_SPICE::OPTION_DEFAULT_FLAGS; if( !m_fixPassiveVals->IsChecked() ) m_netlistOpts &= ~NETLIST_EXPORTER_SPICE::OPTION_ADJUST_PASSIVE_VALS; diff --git a/eeschema/netlist_exporters/netlist.h b/eeschema/netlist_exporters/netlist.h index 6556ee1729..872eaba8d0 100644 --- a/eeschema/netlist_exporters/netlist.h +++ b/eeschema/netlist_exporters/netlist.h @@ -39,6 +39,7 @@ enum NETLIST_TYPE_ID { NET_TYPE_ORCADPCB2, NET_TYPE_CADSTAR, NET_TYPE_SPICE, + NET_TYPE_SPICE_MODEL, NET_TYPE_CUSTOM1, /* NET_TYPE_CUSTOM1 * is the first id for user netlist format * NET_TYPE_CUSTOM1+CUSTOMPANEL_COUNTMAX-1 diff --git a/eeschema/netlist_exporters/netlist_exporter_spice.cpp b/eeschema/netlist_exporters/netlist_exporter_spice.cpp index b17ca677c9..43b813198e 100644 --- a/eeschema/netlist_exporters/netlist_exporter_spice.cpp +++ b/eeschema/netlist_exporters/netlist_exporter_spice.cpp @@ -68,11 +68,11 @@ namespace NETLIST_EXPORTER_SPICE_PARSER bool NETLIST_EXPORTER_SPICE::WriteNetlist( const wxString& aOutFileName, unsigned aNetlistOptions ) { FILE_OUTPUTFORMATTER formatter( aOutFileName, wxT( "wt" ), '\'' ); - return GenerateNetlist( formatter, aNetlistOptions ); + return DoWriteNetlist( formatter, aNetlistOptions ); } -bool NETLIST_EXPORTER_SPICE::GenerateNetlist( OUTPUTFORMATTER& aFormatter, unsigned aNetlistOptions ) +bool NETLIST_EXPORTER_SPICE::DoWriteNetlist( OUTPUTFORMATTER& aFormatter, unsigned aNetlistOptions ) { LOCALE_IO dummy; @@ -85,34 +85,44 @@ bool NETLIST_EXPORTER_SPICE::GenerateNetlist( OUTPUTFORMATTER& aFormatter, unsig if( !ReadSchematicAndLibraries( aNetlistOptions ) ) return false; - aFormatter.Print( 0, ".title %s\n", TO_UTF8( m_title ) ); + WriteHead( aFormatter, aNetlistOptions ); writeIncludes( aFormatter, aNetlistOptions ); writeModels( aFormatter ); WriteDirectives( aFormatter, aNetlistOptions ); writeItems( aFormatter ); - aFormatter.Print( 0, ".end\n" ); + WriteTail( aFormatter, aNetlistOptions ); return true; } +void NETLIST_EXPORTER_SPICE::WriteHead( OUTPUTFORMATTER& aFormatter, unsigned aNetlistOptions ) +{ + aFormatter.Print( 0, ".title %s\n", TO_UTF8( m_title ) ); +} + + +void NETLIST_EXPORTER_SPICE::WriteTail( OUTPUTFORMATTER& aFormatter, unsigned aNetlistOptions ) +{ + aFormatter.Print( 0, ".end\n" ); +} + + bool NETLIST_EXPORTER_SPICE::ReadSchematicAndLibraries( unsigned aNetlistOptions ) { std::set refNames; // Set of reference names to check for duplication. - int NCCounter = 1; + int ncCounter = 1; - ReadDirectives(); + ReadDirectives( aNetlistOptions ); m_nets.clear(); m_items.clear(); m_libParts.clear(); - for( unsigned sheetIndex = 0; sheetIndex < m_schematic->GetSheets().size(); ++sheetIndex ) + for( SCH_SHEET_PATH& sheet : GetSheets( aNetlistOptions ) ) { - SCH_SHEET_PATH sheet = m_schematic->GetSheets().at( sheetIndex ); - for( SCH_ITEM* item : sheet.LastScreen()->Items().OfType( SCH_SYMBOL_T ) ) { SCH_SYMBOL* symbol = findNextSymbol( item, &sheet ); @@ -122,7 +132,7 @@ bool NETLIST_EXPORTER_SPICE::ReadSchematicAndLibraries( unsigned aNetlistOptions CreatePinList( symbol, &sheet, true ); - SPICE_ITEM spiceItem; + ITEM spiceItem; if( !readRefName( sheet, *symbol, spiceItem, refNames ) ) return false; @@ -134,7 +144,7 @@ bool NETLIST_EXPORTER_SPICE::ReadSchematicAndLibraries( unsigned aNetlistOptions continue; readPinNumbers( *symbol, spiceItem ); - readPinNetNames( *symbol, spiceItem, NCCounter ); + readPinNetNames( *symbol, spiceItem, ncCounter ); // TODO: transmission line handling? @@ -156,10 +166,10 @@ void NETLIST_EXPORTER_SPICE::ReplaceForbiddenChars( wxString& aNetName ) wxString NETLIST_EXPORTER_SPICE::GetItemName( const wxString& aRefName ) const { - const std::list& spiceItems = GetItems(); + const std::list& spiceItems = GetItems(); auto it = std::find_if( spiceItems.begin(), spiceItems.end(), - [aRefName]( const SPICE_ITEM& aItem ) + [aRefName]( const ITEM& aItem ) { return aItem.refName == aRefName; } ); @@ -171,13 +181,13 @@ wxString NETLIST_EXPORTER_SPICE::GetItemName( const wxString& aRefName ) const } -void NETLIST_EXPORTER_SPICE::ReadDirectives() +void NETLIST_EXPORTER_SPICE::ReadDirectives( unsigned aNetlistOptions ) { m_directives.clear(); - for( unsigned int sheetIndex = 0; sheetIndex < m_schematic->GetSheets().size(); ++sheetIndex ) + for( const SCH_SHEET_PATH& sheet : GetSheets( aNetlistOptions ) ) { - for( SCH_ITEM* item : m_schematic->GetSheets().at( sheetIndex ).LastScreen()->Items() ) + for( SCH_ITEM* item : sheet.LastScreen()->Items() ) { wxString text; @@ -233,7 +243,7 @@ void NETLIST_EXPORTER_SPICE::ReadDirectives() } -void NETLIST_EXPORTER_SPICE::readLibraryField( SCH_SYMBOL& aSymbol, SPICE_ITEM& aItem ) +void NETLIST_EXPORTER_SPICE::readLibraryField( SCH_SYMBOL& aSymbol, ITEM& aItem ) { SCH_FIELD* field = aSymbol.FindField( SIM_LIBRARY::LIBRARY_FIELD ); wxString path; @@ -261,7 +271,7 @@ void NETLIST_EXPORTER_SPICE::readLibraryField( SCH_SYMBOL& aSymbol, SPICE_ITEM& } -void NETLIST_EXPORTER_SPICE::readNameField( SCH_SYMBOL& aSymbol, SPICE_ITEM& aItem ) +void NETLIST_EXPORTER_SPICE::readNameField( SCH_SYMBOL& aSymbol, ITEM& aItem ) { if( m_libraries.count( aItem.libraryPath ) ) { @@ -300,7 +310,7 @@ void NETLIST_EXPORTER_SPICE::readNameField( SCH_SYMBOL& aSymbol, SPICE_ITEM& aIt bool NETLIST_EXPORTER_SPICE::readRefName( SCH_SHEET_PATH& aSheet, SCH_SYMBOL& aSymbol, - SPICE_ITEM& aItem, + ITEM& aItem, std::set& aRefNames ) { aItem.refName = aSymbol.GetRef( &aSheet ); @@ -318,7 +328,7 @@ bool NETLIST_EXPORTER_SPICE::readRefName( SCH_SHEET_PATH& aSheet, SCH_SYMBOL& aS } -bool NETLIST_EXPORTER_SPICE::readModel( SCH_SYMBOL& aSymbol, SPICE_ITEM& aItem ) +bool NETLIST_EXPORTER_SPICE::readModel( SCH_SYMBOL& aSymbol, ITEM& aItem ) { if( !aItem.model.get() ) { @@ -350,24 +360,19 @@ bool NETLIST_EXPORTER_SPICE::readModel( SCH_SYMBOL& aSymbol, SPICE_ITEM& aItem ) } -void NETLIST_EXPORTER_SPICE::readPinNumbers( SCH_SYMBOL& aSymbol, SPICE_ITEM& aItem ) +void NETLIST_EXPORTER_SPICE::readPinNumbers( SCH_SYMBOL& aSymbol, ITEM& aItem ) { for( const PIN_INFO& pin : m_sortedSymbolPinList ) aItem.pinNumbers.push_back( pin.num ); } -void NETLIST_EXPORTER_SPICE::readPinNetNames( SCH_SYMBOL& aSymbol, SPICE_ITEM& aItem, - int& aNCCounter ) +void NETLIST_EXPORTER_SPICE::readPinNetNames( SCH_SYMBOL& aSymbol, ITEM& aItem, + int& aNcCounter ) { for( const PIN_INFO& pinInfo : m_sortedSymbolPinList ) { - wxString netName = pinInfo.netName; - ReplaceForbiddenChars( netName ); - netName = UnescapeString( netName ); - - if( netName == "" ) - netName = wxString::Format( wxT( "NC-%u" ), aNCCounter++ ); + wxString netName = GenerateItemPinNetName( pinInfo.netName, aNcCounter ); aItem.pinNetNames.push_back( netName ); m_nets.insert( netName ); @@ -415,7 +420,7 @@ void NETLIST_EXPORTER_SPICE::writeIncludes( OUTPUTFORMATTER& aFormatter, unsigne void NETLIST_EXPORTER_SPICE::writeModels( OUTPUTFORMATTER& aFormatter ) { - for( const SPICE_ITEM& item : m_items ) + for( const ITEM& item : m_items ) { if( !item.model->IsEnabled() ) continue; @@ -427,7 +432,7 @@ void NETLIST_EXPORTER_SPICE::writeModels( OUTPUTFORMATTER& aFormatter ) void NETLIST_EXPORTER_SPICE::writeItems( OUTPUTFORMATTER& aFormatter ) { - for( const SPICE_ITEM& item : m_items ) + for( const ITEM& item : m_items ) { if( !item.model->IsEnabled() ) continue; @@ -453,3 +458,28 @@ void NETLIST_EXPORTER_SPICE::WriteDirectives( OUTPUTFORMATTER& aFormatter, for( const wxString& directive : m_directives ) aFormatter.Print( 0, "%s\n", TO_UTF8( directive ) ); } + + +wxString NETLIST_EXPORTER_SPICE::GenerateItemPinNetName( const wxString& aNetName, + int& aNcCounter ) const +{ + wxString netName = aNetName; + + ReplaceForbiddenChars( netName ); + netName = UnescapeString( netName ); + + if( netName == "" ) + netName = wxString::Format( wxT( "NC-%u" ), aNcCounter++ ); + + return netName; +} + + +SCH_SHEET_LIST NETLIST_EXPORTER_SPICE::GetSheets( unsigned aNetlistOptions ) const +{ + if( aNetlistOptions & OPTION_CUR_SHEET_AS_ROOT ) + return SCH_SHEET_LIST( m_schematic->CurrentSheet().at( 0 ) ); + else + return m_schematic->GetSheets(); +} + diff --git a/eeschema/netlist_exporters/netlist_exporter_spice.h b/eeschema/netlist_exporters/netlist_exporter_spice.h index 13f93772a5..a0ac49c080 100644 --- a/eeschema/netlist_exporters/netlist_exporter_spice.h +++ b/eeschema/netlist_exporters/netlist_exporter_spice.h @@ -23,35 +23,38 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ -#ifndef NETLIST_EXPORTER_PSPICE_H -#define NETLIST_EXPORTER_PSPICE_H +#ifndef NETLIST_EXPORTER_SPICE_H +#define NETLIST_EXPORTER_SPICE_H #include "netlist_exporter_base.h" #include #include -struct SPICE_ITEM -{ - wxString refName; - wxString libraryPath; - std::vector pinNumbers; - std::vector pinNetNames; - std::unique_ptr model; - wxString modelName; -}; - - class NETLIST_EXPORTER_SPICE : public NETLIST_EXPORTER_BASE { public: enum OPTIONS { - OPTION_ADJUST_INCLUDE_PATHS = 8, - OPTION_ADJUST_PASSIVE_VALS = 16, - OPTION_SAVE_ALL_VOLTAGES = 16, - OPTION_SAVE_ALL_CURRENTS = 32, - OPTION_ALL_FLAGS = 0xFFFF + OPTION_ADJUST_INCLUDE_PATHS = 0x10, + OPTION_ADJUST_PASSIVE_VALS = 0x20, + OPTION_SAVE_ALL_VOLTAGES = 0x40, + OPTION_SAVE_ALL_CURRENTS = 0x80, + OPTION_CUR_SHEET_AS_ROOT = 0x0100, + OPTION_DEFAULT_FLAGS = OPTION_ADJUST_INCLUDE_PATHS + | OPTION_ADJUST_PASSIVE_VALS + | OPTION_SAVE_ALL_VOLTAGES + | OPTION_SAVE_ALL_CURRENTS + }; + + struct ITEM + { + wxString refName; + wxString libraryPath; + std::vector pinNumbers; + std::vector pinNetNames; + std::unique_ptr model; + wxString modelName; }; NETLIST_EXPORTER_SPICE( SCHEMATIC_IFACE* aSchematic ) : NETLIST_EXPORTER_BASE( aSchematic ) {} @@ -62,9 +65,19 @@ public: bool WriteNetlist( const wxString& aOutFileName, unsigned aNetlistOptions ) override; /** - * Generate the netlist in aFormatter. + * Write the netlist in aFormatter. */ - bool GenerateNetlist( OUTPUTFORMATTER& aFormatter, unsigned aNetlistOptions ); + bool DoWriteNetlist( OUTPUTFORMATTER& aFormatter, unsigned aNetlistOptions ); + + /** + * Write the netlist head (title and so on). + */ + virtual void WriteHead( OUTPUTFORMATTER& aFormatter, unsigned aNetlistOptions ); + + /** + * Write the tail (.end). + */ + virtual void WriteTail( OUTPUTFORMATTER& aFormatter, unsigned aNetlistOptions ); /** * Process the schematic and Spice libraries to create net mapping and a list of SPICE_ITEMs. @@ -72,7 +85,7 @@ public: * if only net mapping and the list of SPICE_ITEMs are required. * @return True if successful. */ - bool ReadSchematicAndLibraries( unsigned aNetlistOptions ); + virtual bool ReadSchematicAndLibraries( unsigned aNetlistOptions ); /** * Replace illegal spice net name characters with underscores. @@ -82,7 +95,8 @@ public: /** * Return the list of nets. */ - const std::set& GetNets() const { return m_nets; } + std::set GetNets() const { return m_nets; } + /** * Return name of Spice device corresponding to a schematic symbol. @@ -98,23 +112,30 @@ public: /** * Return the list of items representing schematic components in the Spice world. */ - const std::list& GetItems() const { return m_items; } + const std::list& GetItems() const { return m_items; } const std::vector& GetDirectives() { return m_directives; } protected: - void ReadDirectives(); + void ReadDirectives( unsigned aNetlistOptions = 0 ); virtual void WriteDirectives( OUTPUTFORMATTER& aFormatter, unsigned aNetlistOptions ) const; + virtual wxString GenerateItemPinNetName( const wxString& aNetName, int& aNcCounter ) const; + + /** + * Return the paths of exported sheets (either all or the current one). + */ + SCH_SHEET_LIST GetSheets( unsigned aNetlistOptions = 0 ) const; + private: - void readLibraryField( SCH_SYMBOL& aSymbol, SPICE_ITEM& aItem ); - void readNameField( SCH_SYMBOL& aSymbol, SPICE_ITEM& aItem ); - void readEnabledField( SCH_SYMBOL& aSymbol, SPICE_ITEM& aItem ); - bool readRefName( SCH_SHEET_PATH& aSheet, SCH_SYMBOL& aSymbol, SPICE_ITEM& aItem, + void readLibraryField( SCH_SYMBOL& aSymbol, ITEM& aItem ); + void readNameField( SCH_SYMBOL& aSymbol, ITEM& aItem ); + void readEnabledField( SCH_SYMBOL& aSymbol, ITEM& aItem ); + bool readRefName( SCH_SHEET_PATH& aSheet, SCH_SYMBOL& aSymbol, ITEM& aItem, std::set& aRefNames ); - bool readModel( SCH_SYMBOL& aSymbol, SPICE_ITEM& aItem ); - void readPinNumbers( SCH_SYMBOL& aSymbol, SPICE_ITEM& aItem ); - void readPinNetNames( SCH_SYMBOL& aSymbol, SPICE_ITEM& aItem, int& aNCCounter ); + bool readModel( SCH_SYMBOL& aSymbol, ITEM& aItem ); + void readPinNumbers( SCH_SYMBOL& aSymbol, ITEM& aItem ); + void readPinNetNames( SCH_SYMBOL& aSymbol, ITEM& aItem, int& aNcCounter ); void writeInclude( OUTPUTFORMATTER& aFormatter, unsigned aNetlistOptions, const wxString& aPath ); @@ -123,13 +144,13 @@ private: void writeModels( OUTPUTFORMATTER& aFormatter ); void writeItems( OUTPUTFORMATTER& aFormatter ); - wxString m_title; ///< Spice simulation title found in the schematic sheet - std::vector m_directives; ///< Spice directives found in the schematic sheet + wxString m_title; ///< Spice simulation title found in the schematic sheet + std::vector m_directives; ///< Spice directives found in the schematic sheet std::map> m_libraries; ///< Spice libraries - std::set m_rawIncludes; ///< include directives found in symbols - std::set m_nets; - std::list m_items; ///< Items representing schematic symbols in Spice world + std::set m_rawIncludes; ///< include directives found in symbols + std::set m_nets; + std::list m_items; ///< Items representing schematic symbols in Spice world }; -#endif // NETLIST_EXPORTER_PSPICE_H +#endif // NETLIST_EXPORTER_SPICE_H diff --git a/eeschema/netlist_exporters/netlist_generator.cpp b/eeschema/netlist_exporters/netlist_generator.cpp index 9b1a6b1d16..0113b7281b 100644 --- a/eeschema/netlist_exporters/netlist_generator.cpp +++ b/eeschema/netlist_exporters/netlist_generator.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include #include @@ -81,6 +82,10 @@ bool SCH_EDIT_FRAME::WriteNetListFile( int aFormat, const wxString& aFullFileNam helper = new NETLIST_EXPORTER_SPICE( sch ); break; + case NET_TYPE_SPICE_MODEL: + helper = new NETLIST_EXPORTER_SPICE_MODEL( sch ); + break; + case NET_TYPE_BOM: // When generating the BOM, we have a bare filename so don't strip // the extension or you might string a '.' from the middle of the filename diff --git a/eeschema/schematic_settings.cpp b/eeschema/schematic_settings.cpp index a7c4d04911..d3d3c6fc21 100644 --- a/eeschema/schematic_settings.cpp +++ b/eeschema/schematic_settings.cpp @@ -53,8 +53,10 @@ SCHEMATIC_SETTINGS::SCHEMATIC_SETTINGS( JSON_SETTINGS* aParent, const std::strin m_DashedLineDashRatio( 12.0 ), m_DashedLineGapRatio( 3.0 ), m_SpiceAdjustPassiveValues( false ), + m_SpiceCurSheetAsRoot( false ), m_SpiceSaveAllVoltages( false ), m_SpiceSaveAllCurrents( false ), + m_SpiceModelCurSheetAsRoot( true ), m_NgspiceSimulatorSettings( nullptr ) { EESCHEMA_SETTINGS* appSettings = dynamic_cast( Kiface().KifaceSettings() ); diff --git a/eeschema/schematic_settings.h b/eeschema/schematic_settings.h index 4ed50dc6d3..c9650e4d27 100644 --- a/eeschema/schematic_settings.h +++ b/eeschema/schematic_settings.h @@ -70,10 +70,13 @@ public: ///< @todo These should probably be moved to the "schematic.simulator" path. bool m_SpiceAdjustPassiveValues; + bool m_SpiceCurSheetAsRoot; bool m_SpiceSaveAllVoltages; bool m_SpiceSaveAllCurrents; wxString m_SpiceCommandString; // A command string to run external spice + bool m_SpiceModelCurSheetAsRoot; + TEMPLATES m_TemplateFieldNames; /** diff --git a/eeschema/sim/ngspice_helpers.h b/eeschema/sim/ngspice_helpers.h index 183b68a551..67eb7b0f81 100644 --- a/eeschema/sim/ngspice_helpers.h +++ b/eeschema/sim/ngspice_helpers.h @@ -70,7 +70,7 @@ public: bool GetNetlist( OUTPUTFORMATTER* aFormatter ) { - return NGSPICE_CIRCUIT_MODEL::GenerateNetlist( *aFormatter, m_options ); + return NGSPICE_CIRCUIT_MODEL::DoWriteNetlist( *aFormatter, m_options ); } /** diff --git a/eeschema/sim/sim_plot_frame.cpp b/eeschema/sim/sim_plot_frame.cpp index 18ca28c92f..aee3e35d82 100644 --- a/eeschema/sim/sim_plot_frame.cpp +++ b/eeschema/sim/sim_plot_frame.cpp @@ -895,7 +895,8 @@ void SIM_PLOT_FRAME::updateTuners() { const wxString& ref = (*it)->GetComponentName(); - if( std::find_if( spiceItems.begin(), spiceItems.end(), [&]( const SPICE_ITEM& item ) + if( std::find_if( spiceItems.begin(), spiceItems.end(), + [&]( const NETLIST_EXPORTER_SPICE::ITEM& item ) { return item.refName == ref; }) == spiceItems.end() ) @@ -1475,7 +1476,7 @@ void SIM_PLOT_FRAME::onSettings( wxCommandEvent& event ) if( !m_settingsDlg ) m_settingsDlg = new DIALOG_SIM_SETTINGS( this, m_circuitModel, m_simulator->Settings() ); - if( !m_circuitModel->ReadSchematicAndLibraries( NETLIST_EXPORTER_SPICE::OPTION_ALL_FLAGS ) ) + if( !m_circuitModel->ReadSchematicAndLibraries( NETLIST_EXPORTER_SPICE::OPTION_DEFAULT_FLAGS ) ) { DisplayErrorMessage( this, _( "There were errors during netlist export, aborted." ) ); return;