KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_library_spice.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers, see AUTHORS.TXT for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
21#include <eeschema_test_utils.h>
24
25#include <boost/algorithm/string/case_conv.hpp>
26#include <fmt/core.h>
27#include <locale_io.h>
28
29#include <atomic>
30#include <cstdlib>
31#include <map>
32#include <string>
33#include <thread>
34
35
37{
38public:
39 std::string GetLibraryPath( const std::string& aBaseName )
40 {
41 wxFileName fn( KI_TEST::GetEeschemaTestDataDir() );
42 fn.AppendDir( "spice_netlists" );
43 fn.AppendDir( "libraries" );
44 fn.SetName( aBaseName );
45 fn.SetExt( "lib.spice" );
46
47 return std::string( fn.GetFullPath().ToUTF8() );
48 }
49
50 void LoadLibrary( const std::string& aBaseName )
51 {
52 NULL_REPORTER devnull;
53 std::string path = GetLibraryPath( aBaseName );
54
55 m_library = std::make_unique<SIM_LIBRARY_SPICE>( true );
56 m_library->ReadFile( path, devnull );
57 }
58
59 void CompareToUsualDiodeModel( const SIM_MODEL& aModel, const std::string& aModelName, int aModelIndex )
60 {
61 BOOST_CHECK( aModel.GetType() == SIM_MODEL::TYPE::D );
62 BOOST_CHECK_EQUAL( aModelName,
63 fmt::format( "{}{}_Usual",
64 boost::to_upper_copy( aModel.GetSpiceInfo().modelType ),
65 aModelIndex ) );
66 BOOST_CHECK_EQUAL( aModel.FindParam( "bv" )->value, "1.1u" );
67 BOOST_CHECK_EQUAL( aModel.FindParam( "cjo" )->value, "2.2m" );
68 BOOST_CHECK_EQUAL( aModel.FindParam( "ibv" )->value, "3.3" );
69 BOOST_CHECK_EQUAL( aModel.FindParam( "is" )->value, "4.4k" );
70 BOOST_CHECK_EQUAL( aModel.FindParam( "m_" )->value, "5.5M" );
71 BOOST_CHECK_EQUAL( aModel.FindParam( "n" )->value, "6.6G" );
72 }
73
74 void CompareToEmptyModel( const SIM_MODEL& aModel, const std::string& aModelName, int aModelIndex )
75 {
76 BOOST_TEST_CONTEXT( "Model index: " << aModelIndex )
77 {
78 BOOST_CHECK_EQUAL( aModelName,
79 fmt::format( "{}{}_Empty",
80 boost::to_upper_copy( aModel.GetSpiceInfo().modelType ),
81 aModelIndex ) );
82
83 for( unsigned i = 0; i < aModel.GetParamCount(); ++i )
84 {
85 BOOST_TEST_CONTEXT( "Param name: " << aModel.GetParam( i ).info.name )
86 {
87 BOOST_CHECK_EQUAL( aModel.GetParamOverride( i ).value, "" );
88 }
89 }
90 }
91 }
92
93 void TestTransistor( const SIM_MODEL& aModel, const std::string& aModelName, int aModelIndex,
94 SIM_MODEL::TYPE aType, const std::vector<std::string>& aParamNames )
95 {
96 BOOST_TEST_CONTEXT( "Model index: " << aModelIndex
97 << ", Model name: " << aModelName
98 << ", Model device type: " << aModel.GetDeviceInfo().fieldValue
99 << ", Model type: " << aModel.GetTypeInfo().fieldValue )
100 {
101 if( aModel.GetType() != aType )
102 {
103 aModelIndex++;
104 }
105
106 BOOST_CHECK( aModel.GetType() == aType );
107
108 std::string modelType = aModel.GetSpiceInfo().modelType;
109 std::string fieldValue = aModel.GetTypeInfo().fieldValue;
110
111 // Special case for VDMOS because Ngspice parses it differently.
112 if( modelType == "VDMOS NCHAN" )
113 {
114 modelType = "NMOS";
115 fieldValue = "VD"; // Not "VDMOS" because Ngspice gives an error if this string is
116 // used in a model name (this is a bug in Ngspice, FIXME).
117 }
118
119 if( modelType == "VDMOS PCHAN" )
120 {
121 modelType = "PMOS";
122 fieldValue = "VD";
123 }
124
125 BOOST_CHECK_EQUAL( aModelName, fmt::format( "_{}_{}_{}",
126 aModelIndex,
127 modelType,
128 fieldValue ) );
129
130 for( int i = 0; i < aParamNames.size(); ++i )
131 {
132 std::string paramName = aParamNames.at( i );
133 const SIM_MODEL::PARAM* param = aModel.FindParam( paramName );
134
135 BOOST_TEST_CONTEXT( "Param name: " << paramName )
136 {
137 if( i % 10 == 0 )
138 {
139 BOOST_CHECK( param->value == "0M" || param->value == "0" );
140 }
141 else if( param->info.type == SIM_VALUE::TYPE_INT )
142 {
143 BOOST_CHECK_EQUAL( param->value, fmt::format( "{:d}", i % 10 ) );
144 }
145 else if( param->info.category == SIM_MODEL::PARAM::CATEGORY::FLAGS )
146 {
147 BOOST_CHECK_EQUAL( param->value, "" );
148 }
149 else
150 {
151 BOOST_CHECK_EQUAL( param->value, fmt::format( "{}000.0{}M", i % 10, i % 10 ) );
152 }
153 }
154 }
155 }
156 }
157
158 std::unique_ptr<SIM_LIBRARY_SPICE> m_library;
159};
160
161
162BOOST_FIXTURE_TEST_SUITE( SimLibrarySpice, TEST_SIM_LIBRARY_SPICE_FIXTURE )
163
164
166{
167 LOCALE_IO toggle;
168
169 LoadLibrary( "subckts" );
170
171 const std::vector<SIM_LIBRARY::MODEL> models = m_library->GetModels();
172
173 BOOST_CHECK_EQUAL( models.size(), 7 );
174
175 for( int i = 0; i < models.size(); ++i )
176 {
177 const auto& [modelName, model] = models.at( i );
178
179 BOOST_TEST_CONTEXT( "SUBCKT index: " << i )
180
181 switch( i )
182 {
183 case 0:
184 BOOST_CHECK( model.GetType() == SIM_MODEL::TYPE::SUBCKT );
185 BOOST_CHECK_EQUAL( modelName, "NO_PARAMS_0" );
186 break;
187
188 case 1:
189 BOOST_CHECK( model.GetType() == SIM_MODEL::TYPE::SUBCKT );
190 BOOST_CHECK_EQUAL( modelName, "ONE_PARAM_1" );
191 BOOST_REQUIRE_EQUAL( model.GetParamCount(), 1 );
192 BOOST_CHECK_EQUAL( model.GetParam( 0 ).info.name, "PARAM1" );
193 BOOST_CHECK_EQUAL( model.GetParam( 0 ).info.defaultValue, "1" );
194 BOOST_REQUIRE_EQUAL( model.GetPinCount(), 2 );
195 BOOST_CHECK_EQUAL( model.GetPin( 0 ).modelPinName, "1" );
196 BOOST_CHECK_EQUAL( model.GetPin( 1 ).modelPinName, "2" );
197 break;
198
199 case 2:
200 BOOST_CHECK( model.GetType() == SIM_MODEL::TYPE::SUBCKT );
201 BOOST_CHECK_EQUAL( modelName, "ONE_PARAM_SHORT_FORM_2" );
202 BOOST_REQUIRE_EQUAL( model.GetParamCount(), 1 );
203 BOOST_CHECK_EQUAL( model.GetParam( 0 ).info.name, "PARAM1" );
204 BOOST_CHECK_EQUAL( model.GetParam( 0 ).info.defaultValue, "1.0" );
205 BOOST_CHECK_EQUAL( model.GetPin( 0 ).modelPinName, "1" );
206 BOOST_CHECK_EQUAL( model.GetPin( 1 ).modelPinName, "2" );
207 break;
208
209 case 3:
210 BOOST_CHECK( model.GetType() == SIM_MODEL::TYPE::SUBCKT );
211 BOOST_CHECK_EQUAL( modelName, "two_params_3" );
212 BOOST_REQUIRE_EQUAL( model.GetParamCount(), 2 );
213 BOOST_CHECK_EQUAL( model.GetParam( 0 ).info.name, "param1" );
214 BOOST_CHECK_EQUAL( model.GetParam( 0 ).info.defaultValue, "1.1e+1" );
215 BOOST_CHECK_EQUAL( model.GetParam( 1 ).info.name, "param2" );
216 BOOST_CHECK_EQUAL( model.GetParam( 1 ).info.defaultValue, "2.2e+2" );
217 BOOST_REQUIRE_EQUAL( model.GetPinCount(), 2 );
218 BOOST_CHECK_EQUAL( model.GetPin( 0 ).modelPinName, "1" );
219 BOOST_CHECK_EQUAL( model.GetPin( 1 ).modelPinName, "2" );
220 break;
221
222 case 4:
223 BOOST_CHECK( model.GetType() == SIM_MODEL::TYPE::SUBCKT );
224 BOOST_CHECK_EQUAL( modelName, "two_params_short_form_4" );
225 BOOST_REQUIRE_EQUAL( model.GetParamCount(), 2 );
226 BOOST_CHECK_EQUAL( model.GetParam( 0 ).info.name, "param1" );
227 BOOST_CHECK_EQUAL( model.GetParam( 0 ).info.defaultValue, "1.1E+1" );
228 BOOST_CHECK_EQUAL( model.GetParam( 1 ).info.name, "param2" );
229 BOOST_CHECK_EQUAL( model.GetParam( 1 ).info.defaultValue, "2.2E+2" );
230 BOOST_REQUIRE_EQUAL( model.GetPinCount(), 2 );
231 BOOST_CHECK_EQUAL( model.GetPin( 0 ).modelPinName, "1" );
232 BOOST_CHECK_EQUAL( model.GetPin( 1 ).modelPinName, "2" );
233 break;
234
235 case 5:
236 BOOST_CHECK( model.GetType() == SIM_MODEL::TYPE::SUBCKT );
237 BOOST_CHECK_EQUAL( modelName, "NOTHING_5" );
238 BOOST_CHECK_EQUAL( model.GetParamCount(), 0 );
239 BOOST_CHECK_EQUAL( model.GetPinCount(), 0 );
240 break;
241
242 case 6:
243 BOOST_CHECK( model.GetType() == SIM_MODEL::TYPE::SUBCKT );
244 BOOST_CHECK_EQUAL( modelName, "Numparam_inside_6" );
245 BOOST_CHECK_EQUAL( model.GetParamCount(), 0 );
246 BOOST_CHECK_EQUAL( model.GetPinCount(), 2 );
247 break;
248 }
249 }
250}
251
252
254{
255 LOCALE_IO toggle;
256
257 LoadLibrary( "diodes" );
258
259 const std::vector<SIM_LIBRARY::MODEL> models = m_library->GetModels();
260
261 BOOST_CHECK_EQUAL( models.size(), 26 );
262
263 for( int i = 0; i < models.size(); ++i )
264 {
265 const auto& [modelName, model] = models.at( i );
266
267 BOOST_TEST_CONTEXT( "Diode index: " << i )
268
269 switch( i )
270 {
271 case 0:
272 BOOST_CHECK( model.GetType() == SIM_MODEL::TYPE::D );
273 BOOST_CHECK_EQUAL( modelName, "1N4148" );
274 BOOST_CHECK_EQUAL( model.FindParam( "bv" )->value, "100" );
275 BOOST_CHECK_EQUAL( model.FindParam( "cjo" )->value, "4p" );
276 BOOST_CHECK_EQUAL( model.FindParam( "ibv" )->value, "100u" );
277 BOOST_CHECK_EQUAL( model.FindParam( "is" )->value, "4n" );
278 BOOST_CHECK_EQUAL( model.FindParam( "m_" )->value, "0.33" );
279 BOOST_CHECK_EQUAL( model.FindParam( "n" )->value, "2" );
280 BOOST_CHECK_EQUAL( model.FindParam( "rs" )->value, "0.5" );
281 BOOST_CHECK_EQUAL( model.FindParam( "tt" )->value, "10n" );
282 BOOST_CHECK_EQUAL( model.FindParam( "vj" )->value, "0.8" );
283 break;
284
285 case 1:
286 BOOST_CHECK( model.GetType() == SIM_MODEL::TYPE::D );
287 BOOST_CHECK_EQUAL( modelName, "D1" );
288 BOOST_CHECK_EQUAL( model.FindParam( "is" )->value, "1.23n" );
289 BOOST_CHECK_EQUAL( model.FindParam( "n" )->value, "1.23" );
290 BOOST_CHECK_EQUAL( model.FindParam( "rs" )->value, ".7890" );
291 BOOST_CHECK_EQUAL( model.FindParam( "ikf" )->value, "12.34m" );
292 BOOST_CHECK_EQUAL( model.FindParam( "xti" )->value, "3" );
293 BOOST_CHECK_EQUAL( model.FindParam( "eg" )->value, "1.23" );
294 BOOST_CHECK_EQUAL( model.FindParam( "cjo" )->value, "0.9p" );
295 BOOST_CHECK_EQUAL( model.FindParam( "m_" )->value, ".56" );
296 BOOST_CHECK_EQUAL( model.FindParam( "vj" )->value, ".78" );
297 BOOST_CHECK_EQUAL( model.FindParam( "fc" )->value, ".9" );
298 BOOST_CHECK_EQUAL( model.FindParam( "isr" )->value, "12.34n" );
299 BOOST_CHECK_EQUAL( model.FindParam( "nr" )->value, "2.345" );
300 BOOST_CHECK_EQUAL( model.FindParam( "bv" )->value, "100" );
301 BOOST_CHECK_EQUAL( model.FindParam( "ibv" )->value, "100u" );
302 BOOST_CHECK_EQUAL( model.FindParam( "tt" )->value, "12.34n" );
303 break;
304
305 case 2:
306 case 3:
307 CompareToUsualDiodeModel( model, modelName, i );
308 break;
309
310 case 4:
311 BOOST_CHECK( model.GetType() == SIM_MODEL::TYPE::D );
312 BOOST_CHECK_EQUAL( modelName, "D4" );
313 BOOST_CHECK_EQUAL( model.FindParam( "is" )->value, "0.1p" );
314 BOOST_CHECK_EQUAL( model.FindParam( "rs" )->value, "2" );
315 BOOST_CHECK_EQUAL( model.FindParam( "cjo" )->value, "3p" );
316 BOOST_CHECK_EQUAL( model.FindParam( "tt" )->value, "45n" );
317 BOOST_CHECK_EQUAL( model.FindParam( "bv" )->value, "678" );
318 BOOST_CHECK_EQUAL( model.FindParam( "ibv" )->value, "0.1p" );
319 break;
320
321 case 5:
322 case 6:
323 case 7:
324 case 8:
325 case 9:
326 CompareToEmptyModel( model, modelName, i );
327 break;
328
329 case 10:
330 case 11:
331 case 12:
332 case 13:
333 case 14:
334 case 15:
335 case 16:
336 case 17:
337 CompareToUsualDiodeModel( model, modelName, i );
338 break;
339
340 case 18:
341 BOOST_CHECK( model.GetType() == SIM_MODEL::TYPE::D );
342 BOOST_CHECK_EQUAL( modelName, "D<>/?:\\|[]!@#$%^&-_18" );
343 BOOST_CHECK_EQUAL( model.FindParam( "n" )->value, "-1.1" );
344 BOOST_CHECK_EQUAL( model.FindParam( "m_" )->value, "2.2" );
345 BOOST_CHECK_EQUAL( model.FindParam( "is" )->value, "-3.3m" );
346 BOOST_CHECK_EQUAL( model.FindParam( "ibv" )->value, "44k" );
347 BOOST_CHECK_EQUAL( model.FindParam( "cjo" )->value, "55u" );
348 BOOST_CHECK_EQUAL( model.FindParam( "bv" )->value, "6.6M" );
349 break;
350
351 case 19:
352 case 20:
353 case 21:
354 CompareToUsualDiodeModel( model, modelName, i );
355 break;
356
357 case 22:
358 BOOST_CHECK( model.GetType() == SIM_MODEL::TYPE::D );
359 BOOST_CHECK_EQUAL( modelName, "D22" );
360 BOOST_CHECK_EQUAL( model.FindParam( "is" )->value, "11.1n" );
361 BOOST_CHECK_EQUAL( model.FindParam( "n" )->value, "2.2" );
362 BOOST_CHECK_EQUAL( model.FindParam( "rs" )->value, "33.3m" );
363 BOOST_CHECK_EQUAL( model.FindParam( "ikf" )->value, "99.9" );
364 BOOST_CHECK_EQUAL( model.FindParam( "xti" )->value, "3" );
365 BOOST_CHECK_EQUAL( model.FindParam( "eg" )->value, "1.1" );
366 break;
367
368 case 23:
369 BOOST_CHECK( model.GetType() == SIM_MODEL::TYPE::D );
370 BOOST_CHECK_EQUAL( modelName, "D23" );
371 BOOST_CHECK_EQUAL( model.FindParam( "is" )->value, "11.1n" );
372 BOOST_CHECK_EQUAL( model.FindParam( "n" )->value, "2.2" );
373 BOOST_CHECK_EQUAL( model.FindParam( "rs" )->value, "33.3m" );
374 BOOST_CHECK_EQUAL( model.FindParam( "ikf" )->value, "111.1" );
375 BOOST_CHECK_EQUAL( model.FindParam( "xti" )->value, "3" );
376 BOOST_CHECK_EQUAL( model.FindParam( "eg" )->value, "2.2" );
377 BOOST_CHECK_EQUAL( model.FindParam( "m_" )->value, ".3" );
378 break;
379
380 case 24:
381 BOOST_CHECK( model.GetType() == SIM_MODEL::TYPE::D );
382 BOOST_CHECK_EQUAL( modelName, "D24" );
383 BOOST_CHECK_EQUAL( model.FindParam( "is" )->value, "11.1n" );
384 BOOST_CHECK_EQUAL( model.FindParam( "n" )->value, "1.1" );
385 BOOST_CHECK_EQUAL( model.FindParam( "rs" )->value, "33.3m" );
386 BOOST_CHECK_EQUAL( model.FindParam( "ikf" )->value, "99.9" );
387 BOOST_CHECK_EQUAL( model.FindParam( "xti" )->value, "3" );
388 BOOST_CHECK_EQUAL( model.FindParam( "eg" )->value, "1.1" );
389 break;
390
391 case 25:
392 BOOST_CHECK( model.GetType() == SIM_MODEL::TYPE::D );
393 BOOST_CHECK_EQUAL( modelName, "D25" );
394 //level
395 BOOST_CHECK_EQUAL( model.FindParam( "is" )->value, "0M" );
396 //js
397 BOOST_CHECK_EQUAL( model.FindParam( "jsw" )->value, "1000.01M" );
398 BOOST_CHECK_EQUAL( model.FindParam( "tnom" )->value, "2000.02M" );
399 //tref
400 BOOST_CHECK_EQUAL( model.FindParam( "rs" )->value, "3000.03M" );
401 BOOST_CHECK_EQUAL( model.FindParam( "trs" )->value, "4000.04M" );
402 //trs1
403 BOOST_CHECK_EQUAL( model.FindParam( "trs2" )->value, "5000.05M" );
404 BOOST_CHECK_EQUAL( model.FindParam( "n" )->value, "6000.06M" );
405 BOOST_CHECK_EQUAL( model.FindParam( "ns" )->value, "7000.07M" );
406 BOOST_CHECK_EQUAL( model.FindParam( "tt" )->value, "8000.08M" );
407 BOOST_CHECK_EQUAL( model.FindParam( "ttt1" )->value, "9000.09M" );
408 BOOST_CHECK_EQUAL( model.FindParam( "ttt2" )->value, "0M" );
409 BOOST_CHECK_EQUAL( model.FindParam( "cjo" )->value, "1000.01M" );
410 //cj0
411 //cj
412 BOOST_CHECK_EQUAL( model.FindParam( "vj" )->value, "2000.02M" );
413 //pb
414 BOOST_CHECK_EQUAL( model.FindParam( "m_" )->value, "3000.03M" );
415 //mj
416 BOOST_CHECK_EQUAL( model.FindParam( "tm1" )->value, "4000.04M" );
417 BOOST_CHECK_EQUAL( model.FindParam( "tm2" )->value, "5000.05M" );
418 BOOST_CHECK_EQUAL( model.FindParam( "cjp" )->value, "6000.06M" );
419 //cjsw
420 BOOST_CHECK_EQUAL( model.FindParam( "php" )->value, "7000.07M" );
421 BOOST_CHECK_EQUAL( model.FindParam( "mjsw" )->value, "8000.08M" );
422 BOOST_CHECK_EQUAL( model.FindParam( "ikf" )->value, "9000.09M" );
423 //ik
424 BOOST_CHECK_EQUAL( model.FindParam( "ikr" )->value, "0M" );
425 BOOST_CHECK_EQUAL( model.FindParam( "nbv" )->value, "1000.01M" );
426 BOOST_CHECK_EQUAL( model.FindParam( "area_" )->value, "2000.02M" );
427 BOOST_CHECK_EQUAL( model.FindParam( "pj_" )->value, "3000.03M" );
428 BOOST_CHECK_EQUAL( model.FindParam( "tlev" )->value, "4" );
429 BOOST_CHECK_EQUAL( model.FindParam( "tlevc" )->value, "5" );
430 BOOST_CHECK_EQUAL( model.FindParam( "eg" )->value, "6000.06M" );
431 BOOST_CHECK_EQUAL( model.FindParam( "xti" )->value, "7000.07M" );
432 BOOST_CHECK_EQUAL( model.FindParam( "cta" )->value, "8000.08M" );
433 //ctc
434 BOOST_CHECK_EQUAL( model.FindParam( "ctp" )->value, "9000.09M" );
435 BOOST_CHECK_EQUAL( model.FindParam( "tpb" )->value, "0M" );
436 //tvj
437 BOOST_CHECK_EQUAL( model.FindParam( "tphp" )->value, "1000.01M" );
438 BOOST_CHECK_EQUAL( model.FindParam( "jtun" )->value, "2000.02M" );
439 BOOST_CHECK_EQUAL( model.FindParam( "jtunsw" )->value, "3000.03M" );
440 BOOST_CHECK_EQUAL( model.FindParam( "ntun" )->value, "4000.04M" );
441 BOOST_CHECK_EQUAL( model.FindParam( "xtitun" )->value, "5000.05M" );
442 BOOST_CHECK_EQUAL( model.FindParam( "keg" )->value, "6000.06M" );
443 BOOST_CHECK_EQUAL( model.FindParam( "kf" )->value, "7000.07M" );
444 BOOST_CHECK_EQUAL( model.FindParam( "af" )->value, "8000.08M" );
445 BOOST_CHECK_EQUAL( model.FindParam( "fc" )->value, "9000.09M" );
446 BOOST_CHECK_EQUAL( model.FindParam( "fcs" )->value, "0M" );
447 BOOST_CHECK_EQUAL( model.FindParam( "bv" )->value, "1000.01M" );
448 BOOST_CHECK_EQUAL( model.FindParam( "ibv" )->value, "2000.02M" );
449 //ib
450 BOOST_CHECK_EQUAL( model.FindParam( "tcv" )->value, "3000.03M" );
451 BOOST_CHECK_EQUAL( model.FindParam( "cond" )->value, "4000.04M" );
452 BOOST_CHECK_EQUAL( model.FindParam( "isr" )->value, "5000.05M" );
453 BOOST_CHECK_EQUAL( model.FindParam( "nr" )->value, "6000.06M" );
454 BOOST_CHECK_EQUAL( model.FindParam( "fv_max" )->value, "7000.07M" );
455 BOOST_CHECK_EQUAL( model.FindParam( "bv_max" )->value, "8000.08M" );
456 BOOST_CHECK_EQUAL( model.FindParam( "id_max" )->value, "9000.09M" );
457 BOOST_CHECK_EQUAL( model.FindParam( "te_max" )->value, "0M" );
458 BOOST_CHECK_EQUAL( model.FindParam( "pd_max" )->value, "1000.01M" );
459 BOOST_CHECK_EQUAL( model.FindParam( "rth0" )->value, "2000.02M" );
460 BOOST_CHECK_EQUAL( model.FindParam( "cth0" )->value, "3000.03M" );
461 BOOST_CHECK_EQUAL( model.FindParam( "lm_" )->value, "4000.04M" );
462 BOOST_CHECK_EQUAL( model.FindParam( "lp_" )->value, "5000.05M" );
463 BOOST_CHECK_EQUAL( model.FindParam( "wm_" )->value, "6000.06M" );
464 BOOST_CHECK_EQUAL( model.FindParam( "wp_" )->value, "7000.07M" );
465 BOOST_CHECK_EQUAL( model.FindParam( "xom" )->value, "8000.08M" );
466 BOOST_CHECK_EQUAL( model.FindParam( "xoi" )->value, "9000.09M" );
467 BOOST_CHECK_EQUAL( model.FindParam( "xm" )->value, "0M" );
468 BOOST_CHECK_EQUAL( model.FindParam( "xp" )->value, "1000.01M" );
469 //d
470 break;
471
472 default:
473 BOOST_FAIL( "Unknown parameter index" );
474 break;
475 }
476 }
477}
478
479
481{
482 LOCALE_IO toggle;
483
484 LoadLibrary( "bjts" );
485
486 const std::vector<SIM_LIBRARY::MODEL> models = m_library->GetModels();
487
488 BOOST_CHECK_EQUAL( models.size(), 8 );
489
490 for( int i = 0; i < models.size(); ++i )
491 {
492 const auto& [modelName, model] = models.at( i );
493
494 BOOST_TEST_CONTEXT( "BJT index: " << i )
495
496 switch( i )
497 {
498
499 case 0:
500 TestTransistor( model, modelName, i, SIM_MODEL::TYPE::NPN_VBIC,
501 {
502 "rcx",
503 "rci",
504 "vo",
505 "gamm",
506 "hrcf",
507 "rbx",
508 "rbi",
509 "re",
510 "rs",
511 "rbp",
512 "is_",
513 "nf",
514 "nr",
515 "fc",
516 "cbeo",
517 "cje",
518 "pe",
519 "me",
520 "aje",
521 "cbco",
522 "cjc",
523 "qco",
524 "cjep",
525 "pc",
526 "mc",
527 "ajc",
528 "cjcp",
529 "ps",
530 "ms",
531 "ajs",
532 "ibei",
533 "wbe",
534 "nei",
535 "iben",
536 "nen",
537 "ibci",
538 "nci",
539 "ibcn",
540 "ncn",
541 "avc1",
542 "avc2",
543 "isp",
544 "wsp",
545 "nfp",
546 "ibeip",
547 "ibenp",
548 "ibcip",
549 "ncip",
550 "ibcnp",
551 "ncnp",
552 "vef",
553 "ver",
554 "ikf",
555 "ikr",
556 "ikp",
557 "tf",
558 "qtf",
559 "xtf",
560 "vtf",
561 "itf",
562 "tr",
563 "td",
564 "kfn",
565 "afn",
566 "bfn",
567 "xre",
568 "xrb",
569 "xrbi",
570 "xrc",
571 "xrci",
572 "xrs",
573 "xvo",
574 "ea",
575 "eaie",
576 "eaic",
577 "eais",
578 "eane",
579 "eanc",
580 "eans",
581 "xis",
582 "xii",
583 "xin",
584 "tnf",
585 "tavc",
586 "rth",
587 "cth",
588 "vrt",
589 "art",
590 "ccso",
591 "qbm",
592 "nkf",
593 "xikf",
594 "xrcx",
595 "xrbx",
596 "xrbp",
597 "isrr",
598 "xisr",
599 "dear",
600 "eap",
601 "vbbe",
602 "nbbe",
603 "ibbe",
604 "tvbbe1",
605 "tvbbe2",
606 "tnbbe",
607 "ebbe",
608 "dtemp_",
609 "vers",
610 "vref",
611 "vbe_max",
612 "vbc_max",
613 "vce_max"
614 } );
615 break;
616
617 case 1:
618 TestTransistor( model, modelName, i, SIM_MODEL::TYPE::PNP_VBIC,
619 {
620 "rcx",
621 "rci",
622 "vo",
623 "gamm",
624 "hrcf",
625 "rbx",
626 "rbi",
627 "re",
628 "rs",
629 "rbp",
630 "is_",
631 "nf",
632 "nr",
633 "fc",
634 "cbeo",
635 "cje",
636 "pe",
637 "me",
638 "aje",
639 "cbco",
640 "cjc",
641 "qco",
642 "cjep",
643 "pc",
644 "mc",
645 "ajc",
646 "cjcp",
647 "ps",
648 "ms",
649 "ajs",
650 "ibei",
651 "wbe",
652 "nei",
653 "iben",
654 "nen",
655 "ibci",
656 "nci",
657 "ibcn",
658 "ncn",
659 "avc1",
660 "avc2",
661 "isp",
662 "wsp",
663 "nfp",
664 "ibeip",
665 "ibenp",
666 "ibcip",
667 "ncip",
668 "ibcnp",
669 "ncnp",
670 "vef",
671 "ver",
672 "ikf",
673 "ikr",
674 "ikp",
675 "tf",
676 "qtf",
677 "xtf",
678 "vtf",
679 "itf",
680 "tr",
681 "td",
682 "kfn",
683 "afn",
684 "bfn",
685 "xre",
686 "xrb",
687 "xrbi",
688 "xrc",
689 "xrci",
690 "xrs",
691 "xvo",
692 "ea",
693 "eaie",
694 "eaic",
695 "eais",
696 "eane",
697 "eanc",
698 "eans",
699 "xis",
700 "xii",
701 "xin",
702 "tnf",
703 "tavc",
704 "rth",
705 "cth",
706 "vrt",
707 "art",
708 "ccso",
709 "qbm",
710 "nkf",
711 "xikf",
712 "xrcx",
713 "xrbx",
714 "xrbp",
715 "isrr",
716 "xisr",
717 "dear",
718 "eap",
719 "vbbe",
720 "nbbe",
721 "ibbe",
722 "tvbbe1",
723 "tvbbe2",
724 "tnbbe",
725 "ebbe",
726 "dtemp_",
727 "vers",
728 "vref",
729 "vbe_max",
730 "vbc_max",
731 "vce_max"
732 } );
733 break;
734
735 case 2:
736 TestTransistor( model, modelName, i, SIM_MODEL::TYPE::NPN_GUMMELPOON,
737 {
738 "is_",
739 "nf",
740 "ise",
741 "ne",
742 "bf",
743 "ikf",
744 "vaf",
745 "nr",
746 "isc",
747 "nc",
748 "br",
749 "ikr",
750 "var",
751 "rb",
752 "irb",
753 "rbm",
754 "re",
755 "rc",
756 "xtb",
757 "eg",
758 "xti",
759 "cje",
760 "vje",
761 "mje",
762 "tf",
763 "xtf",
764 "vtf",
765 "itf",
766 "ptf",
767 "cjc",
768 "vjc",
769 "mjc",
770 "xcjc",
771 "tr",
772 "cjs",
773 "vjs",
774 "mjs",
775 "fc"
776 } );
777 break;
778
779 case 3:
780 TestTransistor( model, modelName, i, SIM_MODEL::TYPE::PNP_GUMMELPOON,
781 {
782 "is_",
783 "nf",
784 "ise",
785 "ne",
786 "bf",
787 "ikf",
788 "vaf",
789 "nr",
790 "isc",
791 "nc",
792 "br",
793 "ikr",
794 "var",
795 "rb",
796 "irb",
797 "rbm",
798 "re",
799 "rc",
800 "xtb",
801 "eg",
802 "xti",
803 "cje",
804 "vje",
805 "mje",
806 "tf",
807 "xtf",
808 "vtf",
809 "itf",
810 "ptf",
811 "cjc",
812 "vjc",
813 "mjc",
814 "xcjc",
815 "tr",
816 "cjs",
817 "vjs",
818 "mjs",
819 "fc"
820 } );
821 break;
822
823 case 4:
824 TestTransistor( model, modelName, i, SIM_MODEL::TYPE::NPN_HICUM2,
825 {
826 "c10",
827 "qp0",
828 "ich",
829 "hf0",
830 "hfe",
831 "hfc",
832 "hjei",
833 "ahjei",
834 "rhjei",
835 "hjci",
836 "ibeis",
837 "mbei",
838 "ireis",
839 "mrei",
840 "ibeps",
841 "mbep",
842 "ireps",
843 "mrep",
844 "mcf",
845 "tbhrec",
846 "ibcis",
847 "mbci",
848 "ibcxs",
849 "mbcx",
850 "ibets",
851 "abet",
852 "tunode",
853 "favl",
854 "qavl",
855 "kavl",
856 "alfav",
857 "alqav",
858 "alkav",
859 "rbi0",
860 "rbx",
861 "fgeo",
862 "fdqr0",
863 "fcrbi",
864 "fqi",
865 "re",
866 "rcx",
867 "itss",
868 "msf",
869 "iscs",
870 "msc",
871 "tsf",
872 "rsu",
873 "csu",
874 "cjei0",
875 "vdei",
876 "zei",
877 "ajei",
878 //"aljei", Alias.
879 "cjep0",
880 "vdep",
881 "zep",
882 "ajep",
883 //"aljep", Alias.
884 "cjci0",
885 "vdci",
886 "zci",
887 "vptci",
888 "cjcx0",
889 "vdcx",
890 "zcx",
891 "vptcx",
892 "fbcpar",
893 //"fbc", Alias.
894 "fbepar",
895 //"fbe", Alias.
896 "cjs0",
897 "vds",
898 "zs",
899 "vpts",
900 "cscp0",
901 "vdsp",
902 "zsp",
903 "vptsp",
904 "t0",
905 "dt0h",
906 "tbvl",
907 "tef0",
908 "gtfe",
909 "thcs",
910 "ahc",
911 //"alhc", Alias.
912 "fthc",
913 "rci0",
914 "vlim",
915 "vces",
916 "vpt",
917 "aick",
918 "delck",
919 "tr",
920 "vcbar",
921 "icbar",
922 "acbar",
923 "cbepar",
924 //"ceox", Alias.
925 "cbcpar",
926 //"ccox", Alias.
927 "alqf",
928 "alit",
929 "flnqs",
930 "kf",
931 "af",
932 "cfbe",
933 "flcono",
934 "kfre",
935 "afre",
936 "latb",
937 "latl",
938 "vgb",
939 "alt0",
940 "kt0",
941 "zetaci",
942 "alvs",
943 "alces",
944 "zetarbi",
945 "zetarbx",
946 "zetarcx",
947 "zetare",
948 "zetacx",
949 "vge",
950 "vgc",
951 "vgs",
952 "f1vg",
953 "f2vg",
954 "zetact",
955 "zetabet",
956 "alb",
957 "dvgbe",
958 "zetahjei",
959 "zetavgbe",
960 "flsh",
961 "rth",
962 "zetarth",
963 "alrth",
964 "cth",
965 "flcomp",
966 "vbe_max",
967 "vbc_max",
968 "vce_max"
969 } );
970 break;
971
972 case 5:
973 TestTransistor( model, modelName, i, SIM_MODEL::TYPE::PNP_HICUM2,
974 {
975 "c10",
976 "qp0",
977 "ich",
978 "hf0",
979 "hfe",
980 "hfc",
981 "hjei",
982 "ahjei",
983 "rhjei",
984 "hjci",
985 "ibeis",
986 "mbei",
987 "ireis",
988 "mrei",
989 "ibeps",
990 "mbep",
991 "ireps",
992 "mrep",
993 "mcf",
994 "tbhrec",
995 "ibcis",
996 "mbci",
997 "ibcxs",
998 "mbcx",
999 "ibets",
1000 "abet",
1001 "tunode",
1002 "favl",
1003 "qavl",
1004 "kavl",
1005 "alfav",
1006 "alqav",
1007 "alkav",
1008 "rbi0",
1009 "rbx",
1010 "fgeo",
1011 "fdqr0",
1012 "fcrbi",
1013 "fqi",
1014 "re",
1015 "rcx",
1016 "itss",
1017 "msf",
1018 "iscs",
1019 "msc",
1020 "tsf",
1021 "rsu",
1022 "csu",
1023 "cjei0",
1024 "vdei",
1025 "zei",
1026 "ajei",
1027 //"aljei", Alias.
1028 "cjep0",
1029 "vdep",
1030 "zep",
1031 "ajep",
1032 //"aljep", Alias.
1033 "cjci0",
1034 "vdci",
1035 "zci",
1036 "vptci",
1037 "cjcx0",
1038 "vdcx",
1039 "zcx",
1040 "vptcx",
1041 "fbcpar",
1042 //"fbc", Alias.
1043 "fbepar",
1044 //"fbe", Alias.
1045 "cjs0",
1046 "vds",
1047 "zs",
1048 "vpts",
1049 "cscp0",
1050 "vdsp",
1051 "zsp",
1052 "vptsp",
1053 "t0",
1054 "dt0h",
1055 "tbvl",
1056 "tef0",
1057 "gtfe",
1058 "thcs",
1059 "ahc",
1060 //"alhc", Alias.
1061 "fthc",
1062 "rci0",
1063 "vlim",
1064 "vces",
1065 "vpt",
1066 "aick",
1067 "delck",
1068 "tr",
1069 "vcbar",
1070 "icbar",
1071 "acbar",
1072 "cbepar",
1073 //"ceox", Alias.
1074 "cbcpar",
1075 //"ccox", Alias.
1076 "alqf",
1077 "alit",
1078 "flnqs",
1079 "kf",
1080 "af",
1081 "cfbe",
1082 "flcono",
1083 "kfre",
1084 "afre",
1085 "latb",
1086 "latl",
1087 "vgb",
1088 "alt0",
1089 "kt0",
1090 "zetaci",
1091 "alvs",
1092 "alces",
1093 "zetarbi",
1094 "zetarbx",
1095 "zetarcx",
1096 "zetare",
1097 "zetacx",
1098 "vge",
1099 "vgc",
1100 "vgs",
1101 "f1vg",
1102 "f2vg",
1103 "zetact",
1104 "zetabet",
1105 "alb",
1106 "dvgbe",
1107 "zetahjei",
1108 "zetavgbe",
1109 "flsh",
1110 "rth",
1111 "zetarth",
1112 "alrth",
1113 "cth",
1114 "flcomp",
1115 "vbe_max",
1116 "vbc_max",
1117 "vce_max"
1118 } );
1119
1120 break;
1121
1122 case 6:
1123 case 7:
1124 TestTransistor( model, modelName, i, SIM_MODEL::TYPE::NPN_GUMMELPOON,
1125 { "is_", "nf", "ise", "ne", "bf", "ikf", "vaf", "nr", "isc", "nc" } );
1126 break;
1127 }
1128 }
1129}
1130
1131
1133{
1134 LOCALE_IO toggle;
1135
1136 LoadLibrary( "fets" );
1137
1138 const std::vector<SIM_LIBRARY::MODEL> models = m_library->GetModels();
1139
1140 BOOST_CHECK_EQUAL( models.size(), 46 );
1141
1142 for( int i = 0; i < models.size(); ++i )
1143 {
1144 const auto& [modelName, model] = models.at( i );
1145
1146 BOOST_TEST_CONTEXT( "FET index: " << i )
1147
1148 switch( i )
1149 {
1150 case 0:
1151 TestTransistor( model, modelName, i, SIM_MODEL::TYPE::NJFET_SHICHMANHODGES,
1152 { "vt0", "beta", "lambda", "rd", "rs", "cgs", "cgd", "pb", "is_",
1153 "fc" } );
1154 break;
1155
1156 case 1:
1157 TestTransistor( model, modelName, i, SIM_MODEL::TYPE::PJFET_SHICHMANHODGES,
1158 { "vt0", "beta", "lambda", "rd", "rs", "cgs", "cgd", "pb", "is_",
1159 "fc" } );
1160 break;
1161
1162 case 2:
1163 TestTransistor( model, modelName, i, SIM_MODEL::TYPE::NJFET_PARKERSKELLERN,
1164 { "vbi", "af", "beta", "cds", "cgd", "cgs", "delta", "hfeta", "mvst",
1165 "mxi" } );
1166 break;
1167
1168 case 3:
1169 TestTransistor( model, modelName, i, SIM_MODEL::TYPE::PJFET_PARKERSKELLERN,
1170 { "vbi", "af", "beta", "cds", "cgd", "cgs", "delta", "hfeta", "mvst",
1171 "mxi" } );
1172 break;
1173
1174 case 4:
1175 TestTransistor( model, modelName, i, SIM_MODEL::TYPE::NMES_STATZ,
1176 { "vt0", "alpha", "beta", "lambda", "b", "rd", "rs", "cgs", "cgd_",
1177 "pb" } );
1178 break;
1179
1180 case 5:
1181 TestTransistor( model, modelName, i, SIM_MODEL::TYPE::PMES_STATZ,
1182 { "vt0", "alpha", "beta", "lambda", "b", "rd", "rs", "cgs", "cgd_",
1183 "pb" } );
1184 break;
1185
1186 case 6:
1187 TestTransistor( model, modelName, i, SIM_MODEL::TYPE::NMES_YTTERDAL,
1188 { "vto", "lambda", "lambdahf", "beta", "vs", "rd", "rs", "rg", "ri",
1189 "rf" } );
1190 break;
1191
1192 case 7:
1193 TestTransistor( model, modelName, i, SIM_MODEL::TYPE::PMES_YTTERDAL,
1194 { "vto", "lambda", "lambdahf", "beta", "vs", "rd", "rs", "rg", "ri",
1195 "rf" } );
1196 break;
1197
1198 case 8:
1199 TestTransistor( model, modelName, i, SIM_MODEL::TYPE::NMES_HFET1,
1200 { "vt0", "lambda", "rd", "rs", "rg", "rdi", "rsi", "rgs", "rgd",
1201 "eta" } );
1202 break;
1203
1204 case 9:
1205 TestTransistor( model, modelName, i, SIM_MODEL::TYPE::PMES_HFET1,
1206 { "vt0", "lambda", "rd", "rs", "rg", "rdi", "rsi", "rgs", "rgd",
1207 "eta" } );
1208 break;
1209
1210 case 10:
1211 TestTransistor( model, modelName, i, SIM_MODEL::TYPE::NMES_HFET2,
1212 { "vs", "ggr", "js", "del", "delta", "deltad", "di", "epsi", "eta",
1213 "eta1" } );
1214 break;
1215
1216 case 11:
1217 TestTransistor( model, modelName, i, SIM_MODEL::TYPE::PMES_HFET2,
1218 { "vs", "ggr", "js", "del", "delta", "deltad", "di", "epsi", "eta",
1219 "eta1" } );
1220 break;
1221
1222 case 12:
1223 TestTransistor( model, modelName, i, SIM_MODEL::TYPE::NMOS_VDMOS,
1224 {
1225 //"type",
1226 "vto",
1227 //"vth0",
1228 "kp",
1229 "phi",
1230 "lambda",
1231 "theta",
1232 "rd_",
1233 "rs_",
1234 "rg",
1235 "tnom",
1236 "kf",
1237 "af",
1238 //"vdmosn",
1239 //"vdmosp",
1240 //"vdmos",
1241 "rq",
1242 "vq",
1243 "mtriode",
1244 "tcvth",
1245 //"vtotc",
1246 "mu",
1247 //"bex",
1248 "texp0",
1249 "texp1",
1250 "trd1",
1251 "trd2",
1252 "trg1",
1253 "trg2",
1254 "trs1",
1255 "trs2",
1256 "trb1",
1257 "trb2",
1258 "subshift",
1259 "ksubthres",
1260 "tksubthres1",
1261 "tksubthres2",
1262 "bv",
1263 "ibv",
1264 "nbv",
1265 "rds",
1266 "rb",
1267 "n",
1268 "tt",
1269 "eg",
1270 "xti",
1271 "is_",
1272 "vj",
1273 "cjo",
1274 "m_",
1275 "fc",
1276 "cgdmin",
1277 "cgdmax",
1278 "a",
1279 "cgs_",
1280 "rthjc",
1281 "rthca",
1282 "cthj",
1283 "vgs_max",
1284 "vgd_max",
1285 "vds_max",
1286 "vgsr_max",
1287 "vgdr_max",
1288 "pd_max",
1289 "id_max",
1290 "idr_max",
1291 "te_max",
1292 "rth_ext",
1293 "derating"
1294 } );
1295 break;
1296
1297 case 13:
1298 TestTransistor( model, modelName, i, SIM_MODEL::TYPE::PMOS_VDMOS,
1299 {
1300 //"type",
1301 "vto",
1302 //"vth0",
1303 "kp",
1304 "phi",
1305 "lambda",
1306 "theta",
1307 "rd_",
1308 "rs_",
1309 "rg",
1310 "tnom",
1311 "kf",
1312 "af",
1313 //"vdmosn",
1314 //"vdmosp",
1315 //"vdmos",
1316 "rq",
1317 "vq",
1318 "mtriode",
1319 "tcvth",
1320 //"vtotc",
1321 "mu",
1322 //"bex",
1323 "texp0",
1324 "texp1",
1325 "trd1",
1326 "trd2",
1327 "trg1",
1328 "trg2",
1329 "trs1",
1330 "trs2",
1331 "trb1",
1332 "trb2",
1333 "subshift",
1334 "ksubthres",
1335 "tksubthres1",
1336 "tksubthres2",
1337 "bv",
1338 "ibv",
1339 "nbv",
1340 "rds",
1341 "rb",
1342 "n",
1343 "tt",
1344 "eg",
1345 "xti",
1346 "is_",
1347 "vj",
1348 "cjo",
1349 "m_",
1350 "fc",
1351 "cgdmin",
1352 "cgdmax",
1353 "a",
1354 "cgs_",
1355 "rthjc",
1356 "rthca",
1357 "cthj",
1358 "vgs_max",
1359 "vgd_max",
1360 "vds_max",
1361 "vgsr_max",
1362 "vgdr_max",
1363 "pd_max",
1364 "id_max",
1365 "idr_max",
1366 "te_max",
1367 "rth_ext",
1368 "derating"
1369 } );
1370 break;
1371
1372 case 14:
1373 TestTransistor( model, modelName, i, SIM_MODEL::TYPE::NMOS_MOS1,
1374 { "vto", "kp", "gamma", "phi", "lambda", "rd_", "rs_", "cbd_", "cbs_",
1375 "is_" } );
1376 break;
1377
1378 case 15:
1379 TestTransistor( model, modelName, i, SIM_MODEL::TYPE::PMOS_MOS1,
1380 { "vto", "kp", "gamma", "phi", "lambda", "rd_", "rs_", "cbd_", "cbs_",
1381 "is_" } );
1382 break;
1383
1384 case 16:
1385 TestTransistor( model, modelName, i, SIM_MODEL::TYPE::NMOS_MOS2,
1386 { "vto", "kp", "gamma", "phi", "lambda", "rd_", "rs_", "cbd_", "cbs_",
1387 "is_" } );
1388 break;
1389
1390 case 17:
1391 TestTransistor( model, modelName, i, SIM_MODEL::TYPE::PMOS_MOS2,
1392 { "vto", "kp", "gamma", "phi", "lambda", "rd_", "rs_", "cbd_", "cbs_",
1393 "is_" } );
1394 break;
1395
1396 case 18:
1397 TestTransistor( model, modelName, i, SIM_MODEL::TYPE::NMOS_MOS3,
1398 { "vto", "theta", "gamma", "phi", "eta", "rd_", "rs_", "cbd_", "cbs_",
1399 "is_" } );
1400 break;
1401
1402 case 19:
1403 TestTransistor( model, modelName, i, SIM_MODEL::TYPE::PMOS_MOS3,
1404 { "vto", "theta", "gamma", "phi", "eta", "rd_", "rs_", "cbd_", "cbs_",
1405 "is_" } );
1406 break;
1407
1408 case 20:
1409 TestTransistor( model, modelName, i, SIM_MODEL::TYPE::NMOS_BSIM1,
1410 { "vfb", "lvfb", "wvfb", "phi", "lphi", "wphi", "k1", "lk1", "wk1",
1411 "k2" } );
1412 break;
1413
1414 case 21:
1415 TestTransistor( model, modelName, i, SIM_MODEL::TYPE::PMOS_BSIM1,
1416 { "vfb", "lvfb", "wvfb", "phi", "lphi", "wphi", "k1", "lk1", "wk1",
1417 "k2" } );
1418 break;
1419
1420 case 22:
1421 TestTransistor( model, modelName, i, SIM_MODEL::TYPE::NMOS_BSIM2,
1422 { "bib", "lbib", "wbib", "vghigh", "lvghigh", "wvghigh",
1423 "waib", "bi0", "lbi0", "wbi0" } );
1424 break;
1425
1426 case 23:
1427 TestTransistor( model, modelName, i, SIM_MODEL::TYPE::PMOS_BSIM2,
1428 { "bib", "lbib", "wbib", "vghigh", "lvghigh", "wvghigh",
1429 "waib", "bi0", "lbi0", "wbi0" } );
1430 break;
1431
1432 case 24:
1433 TestTransistor( model, modelName, i, SIM_MODEL::TYPE::NMOS_MOS6,
1434 { "vto", "nvth", "gamma", "phi", "lambda", "rd_", "rs_", "cbd_", "cbs_",
1435 "is_" } );
1436 break;
1437
1438 case 25:
1439 TestTransistor( model, modelName, i, SIM_MODEL::TYPE::PMOS_MOS6,
1440 { "vto", "nvth", "gamma", "phi", "lambda", "rd_", "rs_", "cbd_", "cbs_",
1441 "is_" } );
1442 break;
1443
1444 case 26:
1445 TestTransistor( model, modelName, i, SIM_MODEL::TYPE::NMOS_BSIM3,
1446 { "tox", "toxm", "cdsc", "cdscb", "cdscd", "cit", "nfactor", "xj",
1447 "vsat", "at" } );
1448 break;
1449
1450 case 27:
1451 TestTransistor( model, modelName, i, SIM_MODEL::TYPE::PMOS_BSIM3,
1452 { "tox", "toxm", "cdsc", "cdscb", "cdscd", "cit", "nfactor", "xj",
1453 "vsat", "at" } );
1454 break;
1455
1456 case 28:
1457 TestTransistor( model, modelName, i, SIM_MODEL::TYPE::NMOS_MOS9,
1458 { "vto", "theta", "gamma", "phi", "eta", "rd_", "rs_", "cbd_", "cbs_",
1459 "is_" } );
1460 break;
1461
1462 case 29:
1463 TestTransistor( model, modelName, i, SIM_MODEL::TYPE::PMOS_MOS9,
1464 { "vto", "theta", "gamma", "phi", "eta", "rd_", "rs_", "cbd_", "cbs_",
1465 "is_" } );
1466 break;
1467
1468 case 30:
1469 TestTransistor( model, modelName, i, SIM_MODEL::TYPE::NMOS_B4SOI,
1470 { "tox", "toxp", "toxm", "dtoxcv", "cdsc", "cdscb", "cdscd", "cit",
1471 "nfactor", "vsat" } );
1472 break;
1473
1474 case 31:
1475 TestTransistor( model, modelName, i, SIM_MODEL::TYPE::PMOS_B4SOI,
1476 { "tox", "toxp", "toxm", "dtoxcv", "cdsc", "cdscb", "cdscd", "cit",
1477 "nfactor", "vsat" } );
1478 break;
1479
1480 case 32:
1481 TestTransistor( model, modelName, i, SIM_MODEL::TYPE::NMOS_BSIM4,
1482 { "rbps0", "rbpsl", "rbpsw", "rbpsnf", "rbpd0", "rbpdl", "rbpdw", "rbpdnf",
1483 "rbpbx0", "rbpbxl" } );
1484 break;
1485
1486 case 33:
1487 TestTransistor( model, modelName, i, SIM_MODEL::TYPE::PMOS_BSIM4,
1488 { "rbps0", "rbpsl", "rbpsw", "rbpsnf", "rbpd0", "rbpdl", "rbpdw", "rbpdnf",
1489 "rbpbx0", "rbpbxl" } );
1490 break;
1491
1492 case 34:
1493 TestTransistor( model, modelName, i, SIM_MODEL::TYPE::NMOS_B3SOIFD,
1494 { "tox", "cdsc", "cdscb", "cdscd", "cit", "nfactor", "vsat", "at", "a0",
1495 "ags" } );
1496 break;
1497
1498 case 35:
1499 TestTransistor( model, modelName, i, SIM_MODEL::TYPE::PMOS_B3SOIFD,
1500 { "tox", "cdsc", "cdscb", "cdscd", "cit", "nfactor", "vsat", "at", "a0",
1501 "ags" } );
1502 break;
1503
1504 case 36:
1505 TestTransistor( model, modelName, i, SIM_MODEL::TYPE::NMOS_B3SOIDD,
1506 { "tox", "cdsc", "cdscb", "cdscd", "cit", "nfactor", "vsat", "at", "a0",
1507 "ags" } );
1508 break;
1509
1510 case 37:
1511 TestTransistor( model, modelName, i, SIM_MODEL::TYPE::PMOS_B3SOIDD,
1512 { "tox", "cdsc", "cdscb", "cdscd", "cit", "nfactor", "vsat", "at", "a0",
1513 "ags" } );
1514 break;
1515
1516 case 38:
1517 TestTransistor( model, modelName, i, SIM_MODEL::TYPE::NMOS_B3SOIPD,
1518 { "tox", "cdsc", "cdscb", "cdscd", "cit", "nfactor", "vsat", "at", "a0",
1519 "ags" } );
1520 break;
1521
1522 case 39:
1523 TestTransistor( model, modelName, i, SIM_MODEL::TYPE::PMOS_B3SOIPD,
1524 { "tox", "cdsc", "cdscb", "cdscd", "cit", "nfactor", "vsat", "at", "a0",
1525 "ags" } );
1526 break;
1527
1528 case 40:
1529 TestTransistor( model, modelName, i, SIM_MODEL::TYPE::NMOS_HISIM2,
1530 { "depmue0", "depmue0l", "depmue0lp", "depmue1", "depmue1l",
1531 "depmue1lp", "depmueback0", "depmueback0l", "depmueback0lp",
1532 "depmueback1" } );
1533 break;
1534
1535 case 41:
1536 TestTransistor( model, modelName, i, SIM_MODEL::TYPE::PMOS_HISIM2,
1537 { "depmue0", "depmue0l", "depmue0lp", "depmue1", "depmue1l", "depmue1lp",
1538 "depmueback0", "depmueback0l", "depmueback0lp", "depmueback1" } );
1539 break;
1540
1541 case 42:
1542 TestTransistor( model, modelName, i, SIM_MODEL::TYPE::NMOS_HISIMHV1,
1543 { "prd", "prd22", "prd23", "prd24", "prdict1", "prdov13", "prdslp1",
1544 "prdvb", "prdvd", "prdvg11" } );
1545 break;
1546
1547 case 43:
1548 TestTransistor( model, modelName, i, SIM_MODEL::TYPE::PMOS_HISIMHV1,
1549 { "prd", "prd22", "prd23", "prd24", "prdict1", "prdov13", "prdslp1",
1550 "prdvb", "prdvd", "prdvg11" } );
1551 break;
1552
1553 case 44:
1554 TestTransistor( model, modelName, i, SIM_MODEL::TYPE::NMOS_HISIMHV2,
1555 { "pjs0d", "pjs0swd", "pnjd", "pcisbkd", "pvdiffjd", "pjs0s", "pjs0sws",
1556 "prs", "prth0", "pvover" } );
1557 break;
1558
1559 case 45:
1560 TestTransistor( model, modelName, i, SIM_MODEL::TYPE::PMOS_HISIMHV2,
1561 { "pjs0d", "pjs0swd", "pnjd", "pcisbkd", "pvdiffjd", "pjs0s", "pjs0sws",
1562 "prs", "prth0", "pvover" } );
1563 break;
1564 }
1565 }
1566}
1567
1568
1569// Test that loading an invalid binary file does not crash. (Issue #22189)
1570// When a binary file like an OrCAD .olb is selected instead of a valid SPICE library,
1571// the parser should not crash but report an error gracefully.
1572BOOST_AUTO_TEST_CASE( InvalidBinaryFile )
1573{
1574 LOCALE_IO toggle;
1575
1576 // This should not throw an exception or crash
1577 BOOST_CHECK_NO_THROW( LoadLibrary( "invalid_binary" ) );
1578
1579 // The library should have no valid models since it's not a valid SPICE file
1580 const std::vector<SIM_LIBRARY::MODEL> models = m_library->GetModels();
1581 BOOST_CHECK_EQUAL( models.size(), 0 );
1582}
1583
1584
1585// SPICE library parsing builds its models on the thread pool, and every parameter value parsed
1586// scopes a LOCALE_IO to switch to the "C" locale. LOCALE_IO drives the process-global locale,
1587// so constructing and destroying it from several threads at once must not corrupt the heap or the
1588// locale state. Before this was serialized, concurrent toggles damaged the malloc free list,
1589// crashing when a large SPICE library was loaded from the simulation model editor. (Issue #24627)
1590BOOST_AUTO_TEST_CASE( LocaleIoConcurrency )
1591{
1592 constexpr int threadCount = 16;
1593 constexpr int iterations = 5000;
1594 std::atomic<bool> start{ false };
1595 std::vector<std::thread> threads;
1596
1597 for( int t = 0; t < threadCount; ++t )
1598 {
1599 threads.emplace_back(
1600 [&]()
1601 {
1602 while( !start.load( std::memory_order_acquire ) )
1603 std::this_thread::yield();
1604
1605 for( int i = 0; i < iterations; ++i )
1606 {
1607 LOCALE_IO toggle;
1608
1609 // Touch the "C" locale the way file parsing does, so the test also exercises
1610 // overlapping nested scopes from different threads.
1611 volatile double parsed = std::strtod( "1.5", nullptr );
1612 (void) parsed;
1613 }
1614 } );
1615 }
1616
1617 start.store( true, std::memory_order_release );
1618
1619 for( std::thread& thread : threads )
1620 thread.join();
1621
1622 // Reaching here without a crash or a corrupted free list is the actual assertion; the explicit
1623 // check just keeps Boost from reporting the case as containing no assertions.
1624 BOOST_CHECK( true );
1625}
1626
1627
1628// A CPL (Coupled Multiconductor Line) model whose parameters mix bare numeric multi-values with
1629// braced expressions, e.g. "R=1 0 1 L={L11} {L12} {L22} ...", used to hang the parser (issue
1630// #22105) or, once the hang was fixed, drop values once a parameter switched between the braced and
1631// bare forms. CPL has no native KiCad type, so each model lands as RAWSPICE carrying its whole
1632// line as raw code; assert every model line survives parsing intact.
1634{
1635 LOCALE_IO toggle;
1636
1637 LoadLibrary( "cpl_models" );
1638
1639 std::map<std::string, std::string> spiceByName;
1640
1641 for( const auto& [modelName, model] : m_library->GetModels() )
1642 {
1643 BOOST_TEST_CONTEXT( "CPL model: " << modelName )
1644 {
1645 // A CPL model has no native KiCad type, so it is passed through as raw SPICE.
1646 BOOST_CHECK( model.GetType() == SIM_MODEL::TYPE::RAWSPICE );
1647
1648 auto* fallback = dynamic_cast<const SIM_MODEL_SPICE_FALLBACK*>( &model );
1649 BOOST_REQUIRE( fallback );
1650 spiceByName[modelName] = fallback->GetSpiceCode();
1651 }
1652 }
1653
1654 auto codeContains =
1655 [&]( const std::string& aName, const std::string& aFragment )
1656 {
1657 auto it = spiceByName.find( aName );
1658 BOOST_REQUIRE( it != spiceByName.end() );
1659 BOOST_CHECK( it->second.find( aFragment ) != std::string::npos );
1660 };
1661
1662 BOOST_REQUIRE_EQUAL( spiceByName.size(), 5 );
1663
1664 // The exact multi-parameter line from the issue must round-trip unmangled.
1665 codeContains( "PLINE_MIXED", "R=1 0 1 L={L11} {L12} {L22} G=0 0 0 C={C11} {C12} {C22}" );
1666
1667 // A parameter that starts braced and then goes bare (and vice versa) must keep both.
1668 codeContains( "PLINE_BRACE_FIRST", "R={R11} 0 {R22} L=1e-9 {L12} 1e-9" );
1669
1670 codeContains( "PLINE_BRACED", "R={R11} {R12} {R22}" );
1671 codeContains( "PLINE_NUMERIC", "R=1 0 1 L=1e-9 0 1e-9" );
1672 codeContains( "PLINE_EMPTY", "PLINE_EMPTY CPL" );
1673}
1674
1675
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition locale_io.h:37
A singleton reporter that reports to nowhere.
Definition reporter.h:214
virtual const PARAM & GetParam(unsigned aParamIndex) const
int GetParamCount() const
Definition sim_model.h:488
DEVICE_INFO GetDeviceInfo() const
Definition sim_model.h:467
INFO GetTypeInfo() const
Definition sim_model.h:468
const PARAM * FindParam(const std::string &aParamName) const
const PARAM & GetParamOverride(unsigned aParamIndex) const
SPICE_INFO GetSpiceInfo() const
Definition sim_model.h:459
TYPE GetType() const
Definition sim_model.h:471
void LoadLibrary(const std::string &aBaseName)
void TestTransistor(const SIM_MODEL &aModel, const std::string &aModelName, int aModelIndex, SIM_MODEL::TYPE aType, const std::vector< std::string > &aParamNames)
std::string GetLibraryPath(const std::string &aBaseName)
void CompareToUsualDiodeModel(const SIM_MODEL &aModel, const std::string &aModelName, int aModelIndex)
std::unique_ptr< SIM_LIBRARY_SPICE > m_library
void CompareToEmptyModel(const SIM_MODEL &aModel, const std::string &aModelName, int aModelIndex)
std::string GetEeschemaTestDataDir()
Get the configured location of Eeschema test data.
SIM_VALUE::TYPE type
Definition sim_model.h:377
std::string value
Definition sim_model.h:398
const INFO & info
Definition sim_model.h:399
std::string modelType
Definition sim_model.h:303
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_AUTO_TEST_SUITE_END()
std::string path
KIBIS_MODEL * model
BOOST_AUTO_TEST_CASE(Subckts)
BOOST_TEST_CONTEXT("Test Clearance")
BOOST_CHECK_EQUAL(result, "25.4")