/* * 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 // Must be included after sch_field.h (exactly eda_shape.h) to avoid a colliding // declaration with a window header (under msys2) #include #include class SIM_LIBRARY; namespace SIM_MODEL_GRAMMAR { using namespace SIM_VALUE_GRAMMAR; struct sep : plus {}; struct pinNumber : sor> {}; struct pinSequence : opt> {}; struct pinSequenceGrammar : must, pinSequence, opt, tao::pegtl::eof> {}; struct unquotedString : plus, any> {}; struct quotedStringContent : star>, any> {}; // TODO: Allow escaping '"'. struct quotedString : seq, quotedStringContent, one<'"'>> {}; struct param : plus {}; struct fieldParamValuePair : seq, one<'='>, opt, sor, //number, quotedString, unquotedString>> {}; struct fieldParamValuePairs : seq, star> {}; struct fieldParamValuePairsGrammar : must, fieldParamValuePairs, opt, tao::pegtl::eof> {}; } class SIM_MODEL { public: static constexpr auto REFERENCE_FIELD = "Reference"; static constexpr auto VALUE_FIELD = "Value"; static constexpr auto DEVICE_TYPE_FIELD = "Sim_Device"; static constexpr auto TYPE_FIELD = "Sim_Type"; static constexpr auto PINS_FIELD = "Sim_Pins"; static constexpr auto PARAMS_FIELD = "Sim_Params"; static constexpr auto DISABLED_FIELD = "Sim_Disabled"; // There's a trailing '_' because `DEVICE_TYPE` collides with something in Windows headers. DEFINE_ENUM_CLASS_WITH_ITERATOR( DEVICE_TYPE_, NONE, R, C, L, TLINE, SW, D, NPN, PNP, NJFET, PJFET, NMES, PMES, NMOS, PMOS, V, I, SUBCKT, XSPICE, SPICE ) struct DEVICE_INFO { wxString fieldValue; wxString description; }; DEFINE_ENUM_CLASS_WITH_ITERATOR( TYPE, NONE, R, //R_ADV, R_BEHAVIORAL, C, //C_ADV, C_BEHAVIORAL, L, //L_ADV, L_BEHAVIORAL, TLINE_Z0, TLINE_RLGC, SW_V, SW_I, D, NPN_GUMMELPOON, PNP_GUMMELPOON, NPN_VBIC, PNP_VBIC, //NPN_MEXTRAM, //PNP_MEXTRAM, NPN_HICUM2, PNP_HICUM2, //NPN_HICUM_L0, //PNP_HICUM_L0, NJFET_SHICHMANHODGES, PJFET_SHICHMANHODGES, NJFET_PARKERSKELLERN, PJFET_PARKERSKELLERN, 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_HISIMHV1, PMOS_HISIMHV1, NMOS_HISIMHV2, PMOS_HISIMHV2, V, V_SIN, V_PULSE, V_EXP, /*V_SFAM, V_SFFM,*/ V_PWL, V_WHITENOISE, V_PINKNOISE, V_BURSTNOISE, V_RANDUNIFORM, V_RANDNORMAL, V_RANDEXP, //V_RANDPOISSON, V_BEHAVIORAL, I, I_SIN, I_PULSE, I_EXP, /*I_SFAM, I_SFFM,*/ I_PWL, I_WHITENOISE, I_PINKNOISE, I_BURSTNOISE, I_RANDUNIFORM, I_RANDNORMAL, I_RANDEXP, //I_RANDPOISSON, I_BEHAVIORAL, SUBCKT, XSPICE, SPICE ) struct INFO { DEVICE_TYPE_ deviceType; wxString fieldValue; wxString description; }; struct SPICE_INFO { wxString itemType; wxString modelType = ""; wxString inlineTypeString = ""; wxString level = ""; bool isDefaultLevel = false; bool hasExpression = false; wxString version = ""; }; struct PIN { static constexpr unsigned NOT_CONNECTED = 0; const wxString name; unsigned symbolPinNumber; }; struct PARAM { // MS Windows compilers complain about the names IN and OUT, so we prefix them. enum DIR { DIR_IN, DIR_OUT, DIR_INOUT }; enum class CATEGORY { PRINCIPAL, GEOMETRY, AC, DC, CAPACITANCE, TEMPERATURE, NOISE, DISTRIBUTED_QUANTITIES, LIMITING_VALUES, ADVANCED, FLAGS, INITIAL_CONDITIONS, SUPERFLUOUS }; struct FLAGS {}; // Legacy. struct INFO { wxString name; unsigned id = 0; // Legacy (don't remove). DIR dir = DIR_INOUT; SIM_VALUE::TYPE type = SIM_VALUE::TYPE_FLOAT; FLAGS flags = {}; // Legacy (don't remove). wxString unit = ""; CATEGORY category = CATEGORY::PRINCIPAL; wxString defaultValue = ""; wxString defaultValueOfOtherVariant = ""; // Legacy (don't remove). wxString description = ""; bool isSpiceInstanceParam = false; bool isInstanceParam = false; wxString spiceInstanceName = ""; }; std::unique_ptr value; const INFO& info; bool isOtherVariant = false; // Legacy. PARAM( const INFO& aInfo, bool aIsOtherVariant = false ) : value( SIM_VALUE::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 TYPE InferTypeFromRefAndValue( const wxString& aRef, const wxString& aValue ); template static TYPE InferTypeFromLegacyFields( const std::vector& aFields ); static std::unique_ptr Create( TYPE aType, unsigned aSymbolPinCount = 0 ); static std::unique_ptr Create( const std::string& aSpiceCode ); static std::unique_ptr Create( const SIM_MODEL& aBaseModel, unsigned aSymbolPinCount ); template static std::unique_ptr Create( const SIM_MODEL& aBaseModel, unsigned aSymbolPinCount, const std::vector& aFields ); template static std::unique_ptr Create( unsigned 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 void ReadSpiceCode( const std::string& aSpiceCode ); template void ReadDataFields( unsigned aSymbolPinCount, const std::vector* aFields ); // C++ doesn't allow virtual template methods, so we do this: virtual void ReadDataSchFields( unsigned aSymbolPinCount, const std::vector* aFields ); virtual void ReadDataLibFields( unsigned aSymbolPinCount, const std::vector* aFields ); template void WriteFields( std::vector& aFields ) const; // C++ doesn't allow virtual template methods, so we do this: virtual void WriteDataSchFields( std::vector& aFields ) const; virtual void WriteDataLibFields( std::vector& aFields ) const; virtual bool HasToIncludeSpiceLibrary() const { return GetBaseModel() && !HasOverrides(); } virtual wxString GenerateSpiceModelLine( const wxString& aModelName ) const; virtual wxString GenerateSpiceItemName( const wxString& aRefName ) 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 GenerateSpiceTuningLine( const wxString& aSymbol ) const; virtual wxString GenerateSpicePreview( const wxString& aModelName ) const; SPICE_INFO GetSpiceInfo() const { return SpiceInfo( GetType() ); } virtual std::vector GenerateSpiceCurrentNames( const wxString& aRefName ) const; void AddPin( const PIN& aPin ); unsigned FindModelPinNumber( unsigned aSymbolPinNumber ); void AddParam( const PARAM::INFO& aInfo, bool aIsOtherVariant = false ); DEVICE_INFO GetDeviceTypeInfo() const { return DeviceTypeInfo( GetDeviceType() ); } INFO GetTypeInfo() const { return TypeInfo( GetType() ); } DEVICE_TYPE_ GetDeviceType() const { return GetTypeInfo().deviceType; } TYPE GetType() const { return m_type; } const SIM_MODEL* GetBaseModel() const { return m_baseModel; } virtual void SetBaseModel( const SIM_MODEL& aBaseModel ) { m_baseModel = &aBaseModel; } unsigned GetPinCount() const { return m_pins.size(); } const PIN& GetPin( unsigned aIndex ) const { return m_pins.at( aIndex ); } std::vector> GetPins() const; void SetPinSymbolPinNumber( int aIndex, int aSymbolPinNumber ) { m_pins.at( aIndex ).symbolPinNumber = aSymbolPinNumber; } unsigned GetParamCount() const { return m_params.size(); } const PARAM& GetParam( unsigned aParamIndex ) const; // Return base parameter unless it's overridden. const PARAM* FindParam( const wxString& aParamName ) const; std::vector> GetParams() const; const PARAM& GetUnderlyingParam( unsigned aParamIndex ) const; // Return the actual parameter. const PARAM& GetBaseParam( unsigned aParamIndex ) const; // Always return base parameter if it exists. virtual bool SetParamValue( unsigned aParamIndex, const wxString& aValue, SIM_VALUE_GRAMMAR::NOTATION aNotation = SIM_VALUE_GRAMMAR::NOTATION::SI ); bool SetParamValue( const wxString& aParamName, const wxString& aValue, SIM_VALUE_GRAMMAR::NOTATION aNotation = SIM_VALUE_GRAMMAR::NOTATION::SI ); bool HasOverrides() const; bool HasNonInstanceOverrides() const; bool HasSpiceNonInstanceOverrides() const; // Can modifying a model parameter also modify other parameters? virtual bool HasAutofill() const { return false; } void SetIsEnabled( bool aIsEnabled ) { m_isEnabled = aIsEnabled; } bool IsEnabled() const { return m_isEnabled; } protected: SIM_MODEL( TYPE aType ); template void WriteInferredDataFields( std::vector& aFields, const wxString& aValue ) const; virtual wxString GenerateParamValuePair( const PARAM& aParam, bool& aIsFirst ) const; wxString GenerateParamsField( const wxString& aPairSeparator ) const; void ParseParamsField( const wxString& aParamsField ); void ParsePinsField( unsigned aSymbolPinCount, const wxString& aPinsField ); void ParseDisabledField( const wxString& aDisabledField ); virtual bool SetParamFromSpiceCode( const wxString& aParamName, const wxString& aParamValue, SIM_VALUE_GRAMMAR::NOTATION aNotation = SIM_VALUE_GRAMMAR::NOTATION::SPICE ); template void InferredReadDataFields( unsigned aSymbolPinCount, const std::vector* aFields ); wxString m_spiceCode; private: static std::unique_ptr create( TYPE aType ); static TYPE readTypeFromSpiceStrings( const wxString& aTypeString, const wxString& aLevel = "", const wxString& aVersion = "", bool aSkipDefaultLevel = true ); template void doReadDataFields( unsigned aSymbolPinCount, const std::vector* aFields ); template void doWriteFields( std::vector& aFields ) const; virtual std::vector getPinNames() const { return {}; } wxString generateDeviceTypeField() const; wxString generateTypeField() const; wxString generatePinsField() const; wxString generateDisabledField() const; virtual bool requiresSpiceModel() const; const SIM_MODEL* m_baseModel; const TYPE m_type; std::vector m_pins; std::vector m_params; bool m_isEnabled; bool m_isInferred; }; #endif // SIM_MODEL_H