/* * 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. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 3 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, you may find one here: * https://www.gnu.org/licenses/gpl-3.0.html * or you may search the http://www.gnu.org website for the version 3 license, * or you may write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef SIM_MODEL_H #define SIM_MODEL_H #include #include #include #include #include #include #include class SIM_LIBRARY; namespace SIM_MODEL_GRAMMAR { using namespace SPICE_GRAMMAR; struct pinNumber : sor> {}; struct pinSequence : seq>> {}; struct pinSequenceGrammar : must, pinSequence, opt, eof> {}; template struct paramValuePairsGrammar : must, paramValuePairs, opt, eof> {}; } class SIM_MODEL { public: static constexpr auto DEVICE_TYPE_FIELD = "Model_Device"; static constexpr auto TYPE_FIELD = "Model_Type"; static constexpr auto PINS_FIELD = "Model_Pins"; static constexpr auto PARAMS_FIELD = "Model_Params"; DEFINE_ENUM_CLASS_WITH_ITERATOR( DEVICE_TYPE, NONE, RESISTOR, CAPACITOR, INDUCTOR, TLINE, SWITCH, DIODE, NPN, PNP, NJF, PJF, NMES, PMES, NMOS, PMOS, VSOURCE, ISOURCE, SUBCIRCUIT, CODEMODEL, RAWSPICE ) struct DEVICE_INFO { wxString fieldValue; wxString description; }; DEFINE_ENUM_CLASS_WITH_ITERATOR( TYPE, NONE, RESISTOR_IDEAL, RESISTOR_ADVANCED, RESISTOR_BEHAVIORAL, CAPACITOR_IDEAL, CAPACITOR_ADVANCED, CAPACITOR_BEHAVIORAL, INDUCTOR_IDEAL, INDUCTOR_ADVANCED, INDUCTOR_BEHAVIORAL, TLINE_LOSSY, TLINE_LOSSLESS, TLINE_UNIFORM_RC, TLINE_KSPICE, SWITCH_VCTRL, SWITCH_ICTRL, DIODE, NPN_GUMMEL_POON, PNP_GUMMEL_POON, NPN_VBIC, PNP_VBIC, //NPN_MEXTRAM, //PNP_MEXTRAM, NPN_HICUM_L2, PNP_HICUM_L2, //NPN_HICUM_L0, //PNP_HICUM_L0, NJF_SHICHMAN_HODGES, PJF_SHICHMAN_HODGES, NJF_PARKER_SKELLERN, PJF_PARKER_SKELLERN, NMES_STATZ, PMES_STATZ, NMES_YTTERDAL, PMES_YTTERDAL, NMES_HFET1, PMES_HFET1, NMES_HFET2, PMES_HFET2, NMOS_MOS1, PMOS_MOS1, NMOS_MOS2, PMOS_MOS2, NMOS_MOS3, PMOS_MOS3, NMOS_BSIM1, PMOS_BSIM1, NMOS_BSIM2, PMOS_BSIM2, NMOS_MOS6, PMOS_MOS6, NMOS_MOS9, PMOS_MOS9, NMOS_BSIM3, PMOS_BSIM3, NMOS_B4SOI, PMOS_B4SOI, NMOS_BSIM4, PMOS_BSIM4, //NMOS_EKV2_6, //PMOS_EKV2_6, //NMOS_PSP, //PMOS_PSP, NMOS_B3SOIFD, PMOS_B3SOIFD, NMOS_B3SOIDD, PMOS_B3SOIDD, NMOS_B3SOIPD, PMOS_B3SOIPD, //NMOS_STAG, //PMOS_STAG, NMOS_HISIM2, PMOS_HISIM2, NMOS_HISIM_HV1, PMOS_HISIM_HV1, NMOS_HISIM_HV2, PMOS_HISIM_HV2, VSOURCE_PULSE, VSOURCE_SIN, VSOURCE_EXP, VSOURCE_SFAM, VSOURCE_SFFM, VSOURCE_PWL, VSOURCE_WHITE_NOISE, VSOURCE_PINK_NOISE, VSOURCE_BURST_NOISE, VSOURCE_RANDOM_UNIFORM, VSOURCE_RANDOM_NORMAL, VSOURCE_RANDOM_EXP, VSOURCE_RANDOM_POISSON, VSOURCE_BEHAVIORAL, ISOURCE_PULSE, ISOURCE_SIN, ISOURCE_EXP, ISOURCE_SFAM, ISOURCE_SFFM, ISOURCE_PWL, ISOURCE_WHITE_NOISE, ISOURCE_PINK_NOISE, ISOURCE_BURST_NOISE, ISOURCE_RANDOM_UNIFORM, ISOURCE_RANDOM_NORMAL, ISOURCE_RANDOM_EXP, ISOURCE_RANDOM_POISSON, ISOURCE_BEHAVIORAL, SUBCIRCUIT, CODEMODEL, RAWSPICE ) struct INFO { DEVICE_TYPE deviceType; wxString fieldValue; wxString description; }; struct SPICE_INFO { wxString itemType; wxString typeString = ""; wxString inlineTypeString = ""; int level = 0; bool hasExpression = false; wxString version = ""; }; struct PIN { static constexpr auto NOT_CONNECTED = 0; int symbolPinNumber; const wxString name; }; struct PARAM { enum class DIR { IN, OUT, INOUT }; enum class CATEGORY { PRINCIPAL, DC, CAPACITANCE, TEMPERATURE, NOISE, DISTRIBUTED_QUANTITIES, GEOMETRY, LIMITING_VALUES, ADVANCED, FLAGS, INITIAL_CONDITIONS, SUPERFLUOUS }; struct FLAGS {}; // Legacy. struct INFO { wxString name; unsigned int id = 0; // Legacy. DIR dir = DIR::INOUT; SIM_VALUE_BASE::TYPE type; FLAGS flags = {}; // Legacy wxString unit = ""; CATEGORY category = CATEGORY::PRINCIPAL; wxString defaultValue = ""; wxString defaultValueOfOtherVariant = ""; // Legacy. wxString description = ""; }; std::unique_ptr value; const INFO& info; bool isOtherVariant = false; // Legacy. PARAM( const INFO& aInfo, bool aIsOtherVariant = false ) : value( SIM_VALUE_BASE::Create( aInfo.type ) ), info( aInfo ), isOtherVariant( aIsOtherVariant ) {} }; static DEVICE_INFO DeviceTypeInfo( DEVICE_TYPE aDeviceType ); static INFO TypeInfo( TYPE aType ); static SPICE_INFO SpiceInfo( TYPE aType ); static TYPE ReadTypeFromSpiceCode( const std::string& aSpiceCode ); template static TYPE ReadTypeFromFields( const std::vector& aFields ); static std::unique_ptr Create( TYPE aType, int aSymbolPinCount = 0 ); static std::unique_ptr Create( const std::string& aSpiceCode ); static std::unique_ptr Create( const SIM_MODEL& aBaseModel ); template static std::unique_ptr Create( int aSymbolPinCount, const std::vector& aFields ); template static wxString GetFieldValue( const std::vector* aFields, const wxString& aFieldName ); template static void SetFieldValue( std::vector& aFields, const wxString& aFieldName, const wxString& aValue ); // Move semantics. // Rule of five. virtual ~SIM_MODEL() = default; SIM_MODEL() = delete; SIM_MODEL( const SIM_MODEL& aOther ) = delete; SIM_MODEL( SIM_MODEL&& aOther ) = default; SIM_MODEL& operator=(SIM_MODEL&& aOther ) = delete; virtual bool ReadSpiceCode( const std::string& aSpiceCode ); template void ReadDataFields( int aSymbolPinCount, const std::vector* aFields ); // C++ doesn't allow virtual template methods, so we do this: virtual void ReadDataSchFields( int aSymbolPinCount, const std::vector* aFields ); virtual void ReadDataLibFields( int aSymbolPinCount, const std::vector* aFields ); template void WriteFields( std::vector& aFields ); // C++ doesn't allow virtual template methods, so we do this: virtual void WriteDataSchFields( std::vector& aFields ); virtual void WriteDataLibFields( std::vector& aFields ); virtual wxString GenerateSpiceIncludeLine( const wxString& aLibraryFilename ) const; virtual wxString GenerateSpiceModelLine( const wxString& aModelName ) const; virtual SPICE_INFO GetSpiceInfo() const; wxString GenerateSpiceItemLine( const wxString& aRefName, const wxString& aModelName ) const; virtual wxString GenerateSpiceItemLine( const wxString& aRefName, const wxString& aModelName, const std::vector& aPinNetNames ) const; virtual wxString GenerateSpicePreview( const wxString& aModelName ) const; void AddParam( const PARAM::INFO& aInfo, bool aIsOtherVariant = false ); TYPE GetType() const { return m_type; } const SIM_MODEL* GetBaseModel() const { return m_baseModel; } void SetBaseModel( const SIM_MODEL& aBaseModel ) { m_baseModel = &aBaseModel; } int GetPinCount() const { return static_cast( m_pins.size() ); } const PIN& GetPin( int aIndex ) const { return m_pins.at( aIndex ); } void SetPinSymbolPinNumber( int aIndex, int aSymbolPinNumber ) { m_pins.at( aIndex ).symbolPinNumber = aSymbolPinNumber; } int GetParamCount() const { return static_cast( m_params.size() ); } const PARAM& GetParam( int aParamIndex ) const; // Return base parameter unless it's overridden. const PARAM& GetUnderlyingParam( int aParamIndex ) const; // Return the actual parameter. const PARAM& GetBaseParam( int aParamIndex ) const; // Always return base parameter if it exists. virtual bool SetParamValue( int aParamIndex, const wxString& aValue ); bool HasOverrides() const; bool HasNonPrincipalOverrides() const; // Can modifying a model parameter also modify other parameters? virtual bool HasAutofill() const { return false; } protected: SIM_MODEL( TYPE aType ); private: static std::unique_ptr create( TYPE aType ); static TYPE readTypeFromSpiceTypeString( const std::string& aTypeString ); wxString m_spiceCode; const SIM_MODEL* m_baseModel; const TYPE m_type; std::vector m_pins; std::vector m_params; template void doReadDataFields( int aSymbolPinCount, const std::vector* aFields ); template void doWriteFields( std::vector& aFields ); virtual std::vector getPinNames() const { return {}; } wxString generateDeviceTypeField() const; wxString generateTypeField() const; wxString generatePinsField() const; void parsePinsField( int aSymbolPinCount, const wxString& aPinsField ); wxString generateParamsField( const wxString& aPairSeparator ) const; void parseParamsField( const wxString& aParamsField ); virtual bool setParamFromSpiceCode( const wxString& aParamName, const wxString& aParamValue ); }; #endif // SIM_MODEL_H