1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 1992-2013 jp.charras at wanadoo.fr
5  * Copyright (C) 2013 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
6  * Copyright (C) 1992-2021 KiCad Developers
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, you may find one here:
20  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21  * or you may search the http://www.gnu.org website for the version 2 license,
22  * or you may write to the Free Software Foundation, Inc.,
23  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
24  */
25 
26 #ifndef NETLIST_EXPORTER_PSPICE_H
27 #define NETLIST_EXPORTER_PSPICE_H
28 
29 #include "netlist_exporter_base.h"
30 #include <list>
31 #include <map>
32 
33 class PROJECT;
34 
35 /// Flags for Spice netlist generation (can be combined)
36 enum SPICE_NETLIST_OPTIONS {
37     NET_ADJUST_INCLUDE_PATHS = 8, // use full paths for included files (if they are in search path)
38     NET_ADJUST_PASSIVE_VALS = 16, // reformat passive symbol values (e.g. 1M -> 1Meg)
39     NET_ALL_FLAGS = 0xffff
40 };
41 
42 enum SPICE_FIELD {
43     SF_PRIMITIVE,
44     SF_MODEL,
45     SF_ENABLED,
46     SF_NODE_SEQUENCE,
47     SF_LIB_FILE,
48     SF_END     // sentinel
49 };
50 
51 ///< Basic Spice component primitives
52 enum SPICE_PRIMITIVE {
53     SP_UNKNOWN      = ' ',
54     SP_RESISTOR     = 'R',
55     SP_CAPACITOR    = 'C',
56     SP_INDUCTOR     = 'L',
57     SP_DIODE        = 'D',
58     SP_BJT          = 'Q',
59     SP_MOSFET       = 'M',
60     SP_JFET         = 'J',
61     SP_SUBCKT       = 'X',
62     SP_VSOURCE      = 'V',
63     SP_ISOURCE      = 'I'
64 };
65 
66 /// @todo add NET_ADJUST_INCLUDE_PATHS & NET_ADJUST_PASSIVE_VALS checkboxes in the netlist
67 ///       export dialog.
68 
69 /**
70  * Structure to represent a schematic symbol in the Spice simulation.
71  */
72 struct SPICE_ITEM
73 {
74 
75     SCH_SYMBOL*           m_parent;        ///< Schematic symbol represented by this SPICE_ITEM.
76     wxChar                m_primitive;     ///< Spice primitive type (@see SPICE_PRIMITIVE).
77     wxString              m_model;         ///< Library model (for semiconductors and subcircuits),
78                                            ///<   component value (for passive components) or
79                                            ///<   voltage/current (for sources).
80     wxString              m_refName;
81     bool                  m_enabled;       ///< Whether the symbol should be used in simulation.
82     std::vector<wxString> m_pins;          ///< Array containing Standard Pin Name
83     std::vector<int>      m_pinSequence;   ///< Numeric indices into m_SortedSymbolPinList
84 };
85 
86 
87 /**
88  * Generate a PSPICE compatible netlist.
89  */
90 class NETLIST_EXPORTER_PSPICE : public NETLIST_EXPORTER_BASE
91 {
92 public:
NETLIST_EXPORTER_PSPICE(SCHEMATIC_IFACE * aSchematic)93     NETLIST_EXPORTER_PSPICE( SCHEMATIC_IFACE* aSchematic ) :
94             NETLIST_EXPORTER_BASE( aSchematic )
95     {
96     }
97 
~NETLIST_EXPORTER_PSPICE()98     virtual ~NETLIST_EXPORTER_PSPICE()
99     {
100     }
101 
102     /**
103      * Return list of items representing schematic components in the Spice world.
104      */
GetSpiceItems()105     const std::list<SPICE_ITEM>& GetSpiceItems() const
106     {
107         return m_spiceItems;
108     }
109 
110     /**
111      * Return name of Spice device corresponding to a schematic symbol.
112      *
113      * @param aSymbol is the component reference.
114      * @return Spice device name or empty string if there is no such symbol in the netlist. The
115      * name is either plain reference if the first character of reference corresponds to the
116      * assigned device model type or it is the reference prefixed with a character defining
117      * the device model type.
118      */
119     wxString GetSpiceDevice( const wxString& aSymbol ) const;
120 
121     /**
122      * Write to specified output file
123      */
124     bool WriteNetlist( const wxString& aOutFileName, unsigned aNetlistOptions ) override;
125 
126     ///< @copydoc NETLIST_EXPORTER_BASE::Format()
127     bool Format( OUTPUTFORMATTER* aFormatter, unsigned aCtl );
128 
129     /**
130      * Process the netlist to create net mapping and a list of SPICE_ITEMs.
131      * It is automatically called by WriteNetlist(), but might be used separately,
132      * if only net mapping and the list of SPICE_ITEMs are required.
133      * @return True if successful.
134      */
135     bool ProcessNetlist( unsigned aCtl );
136 
137 
138     /**
139      * Replace illegal spice net name characters with an underscore.
140      */
141      static void ReplaceForbiddenChars( wxString& aNetName );
142 
143     /**
144      * Return a map of circuit nodes to net names.
145      */
GetNetIndexMap()146     const std::map<wxString, int>& GetNetIndexMap() const
147     {
148         return m_netMap;
149     }
150 
151     /**
152      * Return a vector of component field names related to Spice simulation.
153      */
GetSpiceFields()154     static const std::vector<wxString>& GetSpiceFields()
155     {
156         return m_spiceFields;
157     }
158 
159     /**
160      * Return a string used for a particular component field related to Spice simulation.
161      */
GetSpiceFieldName(SPICE_FIELD aField)162     static const wxString& GetSpiceFieldName( SPICE_FIELD aField )
163     {
164         return m_spiceFields[(int) aField];
165     }
166 
167     /**
168      * Retrieve either the requested field value or the default value.
169      */
170     static wxString GetSpiceField( SPICE_FIELD aField, SCH_SYMBOL* aSymbol, unsigned aCtl );
171 
172     /**
173      * Retrieve the default value for a given field.
174      */
175     static wxString GetSpiceFieldDefVal( SPICE_FIELD aField, SCH_SYMBOL* aSymbol, unsigned aCtl );
176 
177     /**
178      * Update the vector of Spice directives placed in the schematics.
179      */
180     void UpdateDirectives( unsigned aCtl );
181 
182     /**
183      * Return a vector of Spice directives found in the schematics.
184      */
GetDirectives()185     const std::vector<wxString> GetDirectives() const
186     {
187         return m_directives;
188     }
189 
190     /**
191      * Convert typical boolean string values (no/yes, true/false, 1/0) to a boolean value.
192      */
StringToBool(const wxString & aStr)193     static bool StringToBool( const wxString& aStr )
194     {
195         if( aStr.IsEmpty() )
196             return false;
197 
198         char c = tolower( aStr[0] );
199 
200         // Different ways of saying false (no/false/0)
201         return !( c == 'n' || c == 'f' || c == '0' );
202     }
203 
204 protected:
205     /**
206      * Save the Spice directives.
207      */
208     virtual void writeDirectives( OUTPUTFORMATTER* aFormatter, unsigned aCtl ) const;
209 
210 private:
211 
212     wxString                m_title;       ///< Spice simulation title found in the schematic sheet
213     std::vector<wxString>   m_directives;  ///< Spice directives found in the schematic sheet
214     std::set<wxString>      m_libraries;   ///< Spice libraries used by the simulated circuit
215     std::map<wxString, int> m_netMap;      ///< Map spice nodes to net codes
216     std::list<SPICE_ITEM>   m_spiceItems;  ///< Items representing schematic symbols in Spice world
217 
218     // Component fields that are processed during netlist export & simulation
219     static const std::vector<wxString> m_spiceFields;
220 };
221 
222 #endif
223