You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1621 lines
65 KiB

More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not.... Fixes https://gitlab.com/kicad/code/kicad/issues/13179
3 years ago
More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not.... Fixes https://gitlab.com/kicad/code/kicad/issues/13179
3 years ago
More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not.... Fixes https://gitlab.com/kicad/code/kicad/issues/13179
3 years ago
More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not.... Fixes https://gitlab.com/kicad/code/kicad/issues/13179
3 years ago
More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not.... Fixes https://gitlab.com/kicad/code/kicad/issues/13179
3 years ago
More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not.... Fixes https://gitlab.com/kicad/code/kicad/issues/13179
3 years ago
More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not.... Fixes https://gitlab.com/kicad/code/kicad/issues/13179
3 years ago
More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not.... Fixes https://gitlab.com/kicad/code/kicad/issues/13179
3 years ago
More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not....More bug fixes for escaped model parameters. Note that this whole escaping thing seems like a bad idea to me, but I don't fully understand the difference between model parameters and instance parameters so I don't know if there's a better way to handle it or not.... Fixes https://gitlab.com/kicad/code/kicad/issues/13179
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2022 Mikolaj Wielgus
  5. * Copyright (C) 2022 CERN
  6. * Copyright (C) 2022 KiCad Developers, see AUTHORS.txt for contributors.
  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 3
  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. * https://www.gnu.org/licenses/gpl-3.0.html
  21. * or you may search the http://www.gnu.org website for the version 3 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. #include <lib_symbol.h>
  26. #include <sch_symbol.h>
  27. #include <confirm.h>
  28. #include <string_utils.h>
  29. #include <wx/regex.h>
  30. #include <sim/sim_model.h>
  31. #include <sim/sim_model_behavioral.h>
  32. #include <sim/sim_model_ideal.h>
  33. #include <sim/sim_model_l_mutual.h>
  34. #include <sim/sim_model_ngspice.h>
  35. #include <sim/sim_model_r_pot.h>
  36. #include <sim/sim_model_kibis.h>
  37. #include <sim/sim_model_source.h>
  38. #include <sim/sim_model_raw_spice.h>
  39. #include <sim/sim_model_subckt.h>
  40. #include <sim/sim_model_switch.h>
  41. #include <sim/sim_model_tline.h>
  42. #include <sim/sim_model_xspice.h>
  43. #include <sim/sim_lib_mgr.h>
  44. #include <sim/sim_library_kibis.h>
  45. #include <boost/algorithm/string/case_conv.hpp>
  46. #include <fmt/core.h>
  47. #include <pegtl/contrib/parse_tree.hpp>
  48. #include <iterator>
  49. using TYPE = SIM_MODEL::TYPE;
  50. SIM_MODEL::DEVICE_INFO SIM_MODEL::DeviceInfo( DEVICE_T aDeviceType )
  51. {
  52. switch( aDeviceType )
  53. {
  54. case DEVICE_T::NONE: return { "", "", true };
  55. case DEVICE_T::R: return { "R", "Resistor", true };
  56. case DEVICE_T::C: return { "C", "Capacitor", true };
  57. case DEVICE_T::L: return { "L", "Inductor", true };
  58. case DEVICE_T::TLINE: return { "TLINE", "Transmission Line", true };
  59. case DEVICE_T::SW: return { "SW", "Switch", true };
  60. case DEVICE_T::D: return { "D", "Diode", true };
  61. case DEVICE_T::NPN: return { "NPN", "NPN BJT", true };
  62. case DEVICE_T::PNP: return { "PNP", "PNP BJT", true };
  63. case DEVICE_T::NJFET: return { "NJFET", "N-channel JFET", true };
  64. case DEVICE_T::PJFET: return { "PJFET", "P-channel JFET", true };
  65. case DEVICE_T::NMOS: return { "NMOS", "N-channel MOSFET", true };
  66. case DEVICE_T::PMOS: return { "PMOS", "P-channel MOSFET", true };
  67. case DEVICE_T::NMES: return { "NMES", "N-channel MESFET", true };
  68. case DEVICE_T::PMES: return { "PMES", "P-channel MESFET", true };
  69. case DEVICE_T::V: return { "V", "Voltage Source", true };
  70. case DEVICE_T::I: return { "I", "Current Source", true };
  71. case DEVICE_T::KIBIS: return { "IBIS", "IBIS Model", false };
  72. case DEVICE_T::SUBCKT: return { "SUBCKT", "Subcircuit", false };
  73. case DEVICE_T::XSPICE: return { "XSPICE", "XSPICE Code Model", true };
  74. case DEVICE_T::SPICE: return { "SPICE", "Raw Spice Element", true };
  75. default: wxFAIL; return {};
  76. }
  77. }
  78. SIM_MODEL::INFO SIM_MODEL::TypeInfo( TYPE aType )
  79. {
  80. switch( aType )
  81. {
  82. case TYPE::NONE: return { DEVICE_T::NONE, "", "" };
  83. case TYPE::R: return { DEVICE_T::R, "", "Ideal" };
  84. case TYPE::R_POT: return { DEVICE_T::R, "POT", "Potentiometer" };
  85. case TYPE::R_BEHAVIORAL: return { DEVICE_T::R, "=", "Behavioral" };
  86. case TYPE::C: return { DEVICE_T::C, "", "Ideal" };
  87. case TYPE::C_BEHAVIORAL: return { DEVICE_T::C, "=", "Behavioral" };
  88. case TYPE::L: return { DEVICE_T::L, "", "Ideal" };
  89. case TYPE::L_MUTUAL: return { DEVICE_T::L, "MUTUAL", "Mutual" };
  90. case TYPE::L_BEHAVIORAL: return { DEVICE_T::L, "=", "Behavioral" };
  91. case TYPE::TLINE_Z0: return { DEVICE_T::TLINE, "", "Characteristic impedance" };
  92. case TYPE::TLINE_RLGC: return { DEVICE_T::TLINE, "RLGC", "RLGC" };
  93. case TYPE::SW_V: return { DEVICE_T::SW, "V", "Voltage-controlled" };
  94. case TYPE::SW_I: return { DEVICE_T::SW, "I", "Current-controlled" };
  95. case TYPE::D: return { DEVICE_T::D, "", "" };
  96. case TYPE::NPN_VBIC: return { DEVICE_T::NPN, "VBIC", "VBIC" };
  97. case TYPE::PNP_VBIC: return { DEVICE_T::PNP, "VBIC", "VBIC" };
  98. case TYPE::NPN_GUMMELPOON: return { DEVICE_T::NPN, "GUMMELPOON", "Gummel-Poon" };
  99. case TYPE::PNP_GUMMELPOON: return { DEVICE_T::PNP, "GUMMELPOON", "Gummel-Poon" };
  100. //case TYPE::BJT_MEXTRAM: return {};
  101. case TYPE::NPN_HICUM2: return { DEVICE_T::NPN, "HICUML2", "HICUM level 2" };
  102. case TYPE::PNP_HICUM2: return { DEVICE_T::PNP, "HICUML2", "HICUM level 2" };
  103. //case TYPE::BJT_HICUM_L0: return {};
  104. case TYPE::NJFET_SHICHMANHODGES: return { DEVICE_T::NJFET, "SHICHMANHODGES", "Shichman-Hodges" };
  105. case TYPE::PJFET_SHICHMANHODGES: return { DEVICE_T::PJFET, "SHICHMANHODGES", "Shichman-Hodges" };
  106. case TYPE::NJFET_PARKERSKELLERN: return { DEVICE_T::NJFET, "PARKERSKELLERN", "Parker-Skellern" };
  107. case TYPE::PJFET_PARKERSKELLERN: return { DEVICE_T::PJFET, "PARKERSKELLERN", "Parker-Skellern" };
  108. case TYPE::NMES_STATZ: return { DEVICE_T::NMES, "STATZ", "Statz" };
  109. case TYPE::PMES_STATZ: return { DEVICE_T::PMES, "STATZ", "Statz" };
  110. case TYPE::NMES_YTTERDAL: return { DEVICE_T::NMES, "YTTERDAL", "Ytterdal" };
  111. case TYPE::PMES_YTTERDAL: return { DEVICE_T::PMES, "YTTERDAL", "Ytterdal" };
  112. case TYPE::NMES_HFET1: return { DEVICE_T::NMES, "HFET1", "HFET1" };
  113. case TYPE::PMES_HFET1: return { DEVICE_T::PMES, "HFET1", "HFET1" };
  114. case TYPE::NMES_HFET2: return { DEVICE_T::NMES, "HFET2", "HFET2" };
  115. case TYPE::PMES_HFET2: return { DEVICE_T::PMES, "HFET2", "HFET2" };
  116. case TYPE::NMOS_VDMOS: return { DEVICE_T::NMOS, "VDMOS", "VDMOS" };
  117. case TYPE::PMOS_VDMOS: return { DEVICE_T::PMOS, "VDMOS", "VDMOS" };
  118. case TYPE::NMOS_MOS1: return { DEVICE_T::NMOS, "MOS1", "Classical quadratic (MOS1)" };
  119. case TYPE::PMOS_MOS1: return { DEVICE_T::PMOS, "MOS1", "Classical quadratic (MOS1)" };
  120. case TYPE::NMOS_MOS2: return { DEVICE_T::NMOS, "MOS2", "Grove-Frohman (MOS2)" };
  121. case TYPE::PMOS_MOS2: return { DEVICE_T::PMOS, "MOS2", "Grove-Frohman (MOS2)" };
  122. case TYPE::NMOS_MOS3: return { DEVICE_T::NMOS, "MOS3", "MOS3" };
  123. case TYPE::PMOS_MOS3: return { DEVICE_T::PMOS, "MOS3", "MOS3" };
  124. case TYPE::NMOS_BSIM1: return { DEVICE_T::NMOS, "BSIM1", "BSIM1" };
  125. case TYPE::PMOS_BSIM1: return { DEVICE_T::PMOS, "BSIM1", "BSIM1" };
  126. case TYPE::NMOS_BSIM2: return { DEVICE_T::NMOS, "BSIM2", "BSIM2" };
  127. case TYPE::PMOS_BSIM2: return { DEVICE_T::PMOS, "BSIM2", "BSIM2" };
  128. case TYPE::NMOS_MOS6: return { DEVICE_T::NMOS, "MOS6", "MOS6" };
  129. case TYPE::PMOS_MOS6: return { DEVICE_T::PMOS, "MOS6", "MOS6" };
  130. case TYPE::NMOS_BSIM3: return { DEVICE_T::NMOS, "BSIM3", "BSIM3" };
  131. case TYPE::PMOS_BSIM3: return { DEVICE_T::PMOS, "BSIM3", "BSIM3" };
  132. case TYPE::NMOS_MOS9: return { DEVICE_T::NMOS, "MOS9", "MOS9" };
  133. case TYPE::PMOS_MOS9: return { DEVICE_T::PMOS, "MOS9", "MOS9" };
  134. case TYPE::NMOS_B4SOI: return { DEVICE_T::NMOS, "B4SOI", "BSIM4 SOI (B4SOI)" };
  135. case TYPE::PMOS_B4SOI: return { DEVICE_T::PMOS, "B4SOI", "BSIM4 SOI (B4SOI)" };
  136. case TYPE::NMOS_BSIM4: return { DEVICE_T::NMOS, "BSIM4", "BSIM4" };
  137. case TYPE::PMOS_BSIM4: return { DEVICE_T::PMOS, "BSIM4", "BSIM4" };
  138. //case TYPE::NMOS_EKV2_6: return {};
  139. //case TYPE::PMOS_EKV2_6: return {};
  140. //case TYPE::NMOS_PSP: return {};
  141. //case TYPE::PMOS_PSP: return {};
  142. case TYPE::NMOS_B3SOIFD: return { DEVICE_T::NMOS, "B3SOIFD", "B3SOIFD (BSIM3 FD-SOI)" };
  143. case TYPE::PMOS_B3SOIFD: return { DEVICE_T::PMOS, "B3SOIFD", "B3SOIFD (BSIM3 FD-SOI)" };
  144. case TYPE::NMOS_B3SOIDD: return { DEVICE_T::NMOS, "B3SOIDD", "B3SOIDD (BSIM3 SOI)" };
  145. case TYPE::PMOS_B3SOIDD: return { DEVICE_T::PMOS, "B3SOIDD", "B3SOIDD (BSIM3 SOI)" };
  146. case TYPE::NMOS_B3SOIPD: return { DEVICE_T::NMOS, "B3SOIPD", "B3SOIPD (BSIM3 PD-SOI)" };
  147. case TYPE::PMOS_B3SOIPD: return { DEVICE_T::PMOS, "B3SOIPD", "B3SOIPD (BSIM3 PD-SOI)" };
  148. //case TYPE::NMOS_STAG: return {};
  149. //case TYPE::PMOS_STAG: return {};
  150. case TYPE::NMOS_HISIM2: return { DEVICE_T::NMOS, "HISIM2", "HiSIM2" };
  151. case TYPE::PMOS_HISIM2: return { DEVICE_T::PMOS, "HISIM2", "HiSIM2" };
  152. case TYPE::NMOS_HISIMHV1: return { DEVICE_T::NMOS, "HISIMHV1", "HiSIM_HV1" };
  153. case TYPE::PMOS_HISIMHV1: return { DEVICE_T::PMOS, "HISIMHV1", "HiSIM_HV1" };
  154. case TYPE::NMOS_HISIMHV2: return { DEVICE_T::NMOS, "HISIMHV2", "HiSIM_HV2" };
  155. case TYPE::PMOS_HISIMHV2: return { DEVICE_T::PMOS, "HISIMHV2", "HiSIM_HV2" };
  156. case TYPE::V: return { DEVICE_T::V, "DC", "DC", };
  157. case TYPE::V_SIN: return { DEVICE_T::V, "SIN", "Sine" };
  158. case TYPE::V_PULSE: return { DEVICE_T::V, "PULSE", "Pulse" };
  159. case TYPE::V_EXP: return { DEVICE_T::V, "EXP", "Exponential" };
  160. /*case TYPE::V_SFAM: return { DEVICE_TYPE::V, "SFAM", "Single-frequency AM" };
  161. case TYPE::V_SFFM: return { DEVICE_TYPE::V, "SFFM", "Single-frequency FM" };*/
  162. case TYPE::V_PWL: return { DEVICE_T::V, "PWL", "Piecewise linear" };
  163. case TYPE::V_WHITENOISE: return { DEVICE_T::V, "WHITENOISE", "White noise" };
  164. case TYPE::V_PINKNOISE: return { DEVICE_T::V, "PINKNOISE", "Pink noise (1/f)" };
  165. case TYPE::V_BURSTNOISE: return { DEVICE_T::V, "BURSTNOISE", "Burst noise" };
  166. case TYPE::V_RANDUNIFORM: return { DEVICE_T::V, "RANDUNIFORM", "Random uniform" };
  167. case TYPE::V_RANDNORMAL: return { DEVICE_T::V, "RANDNORMAL", "Random normal" };
  168. case TYPE::V_RANDEXP: return { DEVICE_T::V, "RANDEXP", "Random exponential" };
  169. //case TYPE::V_RANDPOISSON: return { DEVICE_TYPE::V, "RANDPOISSON", "Random Poisson" };
  170. case TYPE::V_BEHAVIORAL: return { DEVICE_T::V, "=", "Behavioral" };
  171. case TYPE::I: return { DEVICE_T::I, "DC", "DC", };
  172. case TYPE::I_SIN: return { DEVICE_T::I, "SIN", "Sine" };
  173. case TYPE::I_PULSE: return { DEVICE_T::I, "PULSE", "Pulse" };
  174. case TYPE::I_EXP: return { DEVICE_T::I, "EXP", "Exponential" };
  175. /*case TYPE::I_SFAM: return { DEVICE_TYPE::I, "SFAM", "Single-frequency AM" };
  176. case TYPE::I_SFFM: return { DEVICE_TYPE::I, "SFFM", "Single-frequency FM" };*/
  177. case TYPE::I_PWL: return { DEVICE_T::I, "PWL", "Piecewise linear" };
  178. case TYPE::I_WHITENOISE: return { DEVICE_T::I, "WHITENOISE", "White noise" };
  179. case TYPE::I_PINKNOISE: return { DEVICE_T::I, "PINKNOISE", "Pink noise (1/f)" };
  180. case TYPE::I_BURSTNOISE: return { DEVICE_T::I, "BURSTNOISE", "Burst noise" };
  181. case TYPE::I_RANDUNIFORM: return { DEVICE_T::I, "RANDUNIFORM", "Random uniform" };
  182. case TYPE::I_RANDNORMAL: return { DEVICE_T::I, "RANDNORMAL", "Random normal" };
  183. case TYPE::I_RANDEXP: return { DEVICE_T::I, "RANDEXP", "Random exponential" };
  184. //case TYPE::I_RANDPOISSON: return { DEVICE_TYPE::I, "RANDPOISSON", "Random Poisson" };
  185. case TYPE::I_BEHAVIORAL: return { DEVICE_T::I, "=", "Behavioral" };
  186. case TYPE::SUBCKT: return { DEVICE_T::SUBCKT, "", "" };
  187. case TYPE::XSPICE: return { DEVICE_T::XSPICE, "", "" };
  188. case TYPE::KIBIS_DEVICE: return { DEVICE_T::KIBIS, "DEVICE", "Device" };
  189. case TYPE::KIBIS_DRIVER_DC: return { DEVICE_T::KIBIS, "DCDRIVER", "DC driver" };
  190. case TYPE::KIBIS_DRIVER_RECT: return { DEVICE_T::KIBIS, "RECTDRIVER", "Rectangular wave driver" };
  191. case TYPE::KIBIS_DRIVER_PRBS: return { DEVICE_T::KIBIS, "PRBSDRIVER", "PRBS driver" };
  192. case TYPE::RAWSPICE: return { DEVICE_T::SPICE, "", "" };
  193. default: wxFAIL; return {};
  194. }
  195. }
  196. SIM_MODEL::SPICE_INFO SIM_MODEL::SpiceInfo( TYPE aType )
  197. {
  198. switch( aType )
  199. {
  200. case TYPE::R: return { "R", "" };
  201. case TYPE::R_POT: return { "A", "" };
  202. case TYPE::R_BEHAVIORAL: return { "R", "", "", "0", false, true };
  203. case TYPE::C: return { "C", "" };
  204. case TYPE::C_BEHAVIORAL: return { "C", "", "", "0", false, true };
  205. case TYPE::L: return { "L", "" };
  206. case TYPE::L_MUTUAL: return { "K", "" };
  207. case TYPE::L_BEHAVIORAL: return { "L", "", "", "0", false, true };
  208. //case TYPE::TLINE_Z0: return { "T" };
  209. case TYPE::TLINE_Z0: return { "O", "LTRA" };
  210. case TYPE::TLINE_RLGC: return { "O", "LTRA" };
  211. case TYPE::SW_V: return { "S", "SW" };
  212. case TYPE::SW_I: return { "W", "CSW" };
  213. case TYPE::D: return { "D", "D" };
  214. case TYPE::NPN_VBIC: return { "Q", "NPN", "", "4" };
  215. case TYPE::PNP_VBIC: return { "Q", "PNP", "", "4" };
  216. case TYPE::NPN_GUMMELPOON: return { "Q", "NPN", "", "1", true };
  217. case TYPE::PNP_GUMMELPOON: return { "Q", "PNP", "", "1", true };
  218. case TYPE::NPN_HICUM2: return { "Q", "NPN", "", "8" };
  219. case TYPE::PNP_HICUM2: return { "Q", "PNP", "", "8" };
  220. case TYPE::NJFET_SHICHMANHODGES: return { "M", "NJF", "", "1" };
  221. case TYPE::PJFET_SHICHMANHODGES: return { "M", "PJF", "", "1" };
  222. case TYPE::NJFET_PARKERSKELLERN: return { "M", "NJF", "", "2" };
  223. case TYPE::PJFET_PARKERSKELLERN: return { "M", "PJF", "", "2" };
  224. case TYPE::NMES_STATZ: return { "Z", "NMF", "", "1" };
  225. case TYPE::PMES_STATZ: return { "Z", "PMF", "", "1" };
  226. case TYPE::NMES_YTTERDAL: return { "Z", "NMF", "", "2" };
  227. case TYPE::PMES_YTTERDAL: return { "Z", "PMF", "", "2" };
  228. case TYPE::NMES_HFET1: return { "Z", "NMF", "", "5" };
  229. case TYPE::PMES_HFET1: return { "Z", "PMF", "", "5" };
  230. case TYPE::NMES_HFET2: return { "Z", "NMF", "", "6" };
  231. case TYPE::PMES_HFET2: return { "Z", "PMF", "", "6" };
  232. case TYPE::NMOS_VDMOS: return { "M", "VDMOS NCHAN", };
  233. case TYPE::PMOS_VDMOS: return { "M", "VDMOS PCHAN", };
  234. case TYPE::NMOS_MOS1: return { "M", "NMOS", "", "1" };
  235. case TYPE::PMOS_MOS1: return { "M", "PMOS", "", "1" };
  236. case TYPE::NMOS_MOS2: return { "M", "NMOS", "", "2" };
  237. case TYPE::PMOS_MOS2: return { "M", "PMOS", "", "2" };
  238. case TYPE::NMOS_MOS3: return { "M", "NMOS", "", "3" };
  239. case TYPE::PMOS_MOS3: return { "M", "PMOS", "", "3" };
  240. case TYPE::NMOS_BSIM1: return { "M", "NMOS", "", "4" };
  241. case TYPE::PMOS_BSIM1: return { "M", "PMOS", "", "4" };
  242. case TYPE::NMOS_BSIM2: return { "M", "NMOS", "", "5" };
  243. case TYPE::PMOS_BSIM2: return { "M", "PMOS", "", "5" };
  244. case TYPE::NMOS_MOS6: return { "M", "NMOS", "", "6" };
  245. case TYPE::PMOS_MOS6: return { "M", "PMOS", "", "6" };
  246. case TYPE::NMOS_BSIM3: return { "M", "NMOS", "", "8" };
  247. case TYPE::PMOS_BSIM3: return { "M", "PMOS", "", "8" };
  248. case TYPE::NMOS_MOS9: return { "M", "NMOS", "", "9" };
  249. case TYPE::PMOS_MOS9: return { "M", "PMOS", "", "9" };
  250. case TYPE::NMOS_B4SOI: return { "M", "NMOS", "", "10" };
  251. case TYPE::PMOS_B4SOI: return { "M", "PMOS", "", "10" };
  252. case TYPE::NMOS_BSIM4: return { "M", "NMOS", "", "14" };
  253. case TYPE::PMOS_BSIM4: return { "M", "PMOS", "", "14" };
  254. //case TYPE::NMOS_EKV2_6: return {};
  255. //case TYPE::PMOS_EKV2_6: return {};
  256. //case TYPE::NMOS_PSP: return {};
  257. //case TYPE::PMOS_PSP: return {};
  258. case TYPE::NMOS_B3SOIFD: return { "M", "NMOS", "", "55" };
  259. case TYPE::PMOS_B3SOIFD: return { "M", "PMOS", "", "55" };
  260. case TYPE::NMOS_B3SOIDD: return { "M", "NMOS", "", "56" };
  261. case TYPE::PMOS_B3SOIDD: return { "M", "PMOS", "", "56" };
  262. case TYPE::NMOS_B3SOIPD: return { "M", "NMOS", "", "57" };
  263. case TYPE::PMOS_B3SOIPD: return { "M", "PMOS", "", "57" };
  264. //case TYPE::NMOS_STAG: return {};
  265. //case TYPE::PMOS_STAG: return {};
  266. case TYPE::NMOS_HISIM2: return { "M", "NMOS", "", "68" };
  267. case TYPE::PMOS_HISIM2: return { "M", "PMOS", "", "68" };
  268. case TYPE::NMOS_HISIMHV1: return { "M", "NMOS", "", "73", true, false, "1.2.4" };
  269. case TYPE::PMOS_HISIMHV1: return { "M", "PMOS", "", "73", true, false, "1.2.4" };
  270. case TYPE::NMOS_HISIMHV2: return { "M", "NMOS", "", "73", true, false, "2.2.0" };
  271. case TYPE::PMOS_HISIMHV2: return { "M", "PMOS", "", "73", true, false, "2.2.0" };
  272. case TYPE::V: return { "V", "", "DC" };
  273. case TYPE::V_SIN: return { "V", "", "SIN" };
  274. case TYPE::V_PULSE: return { "V", "", "PULSE" };
  275. case TYPE::V_EXP: return { "V", "", "EXP" };
  276. //case TYPE::V_SFAM: return { "V", "", "AM" };
  277. //case TYPE::V_SFFM: return { "V", "", "SFFM" };
  278. case TYPE::V_PWL: return { "V", "", "PWL" };
  279. case TYPE::V_WHITENOISE: return { "V", "", "TRNOISE" };
  280. case TYPE::V_PINKNOISE: return { "V", "", "TRNOISE" };
  281. case TYPE::V_BURSTNOISE: return { "V", "", "TRNOISE" };
  282. case TYPE::V_RANDUNIFORM: return { "V", "", "TRRANDOM" };
  283. case TYPE::V_RANDNORMAL: return { "V", "", "TRRANDOM" };
  284. case TYPE::V_RANDEXP: return { "V", "", "TRRANDOM" };
  285. //case TYPE::V_RANDPOISSON: return { "V", "", "TRRANDOM" };
  286. case TYPE::V_BEHAVIORAL: return { "B" };
  287. case TYPE::I: return { "I", "", "DC" };
  288. case TYPE::I_PULSE: return { "I", "", "PULSE" };
  289. case TYPE::I_SIN: return { "I", "", "SIN" };
  290. case TYPE::I_EXP: return { "I", "", "EXP" };
  291. //case TYPE::I_SFAM: return { "V", "", "AM" };
  292. //case TYPE::I_SFFM: return { "V", "", "SFFM" };
  293. case TYPE::I_PWL: return { "I", "", "PWL" };
  294. case TYPE::I_WHITENOISE: return { "I", "", "TRNOISE" };
  295. case TYPE::I_PINKNOISE: return { "I", "", "TRNOISE" };
  296. case TYPE::I_BURSTNOISE: return { "I", "", "TRNOISE" };
  297. case TYPE::I_RANDUNIFORM: return { "I", "", "TRRANDOM" };
  298. case TYPE::I_RANDNORMAL: return { "I", "", "TRRANDOM" };
  299. case TYPE::I_RANDEXP: return { "I", "", "TRRANDOM" };
  300. //case TYPE::I_RANDPOISSON: return { "I", "", "TRRANDOM" };
  301. case TYPE::I_BEHAVIORAL: return { "B" };
  302. case TYPE::SUBCKT: return { "X" };
  303. case TYPE::XSPICE: return { "A" };
  304. case TYPE::KIBIS_DEVICE: return { "X" };
  305. case TYPE::KIBIS_DRIVER_DC: return { "X" };
  306. case TYPE::KIBIS_DRIVER_RECT: return { "X" };
  307. case TYPE::KIBIS_DRIVER_PRBS: return { "X" };
  308. case TYPE::NONE:
  309. case TYPE::RAWSPICE: return {};
  310. default: wxFAIL; return {};
  311. }
  312. }
  313. template TYPE SIM_MODEL::ReadTypeFromFields( const std::vector<SCH_FIELD>& aFields );
  314. template TYPE SIM_MODEL::ReadTypeFromFields( const std::vector<LIB_FIELD>& aFields );
  315. template <typename T>
  316. TYPE SIM_MODEL::ReadTypeFromFields( const std::vector<T>& aFields )
  317. {
  318. std::string deviceTypeFieldValue = GetFieldValue( &aFields, DEVICE_TYPE_FIELD );
  319. std::string typeFieldValue = GetFieldValue( &aFields, TYPE_FIELD );
  320. if( deviceTypeFieldValue != "" )
  321. {
  322. for( TYPE type : TYPE_ITERATOR() )
  323. {
  324. if( typeFieldValue == TypeInfo( type ).fieldValue )
  325. {
  326. if( deviceTypeFieldValue == DeviceInfo( TypeInfo( type ).deviceType ).fieldValue )
  327. return type;
  328. }
  329. }
  330. }
  331. if( typeFieldValue != "" )
  332. return TYPE::NONE;
  333. // No type information. Look for legacy (pre-V7) fields.
  334. TYPE typeFromLegacyFields = InferTypeFromLegacyFields( aFields );
  335. if( typeFromLegacyFields != TYPE::NONE )
  336. return typeFromLegacyFields;
  337. return TYPE::NONE;
  338. }
  339. template <typename T>
  340. TYPE SIM_MODEL::InferTypeFromLegacyFields( const std::vector<T>& aFields )
  341. {
  342. if( GetFieldValue( &aFields, SIM_MODEL_RAW_SPICE::LEGACY_TYPE_FIELD ) != ""
  343. || GetFieldValue( &aFields, SIM_MODEL_RAW_SPICE::LEGACY_MODEL_FIELD ) != ""
  344. || GetFieldValue( &aFields, SIM_MODEL_RAW_SPICE::LEGACY_ENABLED_FIELD ) != ""
  345. || GetFieldValue( &aFields, SIM_MODEL_RAW_SPICE::LEGACY_LIB_FIELD ) != "" )
  346. {
  347. return TYPE::RAWSPICE;
  348. }
  349. else
  350. {
  351. return TYPE::NONE;
  352. }
  353. }
  354. template <>
  355. void SIM_MODEL::ReadDataFields( const std::vector<SCH_FIELD>* aFields,
  356. const std::vector<LIB_PIN*>& aPins )
  357. {
  358. doReadDataFields( aFields, aPins );
  359. }
  360. template <>
  361. void SIM_MODEL::ReadDataFields( const std::vector<LIB_FIELD>* aFields,
  362. const std::vector<LIB_PIN*>& aPins )
  363. {
  364. doReadDataFields( aFields, aPins );
  365. }
  366. template <>
  367. void SIM_MODEL::WriteFields( std::vector<SCH_FIELD>& aFields ) const
  368. {
  369. doWriteFields( aFields );
  370. }
  371. template <>
  372. void SIM_MODEL::WriteFields( std::vector<LIB_FIELD>& aFields ) const
  373. {
  374. doWriteFields( aFields );
  375. }
  376. std::unique_ptr<SIM_MODEL> SIM_MODEL::Create( TYPE aType, const std::vector<LIB_PIN*>& aPins )
  377. {
  378. std::unique_ptr<SIM_MODEL> model = Create( aType );
  379. // Passing nullptr to ReadDataFields will make it act as if all fields were empty.
  380. model->ReadDataFields( static_cast<const std::vector<SCH_FIELD>*>( nullptr ), aPins );
  381. return model;
  382. }
  383. std::unique_ptr<SIM_MODEL> SIM_MODEL::Create( const SIM_MODEL& aBaseModel,
  384. const std::vector<LIB_PIN*>& aPins)
  385. {
  386. std::unique_ptr<SIM_MODEL> model = Create( aBaseModel.GetType() );
  387. try
  388. {
  389. model->SetBaseModel( aBaseModel );
  390. }
  391. catch( IO_ERROR& err )
  392. {
  393. DisplayErrorMessage( nullptr, err.What() );
  394. }
  395. model->ReadDataFields( static_cast<const std::vector<SCH_FIELD>*>( nullptr ), aPins );
  396. return model;
  397. }
  398. template <typename T>
  399. std::unique_ptr<SIM_MODEL> SIM_MODEL::Create( const SIM_MODEL& aBaseModel,
  400. const std::vector<LIB_PIN*>& aPins,
  401. const std::vector<T>& aFields )
  402. {
  403. TYPE type = ReadTypeFromFields( aFields );
  404. // If the model has a specified type, it takes priority over the type of its base class.
  405. if( type == TYPE::NONE )
  406. type = aBaseModel.GetType();
  407. std::unique_ptr<SIM_MODEL> model = Create( type );
  408. try
  409. {
  410. model->SetBaseModel( aBaseModel );
  411. }
  412. catch( IO_ERROR& err )
  413. {
  414. DisplayErrorMessage( nullptr, err.What() );
  415. }
  416. model->ReadDataFields( &aFields, aPins );
  417. return model;
  418. }
  419. template std::unique_ptr<SIM_MODEL> SIM_MODEL::Create( const SIM_MODEL& aBaseModel,
  420. const std::vector<LIB_PIN*>& aPins,
  421. const std::vector<SCH_FIELD>& aFields );
  422. template std::unique_ptr<SIM_MODEL> SIM_MODEL::Create( const SIM_MODEL& aBaseModel,
  423. const std::vector<LIB_PIN*>& aPins,
  424. const std::vector<LIB_FIELD>& aFields );
  425. template <typename T>
  426. std::unique_ptr<SIM_MODEL> SIM_MODEL::Create( const std::vector<T>& aFields,
  427. const std::vector<LIB_PIN*>& aPins )
  428. {
  429. TYPE type = ReadTypeFromFields( aFields );
  430. std::unique_ptr<SIM_MODEL> model = SIM_MODEL::Create( type );
  431. model->ReadDataFields( &aFields, aPins );
  432. return model;
  433. }
  434. template std::unique_ptr<SIM_MODEL> SIM_MODEL::Create( const std::vector<SCH_FIELD>& aFields,
  435. const std::vector<LIB_PIN*>& aPins );
  436. template std::unique_ptr<SIM_MODEL> SIM_MODEL::Create( const std::vector<LIB_FIELD>& aFields,
  437. const std::vector<LIB_PIN*>& aPins );
  438. template <typename T>
  439. std::string SIM_MODEL::GetFieldValue( const std::vector<T>* aFields, const std::string& aFieldName,
  440. bool aResolve )
  441. {
  442. static_assert( std::is_same<T, SCH_FIELD>::value || std::is_same<T, LIB_FIELD>::value );
  443. if( !aFields )
  444. return ""; // Should not happen, T=void specialization will be called instead.
  445. auto it = std::find_if( aFields->begin(), aFields->end(),
  446. [aFieldName]( const T& field )
  447. {
  448. return field.GetName() == aFieldName;
  449. } );
  450. if( it == aFields->end() )
  451. return "";
  452. else if( aResolve )
  453. return std::string( it->GetShownText().ToUTF8() );
  454. else
  455. return std::string( it->GetText().ToUTF8() );
  456. }
  457. // This specialization is used when no fields are passed.
  458. template <>
  459. std::string SIM_MODEL::GetFieldValue( const std::vector<void>* aFields,
  460. const std::string& aFieldName, bool aResolve )
  461. {
  462. return "";
  463. }
  464. template <typename T>
  465. void SIM_MODEL::SetFieldValue( std::vector<T>& aFields, const std::string& aFieldName,
  466. const std::string& aValue )
  467. {
  468. static_assert( std::is_same<T, SCH_FIELD>::value || std::is_same<T, LIB_FIELD>::value );
  469. auto fieldIt = std::find_if( aFields.begin(), aFields.end(),
  470. [&]( const T& f )
  471. {
  472. return f.GetName() == aFieldName;
  473. } );
  474. if( fieldIt != aFields.end() )
  475. {
  476. if( aValue == "" )
  477. aFields.erase( fieldIt );
  478. else
  479. fieldIt->SetText( aValue );
  480. return;
  481. }
  482. if( aValue == "" )
  483. return;
  484. if constexpr( std::is_same<T, SCH_FIELD>::value )
  485. {
  486. wxASSERT( aFields.size() >= 1 );
  487. SCH_ITEM* parent = static_cast<SCH_ITEM*>( aFields.at( 0 ).GetParent() );
  488. aFields.emplace_back( wxPoint(), aFields.size(), parent, aFieldName );
  489. }
  490. else if constexpr( std::is_same<T, LIB_FIELD>::value )
  491. {
  492. aFields.emplace_back( aFields.size(), aFieldName );
  493. }
  494. aFields.back().SetText( aValue );
  495. }
  496. template void SIM_MODEL::SetFieldValue<SCH_FIELD>( std::vector<SCH_FIELD>& aFields,
  497. const std::string& aFieldName,
  498. const std::string& aValue );
  499. template void SIM_MODEL::SetFieldValue<LIB_FIELD>( std::vector<LIB_FIELD>& aFields,
  500. const std::string& aFieldName,
  501. const std::string& aValue );
  502. SIM_MODEL::~SIM_MODEL() = default;
  503. void SIM_MODEL::AddPin( const PIN& aPin )
  504. {
  505. m_pins.push_back( aPin );
  506. }
  507. void SIM_MODEL::ClearPins()
  508. {
  509. m_pins.clear();
  510. }
  511. int SIM_MODEL::FindModelPinIndex( const std::string& aSymbolPinNumber )
  512. {
  513. for( int modelPinIndex = 0; modelPinIndex < GetPinCount(); ++modelPinIndex )
  514. {
  515. if( GetPin( modelPinIndex ).symbolPinNumber == aSymbolPinNumber )
  516. return modelPinIndex;
  517. }
  518. return PIN::NOT_CONNECTED;
  519. }
  520. void SIM_MODEL::AddParam( const PARAM::INFO& aInfo, bool aIsOtherVariant )
  521. {
  522. m_params.emplace_back( aInfo, aIsOtherVariant );
  523. // Enums are initialized with their default values.
  524. if( aInfo.enumValues.size() >= 1 )
  525. m_params.back().value->FromString( aInfo.defaultValue );
  526. }
  527. std::vector<std::reference_wrapper<const SIM_MODEL::PIN>> SIM_MODEL::GetPins() const
  528. {
  529. std::vector<std::reference_wrapper<const PIN>> pins;
  530. for( int modelPinIndex = 0; modelPinIndex < GetPinCount(); ++modelPinIndex )
  531. pins.emplace_back( GetPin( modelPinIndex ) );
  532. return pins;
  533. }
  534. void SIM_MODEL::SetPinSymbolPinNumber( int aPinIndex, const std::string& aSymbolPinNumber )
  535. {
  536. m_pins.at( aPinIndex ).symbolPinNumber = aSymbolPinNumber;
  537. }
  538. void SIM_MODEL::SetPinSymbolPinNumber( const std::string& aPinName,
  539. const std::string& aSymbolPinNumber )
  540. {
  541. int aPinIndex = -1;
  542. const std::vector<std::reference_wrapper<const PIN>> pins = GetPins();
  543. for( int ii = 0; ii < (int) pins.size(); ++ii )
  544. {
  545. if( pins.at( ii ).get().name == aPinName )
  546. {
  547. aPinIndex = ii;
  548. break;
  549. }
  550. }
  551. if( aPinIndex < 0 )
  552. {
  553. // If aPinName wasn't in fact a name, see if it's a raw (1-based) index. This is
  554. // required for legacy files which didn't use pin names.
  555. aPinIndex = (int) strtol( aPinName.c_str(), nullptr, 10 );
  556. // Convert to 0-based. (Note that this will also convert the error state to -1, which
  557. // means we don't have to check for it separately.)
  558. aPinIndex--;
  559. }
  560. if( aPinIndex < 0 )
  561. {
  562. THROW_IO_ERROR( wxString::Format( _( "Could not find a pin named '%s' in "
  563. "simulation model of type '%s'" ),
  564. aPinName,
  565. GetTypeInfo().fieldValue ) );
  566. }
  567. SetPinSymbolPinNumber( aPinIndex, aSymbolPinNumber );
  568. }
  569. const SIM_MODEL::PARAM& SIM_MODEL::GetParam( unsigned aParamIndex ) const
  570. {
  571. if( m_baseModel && m_params.at( aParamIndex ).value->ToString() == "" )
  572. return m_baseModel->GetParam( aParamIndex );
  573. else
  574. return m_params.at( aParamIndex );
  575. }
  576. const SIM_MODEL::PARAM* SIM_MODEL::FindParam( const std::string& aParamName ) const
  577. {
  578. std::string lowerParamName = boost::to_lower_copy( aParamName );
  579. std::vector<std::reference_wrapper<const PARAM>> params = GetParams();
  580. auto it = std::find_if( params.begin(), params.end(),
  581. [lowerParamName]( const PARAM& param )
  582. {
  583. return param.info.name == lowerParamName;
  584. } );
  585. // Also check for model params that had to be escaped due to collisions with instance
  586. // params.
  587. if( it == params.end() )
  588. {
  589. it = std::find_if( params.begin(), params.end(),
  590. [lowerParamName]( const PARAM& param )
  591. {
  592. return param.info.name == lowerParamName + "_";
  593. } );
  594. }
  595. if( it == params.end() )
  596. return nullptr;
  597. return &it->get();
  598. }
  599. std::vector<std::reference_wrapper<const SIM_MODEL::PARAM>> SIM_MODEL::GetParams() const
  600. {
  601. std::vector<std::reference_wrapper<const PARAM>> params;
  602. for( int i = 0; i < GetParamCount(); ++i )
  603. params.emplace_back( GetParam( i ) );
  604. return params;
  605. }
  606. const SIM_MODEL::PARAM& SIM_MODEL::GetParamOverride( unsigned aParamIndex ) const
  607. {
  608. return m_params.at( aParamIndex );
  609. }
  610. const SIM_MODEL::PARAM& SIM_MODEL::GetBaseParam( unsigned aParamIndex ) const
  611. {
  612. if( m_baseModel )
  613. return m_baseModel->GetParam( aParamIndex );
  614. else
  615. return m_params.at( aParamIndex );
  616. }
  617. void SIM_MODEL::SetParamValue( int aParamIndex, const SIM_VALUE& aValue )
  618. {
  619. *m_params.at( aParamIndex ).value = aValue;
  620. }
  621. void SIM_MODEL::SetParamValue( int aParamIndex, const std::string& aValue,
  622. SIM_VALUE::NOTATION aNotation )
  623. {
  624. const SIM_VALUE& value = *GetParam( aParamIndex ).value;
  625. SetParamValue( aParamIndex, *SIM_VALUE::Create( value.GetType(), aValue, aNotation ) );
  626. }
  627. void SIM_MODEL::SetParamValue( const std::string& aParamName, const SIM_VALUE& aValue )
  628. {
  629. std::string lowerParamName = boost::to_lower_copy( aParamName );
  630. std::vector<std::reference_wrapper<const PARAM>> params = GetParams();
  631. auto it = std::find_if( params.begin(), params.end(),
  632. [lowerParamName]( const PARAM& param )
  633. {
  634. return param.info.name == lowerParamName;
  635. } );
  636. // Also check for model params that had to be escaped due to collisions with instance
  637. // params.
  638. if( it == params.end() )
  639. {
  640. it = std::find_if( params.begin(), params.end(),
  641. [lowerParamName]( const PARAM& param )
  642. {
  643. return param.info.name == lowerParamName + "_";
  644. } );
  645. }
  646. if( it == params.end() )
  647. {
  648. THROW_IO_ERROR( wxString::Format( _( "Could not find a parameter named '%s' in "
  649. "simulation model of type '%s'" ),
  650. aParamName,
  651. GetTypeInfo().fieldValue ) );
  652. }
  653. SetParamValue( static_cast<int>( it - params.begin() ), aValue );
  654. }
  655. void SIM_MODEL::SetParamValue( const std::string& aParamName, const std::string& aValue,
  656. SIM_VALUE::NOTATION aNotation )
  657. {
  658. const PARAM* param = FindParam( aParamName );
  659. if( !param )
  660. {
  661. THROW_IO_ERROR( wxString::Format( _( "Could not find a parameter named '%s' in "
  662. "simulation model of type '%s'" ),
  663. aParamName,
  664. GetTypeInfo().fieldValue ) );
  665. }
  666. const SIM_VALUE& value = *FindParam( aParamName )->value;
  667. SetParamValue( aParamName, *SIM_VALUE::Create( value.GetType(), aValue, aNotation ) );
  668. }
  669. bool SIM_MODEL::HasOverrides() const
  670. {
  671. for( const PARAM& param : m_params )
  672. {
  673. if( param.value->ToString() != "" )
  674. return true;
  675. }
  676. return false;
  677. }
  678. bool SIM_MODEL::HasNonInstanceOverrides() const
  679. {
  680. for( const PARAM& param : m_params )
  681. {
  682. if( !param.info.isInstanceParam && param.value->ToString() != "" )
  683. return true;
  684. }
  685. return false;
  686. }
  687. bool SIM_MODEL::HasSpiceNonInstanceOverrides() const
  688. {
  689. for( const PARAM& param : m_params )
  690. {
  691. if( !param.info.isSpiceInstanceParam && param.value->ToString() != "" )
  692. return true;
  693. }
  694. return false;
  695. }
  696. std::unique_ptr<SIM_MODEL> SIM_MODEL::Create( TYPE aType )
  697. {
  698. switch( aType )
  699. {
  700. case TYPE::R:
  701. case TYPE::C:
  702. case TYPE::L:
  703. return std::make_unique<SIM_MODEL_IDEAL>( aType );
  704. case TYPE::R_POT:
  705. return std::make_unique<SIM_MODEL_R_POT>();
  706. case TYPE::L_MUTUAL:
  707. return std::make_unique<SIM_MODEL_L_MUTUAL>();
  708. case TYPE::R_BEHAVIORAL:
  709. case TYPE::C_BEHAVIORAL:
  710. case TYPE::L_BEHAVIORAL:
  711. case TYPE::V_BEHAVIORAL:
  712. case TYPE::I_BEHAVIORAL:
  713. return std::make_unique<SIM_MODEL_BEHAVIORAL>( aType );
  714. case TYPE::TLINE_Z0:
  715. case TYPE::TLINE_RLGC:
  716. return std::make_unique<SIM_MODEL_TLINE>( aType );
  717. case TYPE::SW_V:
  718. case TYPE::SW_I:
  719. return std::make_unique<SIM_MODEL_SWITCH>( aType );
  720. case TYPE::V:
  721. case TYPE::I:
  722. case TYPE::V_SIN:
  723. case TYPE::I_SIN:
  724. case TYPE::V_PULSE:
  725. case TYPE::I_PULSE:
  726. case TYPE::V_EXP:
  727. case TYPE::I_EXP:
  728. /*case TYPE::V_SFAM:
  729. case TYPE::I_SFAM:
  730. case TYPE::V_SFFM:
  731. case TYPE::I_SFFM:*/
  732. case TYPE::V_PWL:
  733. case TYPE::I_PWL:
  734. case TYPE::V_WHITENOISE:
  735. case TYPE::I_WHITENOISE:
  736. case TYPE::V_PINKNOISE:
  737. case TYPE::I_PINKNOISE:
  738. case TYPE::V_BURSTNOISE:
  739. case TYPE::I_BURSTNOISE:
  740. case TYPE::V_RANDUNIFORM:
  741. case TYPE::I_RANDUNIFORM:
  742. case TYPE::V_RANDNORMAL:
  743. case TYPE::I_RANDNORMAL:
  744. case TYPE::V_RANDEXP:
  745. case TYPE::I_RANDEXP:
  746. //case TYPE::V_RANDPOISSON:
  747. //case TYPE::I_RANDPOISSON:
  748. return std::make_unique<SIM_MODEL_SOURCE>( aType );
  749. case TYPE::SUBCKT:
  750. return std::make_unique<SIM_MODEL_SUBCKT>();
  751. case TYPE::XSPICE:
  752. return std::make_unique<SIM_MODEL_XSPICE>( aType );
  753. case TYPE::KIBIS_DEVICE:
  754. case TYPE::KIBIS_DRIVER_DC:
  755. case TYPE::KIBIS_DRIVER_RECT:
  756. case TYPE::KIBIS_DRIVER_PRBS:
  757. return std::make_unique<SIM_MODEL_KIBIS>( aType );
  758. case TYPE::RAWSPICE:
  759. return std::make_unique<SIM_MODEL_RAW_SPICE>();
  760. default:
  761. return std::make_unique<SIM_MODEL_NGSPICE>( aType );
  762. }
  763. }
  764. SIM_MODEL::SIM_MODEL( TYPE aType ) :
  765. SIM_MODEL( aType, std::make_unique<SPICE_GENERATOR>( *this ),
  766. std::make_unique<SIM_SERDE>( *this ) )
  767. {
  768. }
  769. SIM_MODEL::SIM_MODEL( TYPE aType, std::unique_ptr<SPICE_GENERATOR> aSpiceGenerator ) :
  770. SIM_MODEL( aType, std::move( aSpiceGenerator ), std::make_unique<SIM_SERDE>( *this ) )
  771. {
  772. }
  773. SIM_MODEL::SIM_MODEL( TYPE aType, std::unique_ptr<SPICE_GENERATOR> aSpiceGenerator,
  774. std::unique_ptr<SIM_SERDE> aSerde ) :
  775. m_baseModel( nullptr ),
  776. m_serde( std::move( aSerde ) ),
  777. m_spiceGenerator( std::move( aSpiceGenerator ) ),
  778. m_type( aType ),
  779. m_isEnabled( true ),
  780. m_isStoredInValue( false )
  781. {
  782. }
  783. void SIM_MODEL::CreatePins( const std::vector<LIB_PIN*>& aSymbolPins )
  784. {
  785. // Default pin sequence: model pins are the same as symbol pins.
  786. // Excess model pins are set as Not Connected.
  787. // Note that intentionally nothing is added if `getPinNames()` returns an empty vector.
  788. // SIM_MODEL pins must be ordered by symbol pin numbers -- this is assumed by the code that
  789. // accesses them.
  790. std::vector<std::string> pinNames = getPinNames();
  791. for( unsigned modelPinIndex = 0; modelPinIndex < pinNames.size(); ++modelPinIndex )
  792. {
  793. if( modelPinIndex < aSymbolPins.size() )
  794. {
  795. AddPin( { pinNames.at( modelPinIndex ),
  796. aSymbolPins[ modelPinIndex ]->GetNumber().ToStdString() } );
  797. }
  798. else
  799. {
  800. AddPin( { pinNames.at( modelPinIndex ), "" } );
  801. }
  802. }
  803. }
  804. template <typename T>
  805. void SIM_MODEL::doReadDataFields( const std::vector<T>* aFields,
  806. const std::vector<LIB_PIN*>& aPins )
  807. {
  808. bool diffMode = GetFieldValue( aFields, SIM_LIBRARY_KIBIS::DIFF_FIELD ) == "1";
  809. SwitchSingleEndedDiff( diffMode );
  810. try
  811. {
  812. m_serde->ParseEnable( GetFieldValue( aFields, ENABLE_FIELD ) );
  813. CreatePins( aPins );
  814. m_serde->ParsePins( GetFieldValue( aFields, PINS_FIELD ) );
  815. std::string paramsField = GetFieldValue( aFields, PARAMS_FIELD );
  816. if( !m_serde->ParseParams( paramsField ) )
  817. m_serde->ParseValue( GetFieldValue( aFields, VALUE_FIELD ) );
  818. }
  819. catch( IO_ERROR& err )
  820. {
  821. DisplayErrorMessage( nullptr, err.What() );
  822. }
  823. }
  824. template <typename T>
  825. void SIM_MODEL::doWriteFields( std::vector<T>& aFields ) const
  826. {
  827. SetFieldValue( aFields, DEVICE_TYPE_FIELD, m_serde->GenerateDevice() );
  828. SetFieldValue( aFields, TYPE_FIELD, m_serde->GenerateType() );
  829. SetFieldValue( aFields, ENABLE_FIELD, m_serde->GenerateEnable() );
  830. SetFieldValue( aFields, PINS_FIELD, m_serde->GeneratePins() );
  831. SetFieldValue( aFields, PARAMS_FIELD, m_serde->GenerateParams() );
  832. if( IsStoredInValue() )
  833. SetFieldValue( aFields, VALUE_FIELD, m_serde->GenerateValue() );
  834. }
  835. bool SIM_MODEL::requiresSpiceModelLine() const
  836. {
  837. for( const PARAM& param : GetParams() )
  838. {
  839. if( !param.info.isSpiceInstanceParam )
  840. return true;
  841. }
  842. return false;
  843. }
  844. template <class T_symbol, class T_field>
  845. bool SIM_MODEL::InferSimModel( T_symbol& aSymbol, std::vector<T_field>* aFields, bool aResolve,
  846. SIM_VALUE_GRAMMAR::NOTATION aNotation, wxString* aDeviceType,
  847. wxString* aModelType, wxString* aModelParams, wxString* aPinMap )
  848. {
  849. auto convertNotation =
  850. [&]( const wxString& units ) -> wxString
  851. {
  852. if( aNotation == SIM_VALUE_GRAMMAR::NOTATION::SPICE )
  853. {
  854. if( units == wxT( "M" ) )
  855. return wxT( "Meg" );
  856. }
  857. else if( aNotation == SIM_VALUE_GRAMMAR::NOTATION::SI )
  858. {
  859. if( units == wxT( "Meg" ) || units == wxT( "MEG" ) )
  860. return wxT( "M" );
  861. }
  862. return units;
  863. };
  864. wxString prefix = aSymbol.GetPrefix();
  865. wxString value = GetFieldValue( aFields, VALUE_FIELD, aResolve );
  866. std::vector<LIB_PIN*> pins = aSymbol.GetAllLibPins();
  867. *aDeviceType = GetFieldValue( aFields, DEVICE_TYPE_FIELD, aResolve );
  868. *aModelType = GetFieldValue( aFields, TYPE_FIELD, aResolve );
  869. *aModelParams = GetFieldValue( aFields, PARAMS_FIELD, aResolve );
  870. *aPinMap = GetFieldValue( aFields, PINS_FIELD, aResolve );
  871. if( pins.size() != 2 )
  872. return false;
  873. if( ( ( *aDeviceType == "R" || *aDeviceType == "L" || *aDeviceType == "C" )
  874. && aModelType->IsEmpty() )
  875. ||
  876. ( aDeviceType->IsEmpty()
  877. && aModelType->IsEmpty()
  878. && !value.IsEmpty()
  879. && ( prefix.StartsWith( "R" ) || prefix.StartsWith( "L" ) || prefix.StartsWith( "C" ) ) ) )
  880. {
  881. if( aDeviceType->IsEmpty() )
  882. *aDeviceType = prefix.Left( 1 );
  883. if( aModelParams->IsEmpty() )
  884. {
  885. wxRegEx idealVal( wxT( "^"
  886. "([0-9\\,\\. ]+)"
  887. "([fFpPnNuUmMkKgGtTμµ𝛍𝜇𝝁 ]|M(e|E)(g|G))?"
  888. "([fFhHΩΩ𝛀𝛺𝝮rR]|ohm)?"
  889. "([-1-9 ]*)"
  890. "([fFhHΩΩ𝛀𝛺𝝮rR]|ohm)?"
  891. "$" ) );
  892. if( idealVal.Matches( value ) ) // Ideal
  893. {
  894. wxString valueMantissa( idealVal.GetMatch( value, 1 ) );
  895. wxString valueExponent( idealVal.GetMatch( value, 2 ) );
  896. wxString valueFraction( idealVal.GetMatch( value, 6 ) );
  897. // Remove any thousands separators
  898. valueMantissa.Replace( wxT( "," ), wxEmptyString );
  899. if( valueMantissa.Contains( wxT( "." ) ) || valueFraction.IsEmpty() )
  900. {
  901. aModelParams->Printf( wxT( "%s=\"%s%s\"" ),
  902. prefix.Left(1).Lower(),
  903. valueMantissa,
  904. convertNotation( valueExponent ) );
  905. }
  906. else
  907. {
  908. aModelParams->Printf( wxT( "%s=\"%s.%s%s\"" ),
  909. prefix.Left(1).Lower(),
  910. valueMantissa,
  911. valueFraction,
  912. convertNotation( valueExponent ) );
  913. }
  914. }
  915. else // Behavioral
  916. {
  917. *aModelType = wxT( "=" );
  918. aModelParams->Printf( wxT( "%s=\"%s\"" ), prefix.Left(1).Lower(), value );
  919. }
  920. }
  921. if( aPinMap->IsEmpty() )
  922. aPinMap->Printf( wxT( "%s=+ %s=-" ), pins[0]->GetNumber(), pins[1]->GetNumber() );
  923. return true;
  924. }
  925. if( ( ( *aDeviceType == wxT( "V" ) || *aDeviceType == wxT( "I" ) )
  926. && aModelType->IsEmpty() )
  927. ||
  928. ( aDeviceType->IsEmpty()
  929. && aModelType->IsEmpty()
  930. && !value.IsEmpty()
  931. && ( prefix.StartsWith( "V" ) || prefix.StartsWith( "I" ) ) ) )
  932. {
  933. if( aDeviceType->IsEmpty() )
  934. *aDeviceType = prefix.Left( 1 );
  935. if( aModelType->IsEmpty() )
  936. *aModelType = wxT( "DC" );
  937. if( aModelParams->IsEmpty() && !value.IsEmpty() )
  938. {
  939. if( value.StartsWith( wxT( "DC " ) ) )
  940. value = value.Right( value.Length() - 3 );
  941. wxRegEx sourceVal( wxT( "^"
  942. "([0-9\\. ]+)"
  943. "([fFpPnNuUmMkKgGtTμµ𝛍𝜇𝝁 ]|M(e|E)(g|G))?"
  944. "([vVaA])?"
  945. "([-1-9 ]*)"
  946. "([vVaA])?"
  947. "$" ) );
  948. if( sourceVal.Matches( value ) )
  949. {
  950. wxString valueMantissa( sourceVal.GetMatch( value, 1 ) );
  951. wxString valueExponent( sourceVal.GetMatch( value, 2 ) );
  952. wxString valueFraction( sourceVal.GetMatch( value, 6 ) );
  953. // Remove any thousands separators
  954. valueMantissa.Replace( wxT( "," ), wxEmptyString );
  955. if( valueMantissa.Contains( wxT( "." ) ) || valueFraction.IsEmpty() )
  956. {
  957. aModelParams->Printf( wxT( "dc=\"%s%s\"" ),
  958. valueMantissa,
  959. convertNotation( valueExponent ) );
  960. }
  961. else
  962. {
  963. aModelParams->Printf( wxT( "dc=\"%s.%s%s\"" ),
  964. valueMantissa,
  965. valueFraction,
  966. convertNotation( valueExponent ) );
  967. }
  968. }
  969. else
  970. {
  971. aModelParams->Printf( wxT( "dc=\"%s\"" ), value );
  972. }
  973. }
  974. if( aPinMap->IsEmpty() )
  975. aPinMap->Printf( wxT( "%s=+ %s=-" ), pins[0]->GetNumber(), pins[1]->GetNumber() );
  976. return true;
  977. }
  978. return false;
  979. }
  980. template bool SIM_MODEL::InferSimModel<SCH_SYMBOL, SCH_FIELD>( SCH_SYMBOL& aSymbol,
  981. std::vector<SCH_FIELD>* aFields,
  982. bool aResolve,
  983. SIM_VALUE_GRAMMAR::NOTATION aNotation,
  984. wxString* aDeviceType,
  985. wxString* aModelType,
  986. wxString* aModelParams,
  987. wxString* aPinMap );
  988. template bool SIM_MODEL::InferSimModel<LIB_SYMBOL, LIB_FIELD>( LIB_SYMBOL& aSymbol,
  989. std::vector<LIB_FIELD>* aFields,
  990. bool aResolve,
  991. SIM_VALUE_GRAMMAR::NOTATION aNotation,
  992. wxString* aDeviceType,
  993. wxString* aModelType,
  994. wxString* aModelParams,
  995. wxString* aPinMap );
  996. template <typename T_symbol, typename T_field>
  997. void SIM_MODEL::MigrateSimModel( T_symbol& aSymbol, const PROJECT* aProject )
  998. {
  999. if( aSymbol.FindField( SIM_MODEL::DEVICE_TYPE_FIELD )
  1000. || aSymbol.FindField( SIM_MODEL::TYPE_FIELD )
  1001. || aSymbol.FindField( SIM_MODEL::PINS_FIELD )
  1002. || aSymbol.FindField( SIM_MODEL::PARAMS_FIELD ) )
  1003. {
  1004. // Has a V7 model field -- skip.
  1005. return;
  1006. }
  1007. auto getSIValue =
  1008. []( T_field* aField )
  1009. {
  1010. if( !aField ) // no, not really, but it keeps Coverity happy
  1011. return wxString( wxEmptyString );
  1012. wxRegEx regex( wxT( "([^a-z])(M)(e|E)(g|G)($|[^a-z])" ) );
  1013. wxString value = aField->GetText();
  1014. // Keep prefix, M, and suffix, but drop e|E and g|G
  1015. regex.ReplaceAll( &value, wxT( "\\1\\2\\5" ) );
  1016. return value;
  1017. };
  1018. auto generateDefaultPinMapFromSymbol =
  1019. []( const std::vector<LIB_PIN*>& sourcePins )
  1020. {
  1021. wxString pinMap;
  1022. // If we're creating the pinMap from the symbol it means we don't know what the
  1023. // SIM_MODEL's pin names are, so just use indexes.
  1024. for( unsigned ii = 0; ii < sourcePins.size(); ++ii )
  1025. {
  1026. if( ii > 0 )
  1027. pinMap.Append( wxS( " " ) );
  1028. pinMap.Append( wxString::Format( wxT( "%s=%u" ),
  1029. sourcePins[ii]->GetNumber(),
  1030. ii + 1 ) );
  1031. }
  1032. return pinMap;
  1033. };
  1034. wxString prefix = aSymbol.GetPrefix();
  1035. T_field* valueField = aSymbol.FindField( wxT( "Value" ) );
  1036. std::vector<LIB_PIN*> sourcePins = aSymbol.GetAllLibPins();
  1037. std::sort( sourcePins.begin(), sourcePins.end(),
  1038. []( const LIB_PIN* lhs, const LIB_PIN* rhs )
  1039. {
  1040. return StrNumCmp( lhs->GetNumber(), rhs->GetNumber(), true ) < 0;
  1041. } );
  1042. wxString spiceDeviceType;
  1043. wxString spiceModel;
  1044. wxString spiceType;
  1045. wxString spiceLib;
  1046. wxString pinMap;
  1047. wxString spiceParams;
  1048. bool modelFromValueField = false;
  1049. if( aSymbol.FindField( wxT( "Spice_Primitive" ) )
  1050. || aSymbol.FindField( wxT( "Spice_Node_Sequence" ) )
  1051. || aSymbol.FindField( wxT( "Spice_Model" ) )
  1052. || aSymbol.FindField( wxT( "Spice_Netlist_Enabled" ) )
  1053. || aSymbol.FindField( wxT( "Spice_Lib_File" ) ) )
  1054. {
  1055. if( T_field* primitiveField = aSymbol.FindField( wxT( "Spice_Primitive" ) ) )
  1056. {
  1057. spiceDeviceType = primitiveField->GetText();
  1058. aSymbol.RemoveField( primitiveField );
  1059. }
  1060. if( T_field* nodeSequenceField = aSymbol.FindField( wxT( "Spice_Node_Sequence" ) ) )
  1061. {
  1062. const wxString delimiters( "{:,; }" );
  1063. const wxString& nodeSequence = nodeSequenceField->GetText();
  1064. if( nodeSequence != "" )
  1065. {
  1066. wxStringTokenizer tkz( nodeSequence, delimiters );
  1067. for( long modelPinNumber = 1; tkz.HasMoreTokens(); ++modelPinNumber )
  1068. {
  1069. long symbolPinNumber = 1;
  1070. tkz.GetNextToken().ToLong( &symbolPinNumber );
  1071. if( modelPinNumber != 1 )
  1072. pinMap.Append( " " );
  1073. pinMap.Append( wxString::Format( "%ld=%ld", symbolPinNumber, modelPinNumber ) );
  1074. }
  1075. }
  1076. aSymbol.RemoveField( nodeSequenceField );
  1077. }
  1078. if( T_field* modelField = aSymbol.FindField( wxT( "Spice_Model" ) ) )
  1079. {
  1080. spiceModel = getSIValue( modelField );
  1081. aSymbol.RemoveField( modelField );
  1082. }
  1083. else
  1084. {
  1085. spiceModel = getSIValue( valueField );
  1086. modelFromValueField = true;
  1087. }
  1088. if( T_field* netlistEnabledField = aSymbol.FindField( wxT( "Spice_Netlist_Enabled" ) ) )
  1089. {
  1090. wxString netlistEnabled = netlistEnabledField->GetText().Lower();
  1091. if( netlistEnabled.StartsWith( wxT( "0" ) )
  1092. || netlistEnabled.StartsWith( wxT( "n" ) )
  1093. || netlistEnabled.StartsWith( wxT( "f" ) ) )
  1094. {
  1095. netlistEnabledField->SetName( SIM_MODEL::ENABLE_FIELD );
  1096. netlistEnabledField->SetText( wxT( "0" ) );
  1097. }
  1098. else
  1099. {
  1100. aSymbol.RemoveField( netlistEnabledField );
  1101. }
  1102. }
  1103. if( T_field* libFileField = aSymbol.FindField( wxT( "Spice_Lib_File" ) ) )
  1104. {
  1105. spiceLib = libFileField->GetText();
  1106. aSymbol.RemoveField( libFileField );
  1107. }
  1108. }
  1109. else
  1110. {
  1111. // Auto convert some legacy fields used in the middle of 7.0 development...
  1112. if( T_field* legacyType = aSymbol.FindField( wxT( "Sim_Type" ) ) )
  1113. {
  1114. legacyType->SetName( SIM_MODEL::TYPE_FIELD );
  1115. }
  1116. if( T_field* legacyDevice = aSymbol.FindField( wxT( "Sim_Device" ) ) )
  1117. {
  1118. legacyDevice->SetName( SIM_MODEL::DEVICE_TYPE_FIELD );
  1119. }
  1120. if( T_field* legacyPins = aSymbol.FindField( wxT( "Sim_Pins" ) ) )
  1121. {
  1122. bool isPassive = prefix.StartsWith( wxT( "R" ) )
  1123. || prefix.StartsWith( wxT( "L" ) )
  1124. || prefix.StartsWith( wxT( "C" ) );
  1125. // Migrate pins from array of indexes to name-value-pairs
  1126. wxArrayString pinIndexes;
  1127. wxStringSplit( legacyPins->GetText(), pinIndexes, ' ' );
  1128. if( isPassive && pinIndexes.size() == 2 && sourcePins.size() == 2 )
  1129. {
  1130. if( pinIndexes[0] == wxT( "2" ) )
  1131. {
  1132. pinMap.Printf( wxT( "%s=- %s=+" ),
  1133. sourcePins[0]->GetNumber(),
  1134. sourcePins[1]->GetNumber() );
  1135. }
  1136. else
  1137. {
  1138. pinMap.Printf( wxT( "%s=+ %s=-" ),
  1139. sourcePins[0]->GetNumber(),
  1140. sourcePins[1]->GetNumber() );
  1141. }
  1142. }
  1143. else
  1144. {
  1145. for( unsigned ii = 0; ii < pinIndexes.size(); ++ii )
  1146. {
  1147. if( ii > 0 )
  1148. pinMap.Append( wxS( " " ) );
  1149. pinMap.Append( wxString::Format( wxT( "%s=%s" ),
  1150. sourcePins[ii]->GetNumber(),
  1151. pinIndexes[ ii ] ) );
  1152. }
  1153. }
  1154. legacyPins->SetName( SIM_MODEL::PINS_FIELD );
  1155. legacyPins->SetText( pinMap );
  1156. }
  1157. if( T_field* legacyParams = aSymbol.FindField( wxT( "Sim_Params" ) ) )
  1158. {
  1159. legacyParams->SetName( SIM_MODEL::PARAMS_FIELD );
  1160. }
  1161. return;
  1162. }
  1163. spiceDeviceType = spiceDeviceType.Trim( true ).Trim( false );
  1164. spiceModel = spiceModel.Trim( true ).Trim( false );
  1165. spiceType = spiceType.Trim( true ).Trim( false );
  1166. bool libraryModel = false;
  1167. bool inferredModel = false;
  1168. bool internalModel = false;
  1169. if( !spiceLib.IsEmpty() )
  1170. {
  1171. SIM_LIB_MGR libMgr( aProject );
  1172. try
  1173. {
  1174. std::vector<T_field> emptyFields;
  1175. SIM_LIBRARY::MODEL model = libMgr.CreateModel( spiceLib, spiceModel.ToStdString(),
  1176. emptyFields, sourcePins );
  1177. spiceParams = wxString( model.model.GetBaseModel()->Serde().GenerateParams() );
  1178. libraryModel = true;
  1179. if( pinMap.IsEmpty() )
  1180. {
  1181. // Try to generate a default pin map from the SIM_MODEL's pins; if that fails,
  1182. // generate one from the symbol's pins
  1183. model.model.SIM_MODEL::CreatePins( sourcePins );
  1184. pinMap = wxString( model.model.Serde().GeneratePins() );
  1185. if( pinMap.IsEmpty() )
  1186. pinMap = generateDefaultPinMapFromSymbol( sourcePins );
  1187. }
  1188. }
  1189. catch( ... )
  1190. {
  1191. // Fall back to raw spice model
  1192. }
  1193. }
  1194. else if( ( spiceDeviceType == "R" || spiceDeviceType == "L" || spiceDeviceType == "C" )
  1195. && prefix.StartsWith( spiceDeviceType )
  1196. && modelFromValueField )
  1197. {
  1198. inferredModel = true;
  1199. }
  1200. else
  1201. {
  1202. // See if we have a SPICE model such as "sin(0 1 60)" or "sin 0 1 60" that can be handled
  1203. // by a built-in SIM_MODEL.
  1204. wxStringTokenizer tokenizer( spiceModel, wxT( "() " ), wxTOKEN_STRTOK );
  1205. if( tokenizer.HasMoreTokens() )
  1206. {
  1207. spiceType = tokenizer.GetNextToken();
  1208. spiceType.MakeUpper();
  1209. for( SIM_MODEL::TYPE type : SIM_MODEL::TYPE_ITERATOR() )
  1210. {
  1211. if( spiceDeviceType == SIM_MODEL::SpiceInfo( type ).itemType
  1212. && spiceType == SIM_MODEL::SpiceInfo( type ).inlineTypeString )
  1213. {
  1214. try
  1215. {
  1216. std::unique_ptr<SIM_MODEL> model = SIM_MODEL::Create( type );
  1217. if( spiceType == wxT( "DC" ) && tokenizer.CountTokens() == 1 )
  1218. {
  1219. valueField->SetText( tokenizer.GetNextToken() );
  1220. modelFromValueField = false;
  1221. }
  1222. else
  1223. {
  1224. for( int ii = 0; tokenizer.HasMoreTokens(); ++ii )
  1225. {
  1226. model->SetParamValue( ii, tokenizer.GetNextToken().ToStdString(),
  1227. SIM_VALUE_GRAMMAR::NOTATION::SPICE );
  1228. }
  1229. spiceParams = wxString( model->Serde().GenerateParams() );
  1230. }
  1231. internalModel = true;
  1232. if( pinMap.IsEmpty() )
  1233. {
  1234. // Generate a default pin map from the SIM_MODEL's pins
  1235. model->CreatePins( sourcePins );
  1236. pinMap = wxString( model->Serde().GeneratePins() );
  1237. }
  1238. }
  1239. catch( ... )
  1240. {
  1241. // Fall back to raw spice model
  1242. }
  1243. break;
  1244. }
  1245. }
  1246. }
  1247. }
  1248. if( libraryModel )
  1249. {
  1250. T_field libraryField( &aSymbol, -1, SIM_MODEL::LIBRARY_FIELD );
  1251. libraryField.SetText( spiceLib );
  1252. aSymbol.AddField( libraryField );
  1253. T_field nameField( &aSymbol, -1, SIM_MODEL::NAME_FIELD );
  1254. nameField.SetText( spiceModel );
  1255. aSymbol.AddField( nameField );
  1256. T_field paramsField( &aSymbol, -1, SIM_MODEL::PARAMS_FIELD );
  1257. paramsField.SetText( spiceParams );
  1258. aSymbol.AddField( paramsField );
  1259. if( modelFromValueField )
  1260. valueField->SetText( wxT( "${SIM.NAME}" ) );
  1261. }
  1262. else if( inferredModel )
  1263. {
  1264. // DeviceType is left in the reference designator and Model is left in the value field,
  1265. // so there's nothing to do here....
  1266. }
  1267. else if( internalModel )
  1268. {
  1269. T_field deviceTypeField( &aSymbol, -1, SIM_MODEL::DEVICE_TYPE_FIELD );
  1270. deviceTypeField.SetText( spiceDeviceType );
  1271. aSymbol.AddField( deviceTypeField );
  1272. T_field typeField( &aSymbol, -1, SIM_MODEL::TYPE_FIELD );
  1273. typeField.SetText( spiceType );
  1274. aSymbol.AddField( typeField );
  1275. T_field paramsField( &aSymbol, -1, SIM_MODEL::PARAMS_FIELD );
  1276. paramsField.SetText( spiceParams );
  1277. aSymbol.AddField( paramsField );
  1278. if( modelFromValueField )
  1279. valueField->SetText( wxT( "${SIM.PARAMS}" ) );
  1280. }
  1281. else // Insert a raw spice model as a substitute.
  1282. {
  1283. if( spiceDeviceType.IsEmpty() && spiceLib.IsEmpty() )
  1284. {
  1285. spiceParams = spiceModel;
  1286. }
  1287. else
  1288. {
  1289. spiceParams.Printf( wxT( "type=\"%s\" model=\"%s\" lib=\"%s\"" ),
  1290. spiceDeviceType, spiceModel, spiceLib );
  1291. }
  1292. T_field deviceTypeField( &aSymbol, -1, SIM_MODEL::DEVICE_TYPE_FIELD );
  1293. deviceTypeField.SetText( SIM_MODEL::DeviceInfo( SIM_MODEL::DEVICE_T::SPICE ).fieldValue );
  1294. aSymbol.AddField( deviceTypeField );
  1295. T_field paramsField( &aSymbol, -1, SIM_MODEL::PARAMS_FIELD );
  1296. paramsField.SetText( spiceParams );
  1297. aSymbol.AddField( paramsField );
  1298. if( modelFromValueField )
  1299. {
  1300. // Get the current Value field, after previous changes.
  1301. valueField = aSymbol.FindField( wxT( "Value" ) );
  1302. if( valueField )
  1303. valueField->SetText( wxT( "${SIM.PARAMS}" ) );
  1304. }
  1305. // We know nothing about the SPICE model here, so we've got no choice but to generate
  1306. // the default pin map from the symbol's pins.
  1307. if( pinMap.IsEmpty() )
  1308. pinMap = generateDefaultPinMapFromSymbol( sourcePins );
  1309. }
  1310. if( !pinMap.IsEmpty() )
  1311. {
  1312. T_field pinsField( &aSymbol, -1, SIM_MODEL::PINS_FIELD );
  1313. pinsField.SetText( pinMap );
  1314. aSymbol.AddField( pinsField );
  1315. }
  1316. }
  1317. template void SIM_MODEL::MigrateSimModel<SCH_SYMBOL, SCH_FIELD>( SCH_SYMBOL& aSymbol,
  1318. const PROJECT* aProject );
  1319. template void SIM_MODEL::MigrateSimModel<LIB_SYMBOL, LIB_FIELD>( LIB_SYMBOL& aSymbol,
  1320. const PROJECT* aProject );