diff --git a/CMakeLists.txt b/CMakeLists.txt index 7ac2a10491..67964436db 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -59,6 +59,7 @@ endif() option( BUILD_GITHUB_PLUGIN "Build the GITHUB_PLUGIN for pcbnew." ON ) +option( KICAD_SPICE "Build Kicad with internal Spice simulator." OFF ) # This can be set to a custom name to brag about a particular branch in the "About" dialog: set( KICAD_REPO_NAME "product" CACHE STRING "Name of the tree from which this build came." ) @@ -98,7 +99,7 @@ endif() # Add option to add user directories for linker, if any -LINK_DIRECTORIES( ${LINK_DIRECTORIES_PATH} ) +LINK_DIRECTORIES( ${LINK_DIRECTORIES_PATH} /usr/local/lib ) if( UNIX ) set( KICAD_USER_CONFIG_DIR $ENV{HOME} CACHE PATH "Location of user specific KiCad config files" ) @@ -436,7 +437,9 @@ add_definitions( -DWX_COMPATIBILITY ) # See line 41 of CMakeModules/FindwxWidgets.cmake set( wxWidgets_CONFIG_OPTIONS ${wxWidgets_CONFIG_OPTIONS} --static=no ) -find_package( wxWidgets 3.0.0 COMPONENTS gl aui adv html core net base xml stc REQUIRED ) +find_package( wxWidgets 3.0.0 COMPONENTS gl aui adv html core net base xml stc richtext REQUIRED ) + + # Include wxWidgets macros. include( ${wxWidgets_USE_FILE} ) @@ -517,6 +520,10 @@ set( INC_AFTER ) +#if ( KICAD_SPICE ) +# find_package(MathGL2 2.3.4 COMPONENTS wx REQUIRED ) +#endif () + # Find Python and other scripting resources if( KICAD_SCRIPTING OR KICAD_SCRIPTING_MODULES ) # force a python version < 3.0 diff --git a/eeschema/CMakeLists.txt b/eeschema/CMakeLists.txt index 7c871e9934..e5ba974215 100644 --- a/eeschema/CMakeLists.txt +++ b/eeschema/CMakeLists.txt @@ -7,6 +7,7 @@ include_directories( ./widgets ../common ../common/dialogs + ./ngspice ${INC_AFTER} ) @@ -175,6 +176,9 @@ set( EESCHEMA_SRCS transform.cpp viewlib_frame.cpp viewlibs.cpp + sim/simulate.cpp + sim/dialog_simulate_plot.cpp + sim/ngspice.cpp netlist_exporters/netlist_exporter.cpp netlist_exporters/netlist_exporter_cadstar.cpp @@ -241,12 +245,19 @@ add_executable( eeschema WIN32 MACOSX_BUNDLE set_source_files_properties( ../common/single_top.cpp PROPERTIES COMPILE_DEFINITIONS "TOP_FRAME=FRAME_SCH;PGM_DATA_FILE_EXT=\"sch\";BUILD_KIWAY_DLL" ) + +if (KICAD_SPICE) + set ( EESCHEMA_LINK_LIBS ${wxWidgets_LIBRARIES} mgl mgl-wx) +else() + set ( EESCHEMA_LINK_LIBS ${wxWidgets_LIBRARIES} ) +endif() + target_link_libraries( eeschema #singletop # replaces common, giving us restrictive control and link warnings. # There's way too much crap coming in from common yet. common bitmaps - ${wxWidgets_LIBRARIES} + ${EESCHEMA_LINK_LIBS} ) # the DSO (KIFACE) housing the main eeschema code: @@ -259,9 +270,9 @@ target_link_libraries( eeschema_kiface bitmaps polygon gal - ${wxWidgets_LIBRARIES} + ${EESCHEMA_LINK_LIBS} ${GDI_PLUS_LIBRARIES} - ) +) set_target_properties( eeschema_kiface PROPERTIES # Decorate OUTPUT_NAME with PREFIX and SUFFIX, creating something like # _eeschema.so, _eeschema.dll, or _eeschema.kiface diff --git a/eeschema/eeschema_id.h b/eeschema/eeschema_id.h index 683e476290..de486b3b71 100644 --- a/eeschema/eeschema_id.h +++ b/eeschema/eeschema_id.h @@ -254,7 +254,11 @@ enum id_eeschema_frm ID_END_EESCHEMA_ID_LIST, ID_UPDATE_PCB_FROM_SCH, - ID_UPDATE_SCH_FROM_PCB + ID_UPDATE_SCH_FROM_PCB, + + ID_SIM_RUN, + ID_SIM_STOP, + ID_SIM_ADD_PROBE }; diff --git a/eeschema/menubar.cpp b/eeschema/menubar.cpp index 162c4cd4a0..480f9da1f4 100644 --- a/eeschema/menubar.cpp +++ b/eeschema/menubar.cpp @@ -422,6 +422,25 @@ void SCH_EDIT_FRAME::ReCreateMenuBar() _( "Import and export settings" ), KiBitmap( save_setup_xpm ) ); + + wxMenu* simMenu = new wxMenu; + + AddMenuItem( simMenu, + ID_SIM_RUN, + _("Run simulation"), _( "Run simulation" ), + KiBitmap( pcbnew_xpm ) ); + + AddMenuItem( simMenu, + ID_SIM_STOP, + _( "Stop simulation" ), _( "Stop simulation" ), + KiBitmap( pcbnew_xpm ) ); + + AddMenuItem( simMenu, + ID_SIM_ADD_PROBE, + _( "Add probe" ), _( "Add probe" ), + KiBitmap( pcbnew_xpm ) ); + + // Menu Tools: wxMenu* toolsMenu = new wxMenu; @@ -526,6 +545,7 @@ void SCH_EDIT_FRAME::ReCreateMenuBar() menuBar->Append( viewMenu, _( "&View" ) ); menuBar->Append( placeMenu, _( "&Place" ) ); menuBar->Append( preferencesMenu, _( "P&references" ) ); + menuBar->Append( simMenu, _( "&Simulate" ) ); menuBar->Append( toolsMenu, _( "&Tools" ) ); menuBar->Append( helpMenu, _( "&Help" ) ); diff --git a/eeschema/netlist_exporters/netlist_exporter_pspice.cpp b/eeschema/netlist_exporters/netlist_exporter_pspice.cpp index 3de6f3cb52..0adbaeba16 100644 --- a/eeschema/netlist_exporters/netlist_exporter_pspice.cpp +++ b/eeschema/netlist_exporters/netlist_exporter_pspice.cpp @@ -27,6 +27,8 @@ #include #include +#include + #include #include #include @@ -36,9 +38,13 @@ bool NETLIST_EXPORTER_PSPICE::WriteNetlist( const wxString& aOutFileName, unsigned aNetlistOptions ) { - FILE* f = NULL; - bool aUsePrefix = aNetlistOptions & NET_USE_X_PREFIX; - bool aUseNetcodeAsNetName = aNetlistOptions & NET_USE_NETCODES_AS_NETNAMES; + return false; +} + + +bool NETLIST_EXPORTER_PSPICE::Format( OUTPUTFORMATTER* formatter, int aCtl ) +{ + bool aUsePrefix = aCtl & NET_USE_X_PREFIX; int ret = 0; int nbitems; @@ -55,31 +61,23 @@ bool NETLIST_EXPORTER_PSPICE::WriteNetlist( const wxString& aOutFileName, unsign wxString delimeters = wxT( "{:,; }" ); wxString disableStr = wxT( "N" ); - if( ( f = wxFopen( aOutFileName, wxT( "wt" ) ) ) == NULL ) - { - msg.Printf( _( "Failed to create file '%s'" ), - GetChars( aOutFileName ) ); - DisplayError( NULL, msg ); - return false; - } - - ret |= fprintf( f, "* %s\n\n", TO_UTF8( aOutFileName ) ); - ret |= fprintf( f, "* %s (Spice format) creation date: %s\n\n", - NETLIST_HEAD_STRING, TO_UTF8( DateAndTime() ) ); + std::map netIndices; // Prepare list of nets generation (not used here, but... for( unsigned ii = 0; ii < m_masterList->size(); ii++ ) m_masterList->GetItem( ii )->m_Flag = 0; - ret |= fprintf( f, "* To exclude a component from the Spice Netlist add [Spice_Netlist_Enabled] user FIELD set to: N\n" ); - ret |= fprintf( f, "* To reorder the component spice node sequence add [Spice_Node_Sequence] user FIELD and define sequence: 2,1,0\n" ); - // Create text list starting by [.-]pspice , or [.-]gnucap (simulator // commands) and create text list starting by [+]pspice , or [+]gnucap // (simulator commands) bufnum[BUFYPOS_LEN] = 0; SCH_SHEET_LIST sheetList( g_RootSheet ); + std::vector directives; + std::vector probeNets; + + netIndices["GND"] = 0; + for( unsigned i = 0; i < sheetList.size(); i++ ) { for( EDA_ITEM* item = sheetList[i].LastDrawList(); item; item = item->Next() ) @@ -99,72 +97,24 @@ bool NETLIST_EXPORTER_PSPICE::WriteNetlist( const wxString& aOutFileName, unsign ident = text.GetChar( 0 ); - if( ident != '.' && ident != '-' && ident != '+' ) - continue; - - text.Remove( 0, 1 ); // Remove the first char. - text.Remove( 6 ); // text contains 6 char. - text.MakeLower(); - - if( text != wxT( "pspice" ) && text != wxT( "gnucap" ) ) - continue; - - text = drawText->GetText().Mid( 7 ); - l1 = text.Length(); - text.Trim( false ); - l2 = text.Length(); - - if( l1 == l2 ) - continue; // no whitespace after ident text - + if( ident == '.' ) { - // Put the Y position as an ascii string, for sort by vertical - // position, using usual sort string by alphabetic value - int ypos = drawText->GetPosition().y; - - for( int ii = 0; ii < BUFYPOS_LEN; ii++ ) - { - bufnum[BUFYPOS_LEN - 1 - ii] = (ypos & 63) + ' '; - ypos >>= 6; - } - - // First BUFYPOS_LEN char are the Y position. - msg.Printf( wxT( "%s %s" ), bufnum, text.GetData() ); - - if( ident == '+' ) - spiceCommandAtEndFile.Add( msg ); - else - spiceCommandAtBeginFile.Add( msg ); + printf("Directive found: '%s'\n", (const char *) text.c_str()); + directives.push_back(text); } } } - // Print texts starting by [.-]pspice , ou [.-]gnucap (of course, without - // the Y position string) - nbitems = spiceCommandAtBeginFile.GetCount(); - - if( nbitems ) - { - spiceCommandAtBeginFile.Sort(); - - for( int ii = 0; ii < nbitems; ii++ ) - { - spiceCommandAtBeginFile[ii].Remove( 0, BUFYPOS_LEN ); - spiceCommandAtBeginFile[ii].Trim( true ); - spiceCommandAtBeginFile[ii].Trim( false ); - ret |= fprintf( f, "%s\n", TO_UTF8( spiceCommandAtBeginFile[ii] ) ); - } - } - ret |= fprintf( f, "\n" ); - - // Create component list m_ReferencesAlreadyFound.Clear(); + + int curNetIndex = 1; + for( unsigned sheet_idx = 0; sheet_idx < sheetList.size(); sheet_idx++ ) { - ret |= fprintf( f, "* Sheet Name: %s\n", - TO_UTF8( sheetList[sheet_idx].PathHumanReadable() ) ); + //printf( "* Sheet Name: %s\n", + // TO_UTF8( sheetList[sheet_idx].PathHumanReadable() ) ); for( EDA_ITEM* item = sheetList[sheet_idx].LastDrawList(); item; item = item->Next() ) { @@ -178,6 +128,33 @@ bool NETLIST_EXPORTER_PSPICE::WriteNetlist( const wxString& aOutFileName, unsign // Reset NodeSeqIndex Count: pinSequence.clear(); + SCH_FIELD* spicePrimitiveType = comp->FindField( wxT( "Spice_Primitive" ) ); + SCH_FIELD* spiceModel = comp->FindField( wxT( "Spice_Model" ) ); + + wxString RefName = comp->GetRef( &sheetList[sheet_idx] ); + wxString CompValue = comp->GetField( VALUE )->GetText(); + + wxString model(""); + wxString primType ("X"); + + if(spicePrimitiveType) + primType = spicePrimitiveType->GetText(); + else { + if (RefName.StartsWith(wxT("IC")) || RefName.StartsWith("U") ) + primType = wxT("X"); // subckt + else + primType = RefName.GetChar(0); + } + + if(spiceModel) + { + // printf("model specified\n"); + model = spiceModel->GetText(); + } else { + // printf("no model\n"); + model = CompValue; + } + // Check to see if component should be removed from Spice Netlist: SCH_FIELD* netlistEnabledField = comp->FindField( wxT( "Spice_Netlist_Enabled" ) ); @@ -234,21 +211,30 @@ bool NETLIST_EXPORTER_PSPICE::WriteNetlist( const wxString& aOutFileName, unsign } } - //Get Standard Reference Designator: - wxString RefName = comp->GetRef( &sheetList[sheet_idx] ); + + if(CompValue == wxT("SPICE_PROBE")) + { + NETLIST_OBJECT* pin = m_SortedComponentPinList[0]; + + printf("Probe net: %s\n", (const char*) pin->GetNetName().c_str() ); + + probeNets.push_back(pin->GetNetName()); + continue; + } //Conditionally add Prefix only for devices that begin with U or IC: if( aUsePrefix ) { - if( RefName.StartsWith( wxT( "U" ) ) || RefName.StartsWith( wxT( "IC" ) ) ) - RefName = wxT( "X" ) + RefName; + //if( RefName.StartsWith( wxT( "U" ) ) || RefName.StartsWith( wxT( "IC" ) ) ) + // RefName = wxT( "X" ) + RefName; } - ret |= fprintf( f, "%s ", TO_UTF8( RefName ) ); + printf( "Ref %s primType %s model/value '%s'\n", TO_UTF8( RefName ), (const char*)primType.c_str(), (const char *)model.c_str() ); - // Write pin list: int activePinIndex = 0; + formatter->Print(0, "%s%s ", (const char *)primType.c_str(), (const char *)RefName.c_str()); + for( unsigned ii = 0; ii < m_SortedComponentPinList.size(); ii++ ) { // Case of Alt Sequence definition with Unused/Invalid Node index: @@ -282,56 +268,41 @@ bool NETLIST_EXPORTER_PSPICE::WriteNetlist( const wxString& aOutFileName, unsign if( !pin ) continue; - sprintPinNetName( netName , wxT( "N-%.6d" ), pin, aUseNetcodeAsNetName ); + wxString netName = pin->GetNetName(); + int netIdx; + + if (netIndices.find(netName) == netIndices.end()) + { + netIdx = curNetIndex++; + netIndices[netName] = netIdx; + } else { + netIdx = netIndices[netName]; + } + + //printf("net %s index %d\n", (const char*)netName.c_str(), netIdx); +// sprintPinNetName( netName , wxT( "N-%.6d" ), pin, aUseNetcodeAsNetName ); //Replace parenthesis with underscore to prevent parse issues with Simulators: - netName.Replace( wxT( "(" ), wxT( "_" ) ); - netName.Replace( wxT( ")" ), wxT( "_" ) ); +// netName.Replace( wxT( "(" ), wxT( "_" ) ); +// netName.Replace( wxT( ")" ), wxT( "_" ) ); - if( netName.IsEmpty() ) - netName = wxT( "?" ); +// if( netName.IsEmpty() ) +// netName = wxT( "?" ); - ret |= fprintf( f, " %s", TO_UTF8( netName ) ); +// ret |= fprintf( f, " %s", TO_UTF8( netName ) ); + + formatter->Print(0, "%d ", netIdx ); } - // Get Component Value Name: - wxString CompValue = comp->GetField( VALUE )->GetText(); + formatter->Print(0, "%s\n",(const char *) model.c_str()); - // Check if Override Model Name is Provided: - SCH_FIELD* spiceModelField = comp->FindField( wxT( "spice_model" ) ); - if( spiceModelField ) - { - // Get Model Name String: - wxString ModelNameStr = spiceModelField->GetText(); - - // Verify Field Exists and is not empty: - if( !ModelNameStr.IsEmpty() ) - CompValue = ModelNameStr; - } - - // Print Component Value: - ret |= fprintf( f, " %s\t\t",TO_UTF8( CompValue ) ); - - // Show Seq Spec on same line as component using line-comment ";": - for( unsigned ii = 0; ii < pinSequence.size(); ++ii ) - { - if( ii == 0 ) - ret |= fprintf( f, ";Node Sequence Spec.<" ); - - ret |= fprintf( f, "%s", TO_UTF8( stdPinNameArray.Item( pinSequence[ii] ) ) ); - - if( ii < pinSequence.size()-1 ) - ret |= fprintf( f, "," ); - else - ret |= fprintf( f, ">" ); - } - - // Next Netlist line record: - ret |= fprintf( f, "\n" ); } + + } +#if 0 m_SortedComponentPinList.clear(); // Print texts starting with [+]pspice or [+]gnucap @@ -354,5 +325,8 @@ bool NETLIST_EXPORTER_PSPICE::WriteNetlist( const wxString& aOutFileName, unsign ret |= fprintf( f, "\n.end\n" ); fclose( f ); +#endif + + return ret >= 0; } diff --git a/eeschema/netlist_exporters/netlist_exporter_pspice.h b/eeschema/netlist_exporters/netlist_exporter_pspice.h index c57938f69b..959a176c59 100644 --- a/eeschema/netlist_exporters/netlist_exporter_pspice.h +++ b/eeschema/netlist_exporters/netlist_exporter_pspice.h @@ -45,6 +45,9 @@ public: * writes to specified output file */ bool WriteNetlist( const wxString& aOutFileName, unsigned aNetlistOptions ); + + bool Format( OUTPUTFORMATTER* aOutputFormatter, int aCtl ); + }; #endif diff --git a/eeschema/schframe.cpp b/eeschema/schframe.cpp index 9cca131108..079d2c0654 100644 --- a/eeschema/schframe.cpp +++ b/eeschema/schframe.cpp @@ -264,6 +264,9 @@ BEGIN_EVENT_TABLE( SCH_EDIT_FRAME, EDA_DRAW_FRAME ) EVT_TOOL( ID_GET_ERC, SCH_EDIT_FRAME::OnErc ) EVT_TOOL( ID_GET_NETLIST, SCH_EDIT_FRAME::OnCreateNetlist ) EVT_TOOL( ID_UPDATE_PCB_FROM_SCH, SCH_EDIT_FRAME::OnUpdatePCB ) + EVT_TOOL( ID_SIM_RUN, SCH_EDIT_FRAME::OnSimulationRun ) + EVT_TOOL( ID_SIM_STOP, SCH_EDIT_FRAME::OnSimulationStop ) + EVT_TOOL( ID_SIM_ADD_PROBE, SCH_EDIT_FRAME::OnSimulationAddProbe ) EVT_TOOL( ID_GET_TOOLS, SCH_EDIT_FRAME::OnCreateBillOfMaterials ) EVT_TOOL( ID_FIND_ITEMS, SCH_EDIT_FRAME::OnFindItems ) EVT_TOOL( wxID_REPLACE, SCH_EDIT_FRAME::OnFindItems ) @@ -1371,4 +1374,3 @@ void SCH_EDIT_FRAME::UpdateTitle() SetTitle( title ); } - diff --git a/eeschema/schframe.h b/eeschema/schframe.h index 9f87accc2a..0cac05e445 100644 --- a/eeschema/schframe.h +++ b/eeschema/schframe.h @@ -813,6 +813,9 @@ private: void OnErc( wxCommandEvent& event ); void OnCreateNetlist( wxCommandEvent& event ); void OnUpdatePCB( wxCommandEvent& event ); + void OnSimulationRun( wxCommandEvent& event ); + void OnSimulationStop( wxCommandEvent& event ); + void OnSimulationAddProbe( wxCommandEvent& event ); void OnCreateBillOfMaterials( wxCommandEvent& event ); void OnFindItems( wxCommandEvent& event ); void OnFindDialogClose( wxFindDialogEvent& event );