1 /* $Id: spice-wrapper.cc 2016/03/29 al $ -*- C++ -*-
2 * Copyright (C) 2007 Albert Davis
3 * Author: Albert Davis <aldavis@gnu.org>
5 * This file is part of "Gnucap", the Gnu Circuit Analysis Package
7 * This file is distributed as is, completely without warranty or
8 * service support. The author and its employees are not liable for
9 * the condition or performance of the software.
11 * The author owns the copyright but shall not be liable for any
12 * infringement of copyright or other proprietary rights brought by
13 * third parties against the users of the software.
15 * The author hereby disclaims all implied warranties.
17 * This author grants the users the right to modify, copy, and
18 * redistribute this file, for any purpose, both within the user's
19 * organization and externally.
21 //testing=script 2008.11.28
22 // code style comment: Use of "reinterpret_cast" is always bad style.
23 /*--------------------------------------------------------------------------*/
26 #define _complex CompleX
60 /*--------------------------------------------------------------------------*/
67 /*--------------------------------------------------------------------------*/
68 // customization -- must be last
70 #if !defined(UNCONNECTED_NODES)
71 #define UNCONNECTED_NODES uDISALLOW
72 #if (MIN_NET_NODES != MAX_NET_NODES)
73 #error "What should I do with the unconnected nodes?"
76 #if !defined(VALUE_NAME)
77 #define VALUE_NAME "#"
79 #if !defined(TAIL_SIZE)
82 #if !defined(IS_VALID)
83 #define IS_VALID {return MODEL_CARD::is_valid(d);}
85 /*--------------------------------------------------------------------------*/
87 const int SPICE_INVALID_NODE
= 0;
88 const int SPICE_UNCONNECTED_NODE
= -1;
90 enum {uGROUND
=1, uFLOAT
=2, uDISALLOW
=3};
91 const int MATRIX_NODES
= (MAX_NET_NODES
+ INTERNAL_NODES
);
94 static COMMON_SUBCKT
Default_Params(CC_STATIC
);
95 /*--------------------------------------------------------------------------*/
96 /* function mapping: see devdefs.h
97 * DEVparam DEV_SPICE::parse_spice
98 * DEVmodParam MODEL_SPICE::parse_params
99 * DEVload DEV_SPICE::do_tr
100 * DEVsetup MODEL_SPICE::precalc, DEV_SPICE::expand
101 * DEVunsetup not used -- spice baggage -- just zeros some nodes
102 * DEVpzSetup not used -- pole-zero
103 * DEVtemperature DEV_SPICE::internal_precalc
104 * DEVtrunc DEV_SPICE::tr_review
105 * DEVfindBranch not used -- current probes for current controlled source
106 * DEVacLoad DEV_SPICE::do_ac
107 * DEVaccept not used -- sets break points //BUG// need for: isrc, ltra, tra, vsrc, cpl, txl
108 * DEVdestroy not used -- spice baggage -- deletes a list
109 * DEVmodDelete not used -- spice baggage -- delete one model
110 * DEVdelete not used -- spice baggage -- delete one instance
111 * DEVsetic not used -- "getic" -- initial conditions //BUG// need this
112 * DEVask DEV_SPICE::print_args, DEV_SPICE::tr_probe_num
113 * DEVmodAsk MODEL_SPICE::print_params, MODEL_SPICE::print_calculated
114 * DEVpzLoad not used -- pole zero -- should use for AC
115 * DEVconvTest DEV_SPICE::do_tr
116 * DEVsenSetup not used -- sensitivity
117 * DEVsenLoad not used -- sensitivity
118 * DEVsenUpdate not used -- sensitivity
119 * DEVsenAcLoad not used -- sensitivity
120 * DEVsenPrint not used -- sensitivity
121 * DEVsenTrunc not used -- sensitivity
122 * DEVdisto not used -- distortion
123 * DEVnoise not used -- noise
125 /*--------------------------------------------------------------------------*/
126 union SPICE_MODEL_DATA
{
127 mutable GENmodel _gen
;// generic -- use this one
128 MODEL _full
; // determines size
129 char _space
; // char pointer for fill_n
132 std::fill_n(&_space
, sizeof(MODEL
), '\0');
134 SPICE_MODEL_DATA(const SPICE_MODEL_DATA
& p
)
138 /*--------------------------------------------------------------------------*/
139 class MODEL_SPICE
: public MODEL_CARD
{
142 static CKTcircuit _ckt
;
144 SPICE_MODEL_DATA _spice_model
;
149 explicit MODEL_SPICE(const MODEL_SPICE
& p
); // for clone
151 explicit MODEL_SPICE(const DEV_SPICE
* p
); // for dispatcher
153 public: // override virtual
154 MODEL_CARD
* clone()const {return new MODEL_SPICE(*this);}
155 bool is_valid(const COMPONENT
* d
)const IS_VALID
157 void precalc_first();
160 void set_dev_type(const std::string
& nt
);
161 std::string
dev_type()const { return _key
;}
163 public: // parameters
164 bool param_is_printable(int)const;
165 std::string
param_name(int)const;
166 std::string
param_name(int i
, int j
)const;
167 std::string
param_value(int)const;
168 void set_param_by_name(std::string Name
, std::string Value
);
169 void set_param_by_index(int, std::string
&, int);
170 int param_count_dont_print()const {return MODEL_CARD::param_count();}
171 int param_count()const { return (static_cast<int>(_params
.size()) + MODEL_CARD::param_count());}
173 void Set_param_by_name(std::string Name
, std::string Value
);
175 public: // not virtual
176 static int count() {untested(); return _count
;}
177 static CKTcircuit
* ckt() {return &_ckt
;}
178 static void init_ckt();
180 /*--------------------------------------------------------------------------*/
181 class DEV_SPICE
: public STORAGE
{
187 mutable GENinstance _spice_instance
;
191 std::string _modelname
;
192 const MODEL_SPICE
* _model
;
193 const SPICE_MODEL_DATA
* _spice_model
;
194 node_t _nodes
[MATRIX_NODES
];
195 COMPLEX
* _matrix
[MATRIX_NODES
+OFFSET
]; // For tran, real is now, imag is saved.
196 COMPLEX _matrix_core
[MATRIX_NODES
+OFFSET
][MATRIX_NODES
+OFFSET
];
198 double _i0
[MATRIX_NODES
+OFFSET
]; // right side - current offsets or ac real part
199 double _i1
[MATRIX_NODES
+OFFSET
]; // right side - saved ......... or ac imag part
200 double _v1
[MATRIX_NODES
+OFFSET
]; // input voltages
201 double* (_states
[8]); // array of 8 pointers
206 explicit DEV_SPICE(const DEV_SPICE
& p
);
208 explicit DEV_SPICE();
210 protected: // override virtual
211 char id_letter()const {untested();return SPICE_LETTER
[0];}
212 bool print_type_in_spice()const {return true;}
213 std::string
value_name()const {return VALUE_NAME
;}
214 int max_nodes()const {return MAX_NET_NODES
;}
215 int min_nodes()const {return MIN_NET_NODES
;}
216 int matrix_nodes()const {return MATRIX_NODES
;}
217 int net_nodes()const {return _net_nodes
;}
218 int int_nodes()const {return INTERNAL_NODES
;}
219 CARD
* clone()const {return new DEV_SPICE(*this);}
220 //void precalc_first(); //ELEMENT
223 //void map_nodes(); //ELEMENT
224 void internal_precalc();
226 void tr_iwant_matrix() {tr_iwant_matrix_extended();}
227 void tr_begin() {STORAGE::tr_begin(); internal_precalc();}
228 void tr_restore() {STORAGE::tr_restore(); internal_precalc();}
229 void dc_advance() {STORAGE::dc_advance(); internal_precalc();}
232 bool tr_needs_eval()const;
233 //void tr_queue_eval(); //ELEMENT
236 TIME_PAIR
tr_review();
239 double tr_involts()const {unreachable();return NOT_VALID
;}
240 //double tr_input()const //ELEMENT
241 double tr_involts_limited()const {unreachable();return NOT_VALID
;}
242 //double tr_input_limited()const //ELEMENT
243 double tr_amps()const {itested();return NOT_VALID
;}
244 double tr_probe_num(const std::string
&)const;
246 void ac_iwant_matrix() {ac_iwant_matrix_extended();}
250 COMPLEX
ac_involts()const {unreachable();return NOT_VALID
;}
251 COMPLEX
ac_amps()const {unreachable();return NOT_VALID
;}
252 XPROBE
ac_probe_ext(const std::string
&)const {itested(); return XPROBE(NOT_VALID
, mtNONE
);}
253 int tail_size()const {return TAIL_SIZE
;}
255 void set_dev_type(const std::string
& nt
);
256 std::string
dev_type()const {return _modelname
;}
258 // bool port_exists(int i)const //COMPONENT
259 std::string
port_name(int i
)const {itested();
261 assert(i
< MAX_NET_NODES
);
262 return port_names
[i
];
264 // const std::string& port_value(int i)const; //COMPONENT
265 //void set_port_by_name(std::string& name, std::string& value);
266 //void set_port_by_index(int index, std::string& value);
267 private: // parameters
268 //bool Param_exists(int i)const; // {return Param_name(i) != "";}
269 //bool Param_is_printable(int)const;
270 //std::string Param_name(int)const;
271 //std::string Param_name(int i, int j)const {return STORAGE::Param_name(i, j);}
272 //std::string Param_value(int)const;
273 void set_param_by_name(std::string Name
, std::string Value
);
274 void Set_param_by_name(std::string Name
, std::string Value
);
275 void Set_param_by_index(int, std::string
&, int);
276 int param_count_dont_print()const {return common()->COMMON_COMPONENT::param_count();}
278 CKTcircuit
* ckt()const {return MODEL_SPICE::ckt();}
279 void init_ckt() {MODEL_SPICE::init_ckt();}
280 void update_ckt()const;
281 void localize_ckt()const;
282 int* spice_nodes()const {return &(_spice_instance
.GENnode1
);}
284 /*--------------------------------------------------------------------------*/
285 /*--------------------------------------------------------------------------*/
286 CKTcircuit
MODEL_SPICE::_ckt
;
288 * used as intended, copy-out, matters: CKTnoncon, CKTtroubleElt
290 * used as intended, func specific: CKTmode, CKTcurrentAnalysis
292 * used as intended, localized, matters: CKTstates, CKTdelta, CKTdeltaOld,
293 * CKTag(broken), CKTorder(broken), CKTrhs, CKTrhsOld, CKTirhs,
294 * CKTtimePoints(broken,ltra?)
296 * used as intended, updated, matters: CKTtime, CKTtemp, CKTomega
298 * used as intended, constant, matters: CKTnomTemp, CKTabstol,
299 * CKTreltol, CKTvoltTol, CKTgmin, CKTsrcFact(broken),
300 * CKTdefaultMosL, CKTdefaultMosW, CKTdefaultMosAD, CKTdefaultMosAS,
302 * used almost as intended, matters, probably ok:
303 * CKTbypass: false to disable
304 * CKTintegrateMethod: used only by Jspice -- set to 0 to disable
305 * CKTsenInfo: used by sens, NULL to disable
306 * CKTfixLimit(mos1236): 1 for Spice-2 mode
307 * CKTbadMos3(mos3): false for Spice-3 mode
309 * misused: (not used by spice devs, use to pass gnucap stuff through)
310 * CKTstat: the device (type DEV_SPICE)
311 * CKTmaxEqNum: use as counter for internal nodes, pass to CKTmkVolt
313 * need to handle (ind): CKThead(ind,load)
314 * need to handle (cpl,txl): CKTnodes(cpl,txl),
316 * need to handle ([iv]src):
317 * CKTbreak([iv]src,accept), CKTfinalTime([iv]src,load), CKTstep([iv]src,load),
319 * need to handle (ltra):
320 * CKTminBreak(ltra,tra,accept), CKTtrtol(ltra,trunc),
321 * CKTmaxStep(ltra,temp), CKTtimeListSize(ltra,Jspice,accept),
322 * CKTtimeIndex(ltra), CKTsizeIncr(ltra), CKTtryToCompact(ltra)
324 * used by "predictor": CKTagp, CKTpred, CKTsols
325 * used by "sens": CKTirhsOld, CKTrhsOp
326 * used by noise&distortion: CKTcurJob
328 * not used: CKTvt, CKTmaxOrder, CKTmatrix, CKTniState, CKTrhsSpare,
329 * CKTirhsSpare, CKTsenRhs, CKTseniRhs, CKTlastNode, CKTnumStates,
330 * CKTdcMaxIter, CKTdcTrcvMaxIter, CKTtranMaxIter, CKTbreakSize, CKTsaveDelta,
331 * CKTbreaks, CKTpivotAbsTol, CKTpivotRelTol, CKTchgtol, CKTlteReltol, CKTlteAbstol,
332 * CKTdelmin, CKTinitTime, CKTdiagGmin, CKTnumSrcSteps, CKTnumGminSteps, CKThadNodeset,
333 * CKTnoOpIter, CKTisSetup, CKTdeltaList, CKTkeepOpInfo, CKTtroubleNode
335 #define assert_ckt_initialized(ckt) { \
337 assert((ckt)->CKTnomTemp == OPT::tnom_c + CONSTCtoK); \
338 assert(((ckt)->CKTcurrentAnalysis == DOING_DCOP) == CKT_BASE::_sim->command_is_op()); \
339 assert(((ckt)->CKTcurrentAnalysis == DOING_TRCV) == CKT_BASE::_sim->command_is_dc()); \
340 assert(((ckt)->CKTcurrentAnalysis == DOING_AC ) == CKT_BASE::_sim->analysis_is_ac()); \
341 assert(((ckt)->CKTcurrentAnalysis == DOING_TRAN) == CKT_BASE::_sim->analysis_is_tran()); \
342 assert((ckt)->CKTbypass == false); \
343 assert((ckt)->CKTabstol == OPT::abstol); \
344 assert((ckt)->CKTreltol == OPT::reltol); \
345 assert((ckt)->CKTvoltTol == OPT::vntol); \
346 assert((ckt)->CKTsrcFact == 1.); \
347 assert((ckt)->CKTdefaultMosL == OPT::defl); \
348 assert((ckt)->CKTdefaultMosW == OPT::defw); \
349 assert((ckt)->CKTdefaultMosAD == OPT::defad); \
350 assert((ckt)->CKTdefaultMosAS == OPT::defas); \
353 void MODEL_SPICE::init_ckt()
356 ckt()->CKTtime
= _sim
->_time0
;
357 ckt()->CKTtemp
= _sim
->_temp_c
+ CONSTCtoK
; //manage by update
358 ckt()->CKTnomTemp
= OPT::tnom_c
+ CONSTCtoK
;
359 ckt()->CKTintegrateMethod
= 0; // disable
360 if (_sim
->command_is_op()) {
361 ckt()->CKTcurrentAnalysis
= DOING_DCOP
;
362 }else if (_sim
->command_is_dc()) {
363 ckt()->CKTcurrentAnalysis
= DOING_TRCV
;
364 }else if (_sim
->command_is_ac()) {
365 ckt()->CKTcurrentAnalysis
= DOING_AC
;
366 }else if (_sim
->analysis_is_tran()) {
367 ckt()->CKTcurrentAnalysis
= DOING_TRAN
;
368 }else{ // probably probe
369 ckt()->CKTcurrentAnalysis
= 0;
371 ckt()->CKTmode
= 0; // wrong but safe
372 ckt()->CKTbypass
= false; // manage this elsewhere
373 ckt()->CKTabstol
= OPT::abstol
;
374 ckt()->CKTreltol
= OPT::reltol
;
375 ckt()->CKTvoltTol
= OPT::vntol
;
376 ckt()->CKTgmin
= OPT::gmin
;
377 ckt()->CKTsrcFact
= 1.; // source stepping kluge
378 ckt()->CKTdefaultMosL
= OPT::defl
;
379 ckt()->CKTdefaultMosW
= OPT::defw
;
380 ckt()->CKTdefaultMosAD
= OPT::defad
;
381 ckt()->CKTdefaultMosAS
= OPT::defas
;
382 ckt()->CKTfixLimit
= false; // limiting kluge 1 == spice2
384 ckt()->CKTbadMos3
= false; // 1 = spice2 compat
385 ckt()->CKTsenInfo
= NULL
; // used as flag to print sens info
388 ckt()->CKTdefaultMosM
= 1.;
389 ckt()->CKTcopyNodesets
= false;
391 assert_ckt_initialized(ckt());
394 #define assert_ckt_up_to_date(ckt) { \
395 assert_ckt_initialized(ckt); \
396 assert((ckt)->CKTtime == CKT_BASE::_sim->_time0); \
397 assert((ckt)->CKTtemp == CKT_BASE::_sim->_temp_c + CONSTCtoK); \
400 void DEV_SPICE::update_ckt()const
402 assert_ckt_initialized(ckt());
403 ckt()->CKTgmin
= OPT::gmin
;
404 ckt()->CKTstat
= NULL
; // mark as not localized
405 ckt()->CKTtime
= _sim
->_time0
;
406 ckt()->CKTdelta
= NOT_VALID
; // localized
407 ckt()->CKTtemp
= _sim
->_temp_c
+ CONSTCtoK
;
409 ckt()->CKTomega
= _sim
->_jomega
.imag();
410 assert_ckt_up_to_date(ckt());
413 #define assert_ckt_localized(ckt) { \
414 assert_ckt_up_to_date(ckt); \
415 assert((ckt)->CKTstat); \
416 DEV_SPICE* d = reinterpret_cast<DEV_SPICE*>((ckt)->CKTstat);\
418 assert(dynamic_cast<DEV_SPICE*>(d)); \
419 assert((ckt)->CKTdelta == d->_dt); \
420 if (d->_dt == 0) {untested(); \
421 assert((ckt)->CKTag[0] == 0); \
422 assert((ckt)->CKTorder == 1); \
423 }else if (d->_time[1] != 0 && d->_method_a == mTRAP) { \
424 assert(conchk((ckt)->CKTag[0], 2 / d->_dt)); \
425 assert((ckt)->CKTorder == 2); \
427 assert(conchk((ckt)->CKTag[0], 1 / d->_dt)); \
428 assert((ckt)->CKTorder == 1); \
430 assert((ckt)->CKTag[0] == (ckt)->CKTag[0]); \
431 assert((ckt)->CKTrhs == d->_i0); \
432 assert((ckt)->CKTrhsOld == d->_v1); \
433 assert((ckt)->CKTirhs == d->_i1); \
434 assert((ckt)->CKTtimePoints == d->_time); \
437 void DEV_SPICE::localize_ckt()const
439 assert_ckt_up_to_date(ckt());
440 ckt()->CKTstat
= reinterpret_cast<STATistics
*>(const_cast<DEV_SPICE
*>(this));
441 assert(OPT::_keep_time_steps
<= 8);
442 for (int ii
=0; ii
<8; ++ii
) {
443 ckt()->CKTstates
[ii
] = _states
[ii
];
445 //assert(ckt()->CKTtime == _time[0]); //BUG// can fail in ac
446 ckt()->CKTdelta
= _dt
;
447 for (int ii
=0; ii
<OPT::_keep_time_steps
-1; ++ii
) {
448 ckt()->CKTdeltaOld
[ii
] = _time
[ii
] - _time
[ii
+1];
450 assert(_dt
== NOT_VALID
|| conchk(ckt()->CKTdelta
, ckt()->CKTdeltaOld
[0]));
452 //ckt()->CKTag[0] = tr_c_to_g(1, ckt()->CKTag[0]);
453 // defer fixing this -- GEAR not here
454 if (_dt
== 0) {untested();
455 ckt()->CKTag
[1] = ckt()->CKTag
[0] = 0;
457 }else if (_time
[1] != 0 && _method_a
== mTRAP
) {
458 ckt()->CKTag
[0] = 2 / _dt
;
462 ckt()->CKTag
[0] = 1 / _dt
;
463 ckt()->CKTag
[1] = -1 / _dt
;
466 ckt()->CKTrhs
= const_cast<double*>(_i0
);
467 ckt()->CKTrhsOld
= const_cast<double*>(_v1
);
468 ckt()->CKTirhs
= const_cast<double*>(_i1
);
470 ckt()->CKTtimePoints
= const_cast<double*>(_time
);
471 assert_ckt_localized(ckt());
474 #define assert_model_raw() { \
475 assert(_spice_model._gen.GENmodType == 0); \
476 assert(_spice_model._gen.GENnextModel == NULL); \
477 assert(_spice_model._gen.GENinstances == NULL); \
479 #define assert_model_unlocalized() { \
480 assert(_model->_spice_model._gen.GENinstances == NULL);\
481 assert(_spice_model); \
482 assert(_spice_model->_gen.GENmodType == 0); \
483 assert(_spice_model->_gen.GENnextModel == NULL); \
484 assert(_spice_model->_gen.GENinstances == NULL); \
485 assert(_spice_model->_gen.GENmodName); \
487 #define assert_model_localized() { \
488 assert(_spice_model); \
489 assert(_spice_model->_gen.GENmodType == 0); \
490 assert(_spice_model->_gen.GENnextModel == NULL); \
491 assert(_spice_model->_gen.GENinstances); \
492 assert(_spice_model->_gen.GENmodName); \
494 #define assert_instance() { \
495 assert(_spice_instance.GENnextInstance == NULL); \
496 assert(_spice_instance.GENname == NULL); \
498 /*--------------------------------------------------------------------------*/
499 /*--------------------------------------------------------------------------*/
500 /*--------------------------------------------------------------------------*/
504 IFVA(IFvalue
* v
, int t
) :_v(v
), _type(t
) {assert(v
);}
506 void operator=(const std::string
& s
)
508 CS
cmd(CS::_STRING
, s
);
510 int datatype
= _type
;
511 if (datatype
& IF_SET
) {
512 if (datatype
& IF_VECTOR
) {untested();
516 switch (datatype
& 0xff) {
517 case IF_FLAG
: _v
->iValue
= true; break;
518 case IF_INTEGER
: cmd
>> _v
->iValue
; break;
519 case IF_REAL
: cmd
>> _v
->rValue
; break;
520 case IF_COMPLEX
:untested();
524 case IF_NODE
:untested(); incomplete(); break;
527 //assert(!(_v->sValue));
528 //BUG//memory leak -- this is never deleted
529 _v
->sValue
= new char[s
.length()+1];
530 strcpy(_v
->sValue
, s
.c_str());
533 case IF_INSTANCE
: untested(); incomplete(); break;
534 case IF_PARSETREE
:untested(); incomplete(); break;
535 default: unreachable(); break;
541 /*--------------------------------------------------------------------------*/
542 /*--------------------------------------------------------------------------*/
543 MODEL_SPICE::MODEL_SPICE(const DEV_SPICE
* p
)
552 /*--------------------------------------------------------------------------*/
553 MODEL_SPICE::MODEL_SPICE(const MODEL_SPICE
& p
)
555 _spice_model(p
._spice_model
),
562 /*--------------------------------------------------------------------------*/
563 MODEL_SPICE::~MODEL_SPICE()
567 /*--------------------------------------------------------------------------*/
568 void MODEL_SPICE::Set_param_by_name(std::string Name
, std::string new_value
)
571 assert(info
.DEVpublic
.numModelParms
);
572 assert(info
.DEVpublic
.modelParms
);
573 assert(info
.DEVmodParam
);
575 int num_params
= *(info
.DEVpublic
.numModelParms
);
576 for (int i
= 0; i
< num_params
; ++i
) {
577 IFparm Parms
= info
.DEVpublic
.modelParms
[i
];
578 if (Name
== Parms
.keyword
) {
580 IFVA
v(&Value
, Parms
.dataType
);
582 int ok
= info
.DEVmodParam(Parms
.id
, &Value
, &_spice_model
._gen
);
588 if (Name
!= "level") {untested();
589 throw Exception_No_Match(Name
);
593 /*--------------------------------------------------------------------------*/
594 void MODEL_SPICE::set_param_by_name(std::string Name
, std::string Value
)
596 if (OPT::case_insensitive
) {
597 notstd::to_lower(&Name
);
600 _params
.set(Name
, Value
);
601 Set_param_by_name(Name
, to_string(_params
[Name
].e_val(1,scope())));
603 /*--------------------------------------------------------------------------*/
604 void MODEL_SPICE::precalc_first()
606 MODEL_CARD::precalc_first();
608 Set_param_by_name(_key
, "1");
610 // push down parameters into raw spice data
611 for (PARAM_LIST::iterator i
= _params
.begin(); i
!= _params
.end(); ++i
) {
612 if (i
->second
.has_hard_value()) {
614 Set_param_by_name(i
->first
, to_string(i
->second
.e_val(1,scope())));
615 }catch (Exception_No_Match
&) {
616 error(bTRACE
, long_label() + ": bad parameter: " + i
->first
+ ", ignoring\n");
625 int ok
= info
.DEVsetup(NULL
, &_spice_model
._gen
, ckt(), NULL
);
630 /*--------------------------------------------------------------------------*/
631 void MODEL_SPICE::set_dev_type(const std::string
& new_type
)
635 //_spice_model._gen.set_mod_name(short_label());
636 std::string s
= short_label();
637 char* p
= new char[s
.length()+1]; //BUG//memory leak
638 s
.copy(p
, std::string::npos
);
639 p
[s
.length()] = '\0';
640 _spice_model
._gen
.GENmodName
= p
;
643 if (OPT::case_insensitive
) {
644 notstd::to_lower(&_key
);
648 /*--------------------------------------------------------------------------*/
649 bool MODEL_SPICE::param_is_printable(int i
)const
651 assert(i
< MODEL_SPICE::param_count());
652 if (i
>= MODEL_CARD::param_count()) {
653 return _params
.is_printable(MODEL_SPICE::param_count() - 1 - i
);
655 return MODEL_CARD::param_is_printable(i
);
658 /*--------------------------------------------------------------------------*/
659 std::string
MODEL_SPICE::param_name(int i
)const
661 assert(i
< MODEL_SPICE::param_count());
662 if (i
>= MODEL_CARD::param_count()) {
663 return _params
.name(MODEL_SPICE::param_count() - 1 - i
);
665 return MODEL_CARD::param_name(i
);
668 /*--------------------------------------------------------------------------*/
669 std::string
MODEL_SPICE::param_name(int i
, int j
)const
671 assert(i
< MODEL_SPICE::param_count());
672 if (j
== 0) {untested();
673 return param_name(i
);
674 }else if (i
>= MODEL_CARD::param_count()) {untested();
677 return MODEL_CARD::param_name(i
);
680 /*--------------------------------------------------------------------------*/
681 std::string
MODEL_SPICE::param_value(int i
)const
683 assert(i
< MODEL_SPICE::param_count());
684 if (i
>= MODEL_CARD::param_count()) {
685 return _params
.value(MODEL_SPICE::param_count() - 1 - i
);
687 return MODEL_CARD::param_value(i
);
690 /*--------------------------------------------------------------------------*/
691 void MODEL_SPICE::set_param_by_index(int, std::string
&, int)
695 /*--------------------------------------------------------------------------*/
696 /*--------------------------------------------------------------------------*/
697 DEV_SPICE::DEV_SPICE()
713 attach_common(&Default_Params
);
714 std::fill_n(&_inst_space
, sizeof(INSTANCE
), '\0');
718 int* node
= spice_nodes();
719 for (int ii
= 0; ii
< matrix_nodes(); ++ii
) {
720 node
[ii
] = SPICE_INVALID_NODE
;
724 for (int ii
= 0; ii
< matrix_nodes(); ++ii
) {
725 assert(!(_n
[ii
].n_()));
728 for (int ii
= 0; ii
< matrix_nodes()+OFFSET
; ++ii
) {
729 _matrix
[ii
] = _matrix_core
[ii
];
733 assert(OPT::_keep_time_steps
<= 8);
734 for (int ii
=0; ii
<8; ++ii
) {
741 /*--------------------------------------------------------------------------*/
742 DEV_SPICE::DEV_SPICE(const DEV_SPICE
& p
)
745 _modelname(p
._modelname
),
747 _spice_model(p
._spice_model
),
755 _num_states(p
._num_states
),
756 _maxEqNum(p
._maxEqNum
)
761 int* node
= spice_nodes();
762 for (int ii
= 0; ii
< matrix_nodes(); ++ii
) {
763 assert(node
[ii
] == SPICE_INVALID_NODE
);
767 for (int ii
= 0; ii
< matrix_nodes(); ++ii
) {
771 for (int ii
= 0; ii
< matrix_nodes()+OFFSET
; ++ii
) {
772 _matrix
[ii
] = _matrix_core
[ii
];
776 assert(OPT::_keep_time_steps
<= 8);
777 for (int ii
=0; ii
<8; ++ii
) {
784 /*--------------------------------------------------------------------------*/
785 DEV_SPICE::~DEV_SPICE()
793 for (int ii
=0; ii
<OPT::_keep_time_steps
; ++ii
) {
795 delete [] _states
[ii
];
801 assert(OPT::_keep_time_steps
<= 8);
802 for (int ii
=0; ii
<8; ++ii
) {
803 assert(!_states
[ii
]);
806 assert(!_spice_model
);
809 /*--------------------------------------------------------------------------*/
810 void DEV_SPICE::set_dev_type(const std::string
& new_type
)
812 _modelname
= new_type
;
814 /*--------------------------------------------------------------------------*/
815 void DEV_SPICE::Set_param_by_name(std::string Name
, std::string new_value
)
818 assert(info
.DEVpublic
.numInstanceParms
);
819 assert(info
.DEVpublic
.instanceParms
);
820 assert(info
.DEVparam
);
822 int num_params
= *(info
.DEVpublic
.numInstanceParms
);
823 for (int i
= 0; i
< num_params
; ++i
) {
824 IFparm Parms
= info
.DEVpublic
.instanceParms
[i
];
825 if (Name
== Parms
.keyword
) {
826 Set_param_by_index(i
, new_value
, 0);
831 mutable_common()->COMMON_COMPONENT::Set_param_by_name(Name
, new_value
);
833 /*--------------------------------------------------------------------------*/
834 void DEV_SPICE::set_param_by_name(std::string Name
, std::string Value
)
836 if (OPT::case_insensitive
) {
837 notstd::to_lower(&Name
);
840 COMPONENT::set_param_by_name(Name
, Value
);
841 COMMON_SUBCKT
* c
= dynamic_cast<COMMON_SUBCKT
*>(mutable_common());
843 Set_param_by_name(Name
, to_string(c
->_params
[Name
].e_val(1,scope())));
845 /*--------------------------------------------------------------------------*/
846 void DEV_SPICE::Set_param_by_index(int i
, std::string
& new_value
, int offset
)
849 assert(info
.DEVpublic
.numInstanceParms
);
850 assert(info
.DEVpublic
.instanceParms
);
851 assert(info
.DEVparam
);
853 int num_params
= *(info
.DEVpublic
.numInstanceParms
);
854 if (i
< num_params
) {
855 IFparm Parms
= info
.DEVpublic
.instanceParms
[i
];
857 IFVA
v(&Value
, Parms
.dataType
);
860 int ok
= info
.DEVparam(ckt(), Parms
.id
, &Value
, &_spice_instance
, NULL
);
862 int ok
= info
.DEVparam(Parms
.id
, &Value
, &_spice_instance
, NULL
);
866 STORAGE::set_param_by_index(i
-num_params
, new_value
, offset
+num_params
);
870 /*--------------------------------------------------------------------------*/
871 void DEV_SPICE::expand()
874 assert(info
.DEVsetup
);
880 { //-------- fix up external nodes
881 int* node
= spice_nodes();
882 for (int ii
= 0; ii
< net_nodes(); ++ii
) {
883 node
[ii
] = ii
+OFFSET
;
885 if (UNCONNECTED_NODES
== uGROUND
) {
886 for (int ii
= net_nodes(); ii
< max_nodes(); ++ii
) {itested();
887 node
[ii
] = ii
+OFFSET
;
889 }else if (UNCONNECTED_NODES
== uFLOAT
) {
890 for (int ii
= net_nodes(); ii
< max_nodes(); ++ii
) {untested();
891 node
[ii
] = SPICE_UNCONNECTED_NODE
;
894 assert(UNCONNECTED_NODES
== uDISALLOW
);
895 assert(min_nodes() == max_nodes());
896 assert(net_nodes() == max_nodes());
898 ckt()->CKTmaxEqNum
= max_nodes();
900 for (int ii
= max_nodes(); ii
< matrix_nodes(); ++ii
) {
905 { //------- attach model, set up matrix pointers
906 _model
= dynamic_cast<const MODEL_SPICE
*>(find_model(_modelname
));
908 throw Exception_Model_Type_Mismatch(long_label(), _modelname
, DEVICE_TYPE
);
910 SMPmatrix
* matrix
= reinterpret_cast<SMPmatrix
*>(_matrix
);
913 _spice_instance
.GENmodPtr
= &(_model
->_spice_model
._gen
);
914 _spice_model
= &(_model
->_spice_model
);
915 SPICE_MODEL_DATA
spice_model_copy(*_spice_model
);
916 spice_model_copy
._gen
.GENinstances
= &_spice_instance
;
918 int ok
= info
.DEVsetup(matrix
, &(spice_model_copy
._gen
), ckt(), &_num_states
);
919 // memory pointer setup, and sets _num_states
920 // undesired side effects: sets values, messes up model
923 _maxEqNum
= ckt()->CKTmaxEqNum
;
924 trace1("expand", ckt()->CKTmaxEqNum
);
925 assert_model_unlocalized();
929 //-------- allocate state vectors
931 for (int ii
=0; ii
<OPT::_keep_time_steps
; ++ii
) {
932 assert(!_states
[ii
]);
933 _states
[ii
] = new double[_num_states
];
935 _states_1
= new double[_num_states
];
938 for (int ii
=0; ii
<OPT::_keep_time_steps
; ++ii
) {
940 std::fill_n(_states
[ii
], _num_states
, 0);
943 std::fill_n(_states_1
, _num_states
, 0);
945 //std::fill_n(_i1, matrix_nodes()+OFFSET, 0);
946 //std::fill_n(_v1, matrix_nodes()+OFFSET, 0);
948 //-------- fix up internal nodes
949 if (_sim
->is_first_expand()) {
950 int start_internal
= 0;
951 if (UNCONNECTED_NODES
== uGROUND
) {
952 for (int ii
= net_nodes(); ii
< max_nodes(); ++ii
) {itested();
953 _n
[ii
].set_to_ground(this);
955 start_internal
= max_nodes();
957 assert(UNCONNECTED_NODES
== uDISALLOW
|| UNCONNECTED_NODES
== uFLOAT
);
958 start_internal
= net_nodes();
960 assert(start_internal
!= 0);
962 int* node
= spice_nodes(); // treat as array
963 char fake_name
[] = "a";
964 for (int ii
= start_internal
; ii
< matrix_nodes(); ++ii
) {
965 if (node
[ii
] >= start_internal
+OFFSET
) {
966 // real internal node
967 _n
[ii
].new_model_node('.' + long_label() + '.' + fake_name
, this);
968 trace1("new int", node
[ii
]);
970 }else if (node
[ii
] >= 0+OFFSET
) {
971 // collapsed to an external node
972 _n
[ii
] = _n
[node
[ii
]-OFFSET
];
973 trace1("collapse", node
[ii
]);
977 trace1("not used", node
[ii
]);
978 assert(!_n
[ii
].n_());
983 for (int ii
= 0; ii
< matrix_nodes(); ++ii
) {
984 trace2((_n
[ii
].n_()) ? (_n
[ii
].n_()->short_label().c_str()) : ("NULL"), ii
, node
[ii
]);
987 // This could be one loop, but doing it this way gives more info.
988 for (int ii
= 0; ii
< min_nodes(); ++ii
) {
991 for (int ii
= min_nodes(); ii
< net_nodes(); ++ii
) {
994 for (int ii
= net_nodes(); ii
< max_nodes(); ++ii
) {itested();
995 //assert(_n[ii].n_());
997 for (int ii
= max_nodes(); ii
< matrix_nodes(); ++ii
) {
998 assert(_n
[ii
].n_() || !node
[ii
]);
1002 assert_model_unlocalized();
1005 /*--------------------------------------------------------------------------*/
1006 void DEV_SPICE::precalc_last()
1010 assert(info
.DEVsetup
);
1012 STORAGE::precalc_last();
1015 // push down parameters into spice data
1016 COMMON_SUBCKT
* c
= dynamic_cast<COMMON_SUBCKT
*>(mutable_common());
1018 for (PARAM_LIST::iterator i
= c
->_params
.begin(); i
!= c
->_params
.end(); ++i
) {
1019 if (i
->second
.has_hard_value()) {
1021 Set_param_by_name(i
->first
, to_string(i
->second
.e_val(1,scope())));
1022 }catch (Exception_No_Match
&) {
1023 error(bTRACE
, long_label() + ": bad parameter: " + i
->first
+ ", ignoring\n");
1029 int* node
= spice_nodes(); // treat as array //
1030 int node_stash
[MATRIX_NODES
]; //
1031 notstd::copy_n(node
, matrix_nodes(), node_stash
); // save the real nodes
1033 { //-------- fix up external nodes, again ........
1034 // put the originals back, so DEVsetup can mess them up the same as last time
1035 int* node
= spice_nodes();
1036 for (int ii
= 0; ii
< net_nodes(); ++ii
) {
1037 node
[ii
] = ii
+OFFSET
;
1039 if (UNCONNECTED_NODES
== uGROUND
) {
1040 for (int ii
= net_nodes(); ii
< max_nodes(); ++ii
) {itested();
1041 node
[ii
] = ii
+OFFSET
;
1043 }else if (UNCONNECTED_NODES
== uFLOAT
) {
1044 for (int ii
= net_nodes(); ii
< max_nodes(); ++ii
) {untested();
1045 node
[ii
] = SPICE_UNCONNECTED_NODE
;
1048 assert(UNCONNECTED_NODES
== uDISALLOW
);
1049 assert(min_nodes() == max_nodes());
1050 assert(net_nodes() == max_nodes());
1052 ckt()->CKTmaxEqNum
= max_nodes();
1054 for (int ii
= max_nodes(); ii
< matrix_nodes(); ++ii
) {
1060 SMPmatrix
* matrix
= reinterpret_cast<SMPmatrix
*>(_matrix
);
1061 int num_states_garbage
= 0;
1063 assert(_spice_model
== &(_model
->_spice_model
));
1064 SPICE_MODEL_DATA
spice_model_copy(*_spice_model
);
1065 spice_model_copy
._gen
.GENinstances
= &_spice_instance
;
1067 int ok
= info
.DEVsetup(matrix
, &(spice_model_copy
._gen
), ckt(), &num_states_garbage
);
1070 assert(num_states_garbage
== _num_states
);
1071 trace3("precalc", _maxEqNum
, ckt()->CKTmaxEqNum
, (_maxEqNum
== ckt()->CKTmaxEqNum
));
1072 assert(_maxEqNum
== ckt()->CKTmaxEqNum
);
1073 notstd::copy_n(node_stash
, matrix_nodes(), node
); // put back real nodes
1074 // hopefully, the matrix pointers are the same as last time!
1076 assert(!is_constant());
1077 assert_model_unlocalized();
1080 /*--------------------------------------------------------------------------*/
1081 void DEV_SPICE::internal_precalc()
1085 if (info
.DEVtemperature
) {
1088 assert_model_unlocalized();
1089 _spice_model
->_gen
.GENinstances
= &_spice_instance
;
1090 assert_model_localized();
1092 // ELEMENT::precalc(); .. don't call .. more analysis needed
1094 int ok
= info
.DEVtemperature(&(_spice_model
->_gen
), ckt());
1098 _spice_model
->_gen
.GENinstances
= NULL
;
1100 assert(!is_constant());
1104 assert_model_unlocalized();
1106 /*--------------------------------------------------------------------------*/
1107 void DEV_SPICE::tr_advance()
1109 STORAGE::tr_advance();
1112 double* t
= _states
[OPT::_keep_time_steps
-1];
1113 for (int ii
= OPT::_keep_time_steps
-1; ii
> 0; --ii
) {
1114 _states
[ii
] = _states
[ii
-1];
1117 notstd::copy_n(_states
[1], _num_states
, _states
[0]);
1119 /*--------------------------------------------------------------------------*/
1120 void DEV_SPICE::tr_regress()
1122 ELEMENT::tr_regress();
1125 /*--------------------------------------------------------------------------*/
1126 bool DEV_SPICE::tr_needs_eval()const
1128 if (is_q_for_eval()) {
1130 }else if (!converged()) {
1132 }else if (_sim
->is_advance_iteration()) {
1134 }else if (_time
[1] == 0) {
1135 //BUG// needed for ngspice jfet, but not for spice3f5 jfet
1138 int* node
= spice_nodes();
1139 // check the node voltages, reference to ground
1140 for (int ii
=0; ii
<matrix_nodes(); ++ii
) {
1141 if ((node
[ii
] != SPICE_INVALID_NODE
)
1142 && !conchk(_v1
[node
[ii
]], _n
[ii
].v0(), 0, OPT::reltol
*OPT::bypasstol
)) {
1147 // check the node voltages, reference to each other
1148 for (int ii
=0; ii
<matrix_nodes(); ++ii
) {
1149 for (int jj
=0; jj
<ii
; ++jj
) {
1150 if ((node
[ii
] != SPICE_INVALID_NODE
) && (node
[jj
] != SPICE_INVALID_NODE
)
1151 && !conchk((_v1
[node
[ii
]] - _v1
[node
[jj
]]),
1152 (_n
[ii
].v0() - _n
[jj
].v0()),
1153 0, OPT::reltol
*OPT::bypasstol
)) {
1162 /*--------------------------------------------------------------------------*/
1163 // MODEINITFLOAT = normal iteration
1164 // MODEINITPRED = 1st iter at a new time point
1165 // MODEINITTRAN = 1st iter at 1st time pt after initial DC
1166 // MODEINITFIX = like FLOAT, but honor options like "off"
1167 // MODEINITJCT = initial guess
1168 // MODEINITSMSIG = like FLOAT, but setup for small signal, don't load arrays
1169 /*--------------------------------------------------------------------------*/
1170 bool DEV_SPICE::do_tr()
1173 assert(info
.DEVload
);
1174 assert(_num_states
>= 0);
1178 assert_model_unlocalized();
1179 _spice_model
->_gen
.GENinstances
= &_spice_instance
;
1180 assert_model_localized();
1182 if (_sim
->analysis_is_tran_dynamic()) {
1183 if ((_time
[1] == 0) && _sim
->is_first_iteration()) {
1184 ckt()->CKTmode
= MODETRAN
| MODEINITTRAN
;
1186 ckt()->CKTmode
= MODETRAN
| MODEINITFLOAT
;
1189 if (_sim
->analysis_is_tran_static()) {
1190 ckt()->CKTmode
= MODETRANOP
;
1191 }else if (_sim
->analysis_is_tran_restore()) {
1192 ckt()->CKTmode
= MODETRAN
;
1193 }else if (_sim
->command_is_dc()) {
1194 ckt()->CKTmode
= MODEDCTRANCURVE
;
1195 }else if (_sim
->command_is_op()) {
1196 ckt()->CKTmode
= MODEDCOP
;
1197 }else{unreachable();
1200 if (_sim
->uic_now()) {
1201 ckt()->CKTmode
|= MODEINITFIX
;
1202 ckt()->CKTmode
|= MODEUIC
;
1203 }else if (_sim
->is_initial_step()) {
1204 ckt()->CKTmode
|= MODEINITJCT
;
1206 ckt()->CKTmode
|= MODEINITFLOAT
;
1211 int* node
= spice_nodes();
1212 assert(ckt()->CKTrhsOld
== _v1
);
1213 std::fill_n(_v1
, matrix_nodes()+OFFSET
, 0);
1214 for (int ii
= 0; ii
< matrix_nodes(); ++ii
) {
1215 if (node
[ii
] != SPICE_INVALID_NODE
) {
1216 _v1
[node
[ii
]] = _n
[ii
].v0();
1221 { // clear for copy out
1222 ckt()->CKTtroubleElt
= NULL
;
1223 ckt()->CKTnoncon
= 0;
1225 assert(ckt()->CKTrhs
== _i0
);
1226 std::fill_n(_i0
, matrix_nodes()+OFFSET
, 0);
1228 for (int ii
= 0; ii
< matrix_nodes()+OFFSET
; ++ii
) {
1229 for (int jj
= 0; jj
< matrix_nodes()+OFFSET
; ++jj
) {
1230 _matrix
[ii
][jj
].real(0.);
1235 // do the work -- it might also do convergence checking, might not
1237 info
.DEVload(&(_spice_model
->_gen
), ckt());
1239 // convergence check -- gnucap method
1240 set_converged(ckt()->CKTnoncon
== 0);
1241 for (int ii
= 0; ii
< _num_states
; ++ii
) {
1242 set_converged(converged() && conchk(_states
[0][ii
], _states_1
[ii
]));
1243 trace3("", ii
, _states_1
[ii
], _states
[0][ii
]);
1244 _states_1
[ii
] = _states
[0][ii
];
1246 for (int ii
= 0; converged() && ii
< matrix_nodes()+OFFSET
; ++ii
) {
1247 set_converged(conchk(_i0
[ii
], _i1
[ii
]));
1249 for (int ii
= 0; converged() && ii
< matrix_nodes()+OFFSET
; ++ii
) {
1250 for (int jj
= 0; converged() && jj
< matrix_nodes()+OFFSET
; ++jj
) {
1251 set_converged(conchk(_matrix
[ii
][jj
].real(), _matrix
[ii
][jj
].imag()));
1255 // convergence check -- Spice method
1256 // not sure if it is worth the effort
1257 if (converged() && info
.DEVconvTest
) {
1258 ckt()->CKTnoncon
= 0;
1259 ckt()->CKTrhs
= _v1
; // Spice overlaps _i0 with _v1 as CKTrhs
1260 info
.DEVconvTest(&(_spice_model
->_gen
), ckt());
1261 set_converged(ckt()->CKTnoncon
== 0);
1263 // either no separate test or already failed
1266 bool needs_load
= !converged();
1267 for (int ii
= 0; !needs_load
&& ii
< matrix_nodes()+OFFSET
; ++ii
) {
1268 needs_load
= !conchk(_i0
[ii
], _i1
[ii
], 0, OPT::reltol
*OPT::loadtol
);
1270 for (int ii
= 0; !needs_load
&& ii
< matrix_nodes()+OFFSET
; ++ii
) {
1271 for (int jj
= 0; !needs_load
&& jj
< matrix_nodes()+OFFSET
; ++jj
) {
1272 needs_load
= !conchk(_matrix
[ii
][jj
].real(), _matrix
[ii
][jj
].imag(),
1273 0, OPT::reltol
*OPT::loadtol
);
1282 assert_model_localized();
1283 _spice_model
->_gen
.GENinstances
= NULL
;
1284 assert_model_unlocalized();
1287 /*--------------------------------------------------------------------------*/
1288 void DEV_SPICE::tr_load()
1291 if (_loaditer
== _sim
->iteration_tag()) {untested();
1292 error(bDANGER
, long_label() + " internal error: double load\n");
1294 _loaditer
= _sim
->iteration_tag();
1297 int ihit
[MATRIX_NODES
+OFFSET
];
1298 int jhit
[MATRIX_NODES
+OFFSET
];
1300 std::fill_n(ihit
, matrix_nodes()+OFFSET
, 0);
1301 std::fill_n(jhit
, matrix_nodes()+OFFSET
, 0);
1303 int* node
= spice_nodes();
1304 for (int ii
= 0; ii
< matrix_nodes(); ++ii
) {
1306 if (ni
&& !ihit
[ni
]) {
1308 int nii
= ni
-OFFSET
;
1309 trace4("", ii
, ni
, _i0
[ni
], _i1
[ni
]);
1310 tr_load_source_point(_n
[ii
], &(_i0
[ni
]), &(_i1
[ni
]));
1311 for (int jj
= 0; jj
< matrix_nodes(); ++jj
) {
1313 if (nj
&& jhit
[nj
] != ni
) {
1315 int njj
= nj
-OFFSET
;
1317 trace2("", _matrix
[nii
][njj
].real(), _matrix
[nii
][njj
].imag());
1318 tr_load_point(_n
[ii
], _n
[jj
], &(_matrix
[nii
][njj
].real()), &(_matrix
[nii
][njj
].imag()));
1320 trace2("skip", jj
, nj
);
1324 trace2("=========skip", ii
, ni
);
1328 /*--------------------------------------------------------------------------*/
1329 void DEV_SPICE::tr_unload()
1330 {untested();incomplete();
1332 for (int ii
= 0; ii
< matrix_nodes(); ++ii
) {untested();
1333 for (int jj
= 0; jj
< matrix_nodes(); ++jj
) {untested();
1334 _matrix
[ii
][jj
].real() = 0;
1337 _sim
->mark_inc_mode_bad();
1340 /*--------------------------------------------------------------------------*/
1341 TIME_PAIR
DEV_SPICE::tr_review()
1343 // not calling STORAGE::tr_review();
1345 if (info
.DEVtrunc
) {
1350 assert_model_unlocalized();
1351 _spice_model
->_gen
.GENinstances
= &_spice_instance
;
1352 assert_model_localized();
1354 ckt()->CKTtroubleElt
= NULL
;
1355 double timestep
= NEVER
;
1357 info
.DEVtrunc(&(_spice_model
->_gen
), ckt(), ×tep
);
1360 _time_by
._error_estimate
= tr_review_check_and_convert(timestep
);
1361 _time_by
._event
= NEVER
;
1363 _spice_model
->_gen
.GENinstances
= NULL
;
1364 assert_model_unlocalized();
1367 return TIME_PAIR(NEVER
,NEVER
);
1370 /*--------------------------------------------------------------------------*/
1371 void DEV_SPICE::tr_accept()
1373 assert_model_unlocalized();
1374 _spice_model
->_gen
.GENinstances
= &_spice_instance
;
1375 assert_model_localized();
1377 //STORAGE::tr_accept(); // doesn't do anything
1379 if (_sim
->analysis_is_dcop() || _sim
->analysis_is_ac()) {
1383 assert(ckt()->CKTrhsOld
== _v1
);
1384 // _v1 already has correct values
1385 // _n[ii].v0() is not correct -- may have been cleared
1387 ckt()->CKTmode
= MODEINITSMSIG
;
1388 info
.DEVload(&(_spice_model
->_gen
), ckt());
1391 assert_model_localized();
1392 _spice_model
->_gen
.GENinstances
= NULL
;
1393 assert_model_unlocalized();
1395 /*--------------------------------------------------------------------------*/
1396 double DEV_SPICE::tr_probe_num(const std::string
& x
)const
1399 assert_ckt_up_to_date(ckt());
1402 // all of the "states" in state array
1403 int num_probe_states
= std::min(_num_states
, int(sizeof(state_names
)/sizeof(std::string
)));
1404 for (int ii
=0; ii
<num_probe_states
&& state_names
[ii
]!=""; ++ii
) {
1405 if (Umatch(x
, state_names
[ii
] + ' ')) {
1406 return _states
[0][ii
];
1412 // data that Spice has, through "ask"
1413 assert(info
.DEVpublic
.numInstanceParms
);
1414 assert(info
.DEVpublic
.instanceParms
);
1416 for (int ii
=0; ii
<(*(info
.DEVpublic
.numInstanceParms
)); ++ii
) {
1417 IFparm Parms
= info
.DEVpublic
.instanceParms
[ii
];
1418 int datatype
= Parms
.dataType
;
1419 if (datatype
& IF_ASK
&& Umatch(x
, std::string(Parms
.keyword
) + ' ')) {
1421 int ok
= info
.DEVask(ckt(), &_spice_instance
, Parms
.id
, &v
, NULL
);
1423 switch (datatype
& 0xff) {
1432 // make believe it is not a match
1434 break; // break switch, continue loop
1437 // match, but not useful here.
1443 // maybe there is more than one match, so continue loop
1446 // really not a match, keep looking
1450 // no DEVask .. can't do anything.
1452 return STORAGE::tr_probe_num(x
);
1454 /*--------------------------------------------------------------------------*/
1455 void DEV_SPICE::ac_begin()
1457 STORAGE::ac_begin();
1461 /*--------------------------------------------------------------------------*/
1462 void DEV_SPICE::do_ac()
1464 if (info
.DEVacLoad
|| info
.DEVpzLoad
) {
1466 assert(_num_states
>= 0);
1468 assert_model_unlocalized();
1469 _spice_model
->_gen
.GENinstances
= &_spice_instance
;
1470 assert_model_localized();
1473 ckt()->CKTmode
= MODEAC
;
1474 ckt()->CKTomega
= _sim
->_jomega
.imag();
1476 // clear for copy out
1477 ckt()->CKTtroubleElt
= NULL
;
1478 std::fill_n(_i0
, matrix_nodes()+OFFSET
, 0);
1479 std::fill_n(_i1
, matrix_nodes()+OFFSET
, 0);
1480 for (int ii
= 0; ii
< matrix_nodes()+OFFSET
; ++ii
) {
1481 for (int jj
= 0; jj
< matrix_nodes()+OFFSET
; ++jj
) {
1482 _matrix
[ii
][jj
] = 0;
1486 if (info
.DEVpzLoad
) {
1487 info
.DEVpzLoad(&(_spice_model
->_gen
), ckt(), reinterpret_cast<SPcomplex
*>(&_sim
->_jomega
));
1488 }else if (info
.DEVacLoad
) {
1489 info
.DEVacLoad(&(_spice_model
->_gen
), ckt());
1490 }else{unreachable();
1494 assert_model_localized();
1495 _spice_model
->_gen
.GENinstances
= NULL
;
1496 assert_model_unlocalized();
1498 // there is no acLoad function
1501 /*--------------------------------------------------------------------------*/
1502 void DEV_SPICE::ac_load()
1504 if (info
.DEVacLoad
) {
1505 assert_ckt_up_to_date(ckt());
1507 int ihit
[MATRIX_NODES
+OFFSET
];
1508 int jhit
[MATRIX_NODES
+OFFSET
];
1510 std::fill_n(ihit
, matrix_nodes()+OFFSET
, 0);
1511 std::fill_n(jhit
, matrix_nodes()+OFFSET
, 0);
1513 int* node
= spice_nodes();
1514 for (int ii
= 0; ii
< matrix_nodes(); ++ii
) {
1516 if (ni
&& !ihit
[ni
]) {
1518 int nii
= ni
-OFFSET
;
1519 trace3("", ii
, ni
, nii
);
1520 ac_load_source_point(_n
[ii
], COMPLEX(_i0
[ni
], _i1
[ni
]));
1521 for (int jj
= 0; jj
< matrix_nodes(); ++jj
) {
1523 if (nj
&& jhit
[nj
] != ni
) {
1525 int njj
= nj
-OFFSET
;
1526 trace3("", jj
, nj
, njj
);
1527 trace2("", _matrix
[nii
][njj
].real(), _matrix
[nii
][njj
].imag());
1528 ac_load_point(_n
[ii
], _n
[jj
], _matrix
[nii
][njj
]);
1530 trace2("skip", jj
, nj
);
1534 trace2("=========skip", ii
, ni
);
1538 // there is no acLoad function
1541 /*--------------------------------------------------------------------------*/
1542 /*--------------------------------------------------------------------------*/
1544 // needed to satisfy references. Supposedly unreachable. Stubs.
1545 char *errMsg
= NULL
;
1546 char *errRtn
= NULL
;
1547 char* tmalloc(int size
) {itested(); return static_cast<char*>(calloc(size
,1));}
1548 char* trealloc(char*, int) {untested();incomplete(); return NULL
;} //DEVnoise
1549 void txfree(char *ptr
) {
1550 if (ptr
) {itested();
1556 static class FT_CURCKT
: public circ
{
1561 ci_curTask
= reinterpret_cast<char*>(&junk
);
1562 //::ft_curckt = this;
1564 } stupid_ft_circ_pointer_to_pointer_hack
;
1566 circ
*ft_curckt
= &stupid_ft_circ_pointer_to_pointer_hack
;
1568 IFuid
CKTnodName(CKTcircuit
*,int) {incomplete();return IFuid();} //DEVsenPrint
1570 double D1i2F1(double, double, double) {incomplete(); return NOT_VALID
;} //DEVdisto
1571 double D1i3F1(double, double, double, double, double, double) {incomplete(); return NOT_VALID
;}
1572 double D1iF12(double, double, double, double, double) {incomplete(); return NOT_VALID
;}
1573 double D1i2F12(double, double, double, double, double, double, double, double, double,
1574 double) {incomplete(); return NOT_VALID
;}
1575 double D1n2F1(double, double, double) {incomplete(); return NOT_VALID
;}
1576 double D1n3F1(double, double, double, double, double, double) {incomplete(); return NOT_VALID
;}
1577 double D1nF12(double, double, double, double, double) {incomplete(); return NOT_VALID
;}
1578 double D1n2F12(double, double, double, double, double, double, double, double, double,
1579 double) {incomplete(); return NOT_VALID
;}
1580 double DFn2F1(double, double, double, double, double, double, double, double, double,
1581 double, double, double) {incomplete(); return NOT_VALID
;}
1582 double DFi2F1(double, double, double, double, double, double, double, double, double,
1583 double, double, double) {incomplete(); return NOT_VALID
;}
1584 double DFi3F1(double, double, double, double, double, double, double, double, double,
1585 double, double, double, double, double, double, double, double, double,
1586 double, double, double, double, double, double, double, double, double,
1587 double) {incomplete(); return NOT_VALID
;}
1588 double DFn3F1(double, double, double, double, double, double, double, double, double,
1589 double, double, double, double, double, double, double, double, double,
1590 double, double, double, double, double, double, double, double, double,
1591 double) {incomplete(); return NOT_VALID
;}
1592 double DFnF12(double, double, double, double, double, double, double, double,
1593 double, double, double, double, double, double, double, double,
1594 double, double) {incomplete(); return NOT_VALID
;}
1595 double DFiF12(double, double, double, double, double, double, double, double,
1596 double, double, double, double, double, double, double, double,
1597 double, double) {incomplete(); return NOT_VALID
;}
1598 struct DpassStr
; //DEVdisto
1599 double DFn2F12(DpassStr
*) {incomplete(); return NOT_VALID
;}
1600 double DFi2F12(DpassStr
*) {incomplete(); return NOT_VALID
;}
1602 void AtanDeriv(Dderivs
*, Dderivs
*) {incomplete();} //DEVdisto
1603 void CosDeriv(Dderivs
*, Dderivs
*) {incomplete();} //DEVdisto
1604 void CubeDeriv(Dderivs
*, Dderivs
*) {incomplete();} //DEVdisto
1605 void DivDeriv(Dderivs
*, Dderivs
*, Dderivs
*) {incomplete();} //DEVdisto
1606 void EqualDeriv(Dderivs
*, Dderivs
*) {incomplete();} //DEVdisto
1607 void ExpDeriv(Dderivs
*, Dderivs
*) {incomplete();} //DEVdisto
1608 void InvDeriv(Dderivs
*, Dderivs
*) {incomplete();} //DEVdisto
1609 void MultDeriv(Dderivs
*, Dderivs
*, Dderivs
*) {incomplete();} //DEVdisto
1610 void PlusDeriv(Dderivs
*, Dderivs
*, Dderivs
*) {incomplete();} //DEVdisto
1611 void PowDeriv(Dderivs
*, Dderivs
*, double) {incomplete();} //DEVdisto
1612 void SqrtDeriv(Dderivs
*, Dderivs
*) {incomplete();} //DEVdisto
1613 void TanDeriv(Dderivs
*, Dderivs
*) {incomplete();} //DEVdisto
1614 void TimesDeriv(Dderivs
*, Dderivs
*, double) {incomplete();} //DEVdisto
1616 double Nintegrate(double, double, double, GENERIC
*) {incomplete(); return NOT_VALID
;} //DEVnoise
1618 double Nintegrate(double, double, double, Ndata
*) {incomplete(); return NOT_VALID
;} //DEVnoise
1620 void NevalSrc(double*, double*, CKTcircuit
*, int, int, int, double) {incomplete();} //DEVnoise
1621 void NevalSrc2(double*, double*, CKTcircuit
*, int, int, int, double, double) {incomplete();}
1622 //------------------------------------------------
1623 // should be constants, but spice wants them to be variables.
1624 double CONSTroot2(sqrt(2.));
1625 double CONSTvt0(P_CELSIUS0
*P_K_Q
);
1626 double CONSTKoverQ(P_K_Q
);
1628 //------------------------------------------------
1632 IFsimulator
*ft_sim
;
1633 //------------------------------------------------
1634 //------------------------------------------------
1635 int IFerror(int flags
, char* format
, IFuid
* names
) /* output an error or warning message */
1637 static struct mesg
{
1641 { "Warning", ERR_WARNING
} ,
1642 { "Fatal error", ERR_FATAL
} ,
1643 { "Panic", ERR_PANIC
} ,
1644 { "Note", ERR_INFO
} ,
1649 char buf
[10000], *s
, *bptr
;
1652 for (m
= msgs
; m
->flag
; m
++) {
1653 if (flags
& m
->flag
) {
1654 error(bDANGER
, "%s: ", m
->string
);
1659 for (s
= format
, bptr
= buf
; *s
; s
++) {
1660 if (*s
== '%' && (s
== format
|| *(s
-1) != '%') && *(s
+1) == 's') {
1661 if (names
[nindex
]) {
1662 strcpy(bptr
, reinterpret_cast<char*>(names
[nindex
]));
1664 strcpy(bptr
, "(null)");
1666 bptr
+= strlen(bptr
);
1675 case ERR_WARNING
:error(bWARNING
,buf
); break;
1676 case ERR_FATAL
: error(bDANGER
, buf
); throw Exception("");
1677 case ERR_PANIC
: error(bDANGER
, buf
); throw Exception("");
1678 case ERR_INFO
: error(bTRACE
, buf
); break;
1679 default: error(bDANGER
, buf
); break;
1683 void internalerror(char *message
)
1685 error(bDANGER
, "internal error: %s\n", message
);
1689 int CKTinst2Node(void*, void*, int, CKTnode
**, IFuid
*)
1690 {untested();incomplete();
1695 static IFfrontEnd fe
= {
1696 NULL
, //int ((*IFnewUid)()); /* create a new UID in the circuit */ noise, urcsetup
1697 NULL
, //int ((*IFpauseTest)()); /* should we stop now? */ noisean.c only
1698 NULL
, //double ((*IFseconds)()); /* what time is it? */ bjtdisto unused ifdef only (unused)
1699 IFerror
, //int ((*IFerror)()); /* output an error or warning message */ temp, setup
1707 static IFfrontEnd fe
= {
1708 NULL
, //int ((*IFnewUid)()); /* create a new UID in the circuit */ noise, urcsetup
1709 NULL
, //int ((*IFdelUid)()); /* create a new UID in the circuit */ not used
1710 NULL
, //int ((*IFpauseTest)()); /* should we stop now? */ noisean.c only
1711 NULL
, //double ((*IFseconds)()); /* what time is it? */ bjtdisto unused ifdef only (unused)
1712 IFerror
, //int ((*IFerror)()); /* output an error or warning message */ temp, setup
1713 NULL
, //int ((*OUTpBeginPlot)()); /* start pointwise output plot */ noisean.c only
1714 NULL
, //int ((*OUTpData)()); /* data for pointwise plot */ noisean.c only
1715 NULL
, //int ((*OUTwBeginPlot)()); /* start windowed output plot */ not used
1716 NULL
, //int ((*OUTwReference)()); /* independent vector for windowed plot */ not used
1717 NULL
, //int ((*OUTwData)()); /* data for windowed plot */ not used
1718 NULL
, //int ((*OUTwEnd)()); /* signal end of windows */ not used
1719 NULL
, //int ((*OUTendPlot)()); /* end of plot */ not used
1720 NULL
, //int ((*OUTbeginDomain)()); /* start nested domain */ not used
1721 NULL
, //int ((*OUTendDomain)()); /* end nested domain */ not used
1722 NULL
//int ((*OUTattributes)()); /* specify output attributes of node */ noisean.c only
1725 IFfrontEnd
* SPfrontEnd
= &fe
;
1726 //------------------------------------------------
1727 //------------------------------------------------
1728 int CKTsetBreak(CKTcircuit
* ckt
, double time
)
1730 if (time
< ckt
->CKTminBreak
) {untested();
1731 ckt
->CKTminBreak
= time
;
1736 //------------------------------------------------
1737 void CKTterr(int qcap
, CKTcircuit
* ckt
,double *time_step
)
1739 assert_ckt_localized(ckt
);
1741 std::valarray
<FPOLY1
> q(OPT::_keep_time_steps
);
1743 for (int ii
= 0; ii
< OPT::_keep_time_steps
; ++ii
) {
1744 assert(ckt
->CKTstates
[ii
]);
1745 q
[ii
].x
= NOT_VALID
;
1746 q
[ii
].f0
= ckt
->CKTstates
[ii
][qcap
];
1747 q
[ii
].f1
= NOT_VALID
;
1750 DEV_SPICE
* d
= reinterpret_cast<DEV_SPICE
*>(ckt
->CKTstat
);
1752 assert(dynamic_cast<DEV_SPICE
*>(d
));
1754 *time_step
= std::min(d
->tr_review_trunc_error(&q
[0]), *time_step
);
1756 //------------------------------------------------
1757 int NIintegrate(CKTcircuit
* ckt
,double* geq
,double* ceq
,double cap
,int qcap
)
1758 { //-- used by DEVload (not DC)
1759 assert_ckt_localized(ckt
);
1762 if (ckt
->CKTorder
== 1) {
1765 assert(ckt
->CKTtimePoints
[1] != 0.);
1766 assert(ckt
->CKTorder
== 2);
1770 std::valarray
<FPOLY1
> q(OPT::_keep_time_steps
);
1771 std::valarray
<FPOLY1
> i(OPT::_keep_time_steps
);
1773 for (int ii
= 0; ii
< OPT::_keep_time_steps
; ++ii
) {
1774 assert(ckt
->CKTstates
[ii
]);
1775 q
[ii
].x
= NOT_VALID
;
1776 q
[ii
].f0
= ckt
->CKTstates
[ii
][qcap
];
1778 trace3("", ii
, q
[ii
].f0
, q
[ii
].f1
);
1779 i
[ii
].x
= NOT_VALID
;
1780 i
[ii
].f0
= ckt
->CKTstates
[ii
][qcap
+1];
1781 i
[ii
].f1
= q
[ii
].f1
* ckt
->CKTag
[0];
1782 trace3("", ii
, i
[ii
].f0
, i
[ii
].f1
);
1783 assert(q
[ii
].f0
== q
[ii
].f0
);
1784 assert(q
[ii
].f1
== q
[ii
].f1
);
1785 assert(i
[ii
].f0
== i
[ii
].f0
);
1786 assert(i
[ii
].f1
== i
[ii
].f1
);
1789 i
[0] = differentiate(&q
[0], &i
[0], ckt
->CKTtimePoints
, method
);
1790 assert(i
[0].f0
== i
[0].f0
);
1791 assert(i
[0].f1
== i
[0].f1
);
1792 trace2("", i
[0].f0
, i
[0].f1
);
1794 ckt
->CKTstates
[0][qcap
+1] = i
[0].f0
;
1796 assert(ckt
->CKTdelta
!= 0. || (ckt
->CKTag
[0] == 0. && i
[0].f0
== 0.));
1797 *ceq
= i
[0].f0
- q
[0].f0
* ckt
->CKTag
[0];
1799 assert(*ceq
== *ceq
);
1800 assert(*geq
== *geq
);
1801 trace2("", *ceq
, *geq
);
1804 //------------------------------------------------
1805 //------------------------------------------------
1806 int CKTmkVolt(CKTcircuit
* ckt
, CKTnode
** n
, IFuid
, char*)
1807 { // get a new node number. -- used by DEVsetup
1808 assert_ckt_initialized(ckt
);
1810 static CKTnode n_static
; // always used only on next line
1811 *n
= &n_static
; // so reuse static structure
1812 (*n
)->number
= ((ckt
->CKTmaxEqNum
)++)+OFFSET
;
1813 trace1(__FUNCTION__
, (*n
)->number
);
1814 // local number (- == internal) only number is used
1817 int CKTmkCur(CKTcircuit
* ckt
, CKTnode
** n
, IFuid i
, char* c
)
1819 return CKTmkVolt(ckt
, n
, i
, c
);
1821 //------------------------------------------------
1822 int CKTdltNNum(void*,int)
1823 {untested(); // complement to CKTmkVolt. -- used by DEVunsetup
1824 // deletes what was new in CKTmkVolt
1825 // Nothing, because of no alloc there.
1828 //------------------------------------------------
1829 //------------------------------------------------
1830 double* SMPmakeElt(SMPmatrix
* mm
, int r
, int c
)
1831 { // returns a pointer m[r][c] -- used by DEVsetup
1834 if (r
== 0 || c
== 0) {
1835 static double trash
;
1839 assert(r
>= 0+OFFSET
);
1840 assert(r
< MATRIX_NODES
+OFFSET
);
1841 assert(c
>= 0+OFFSET
);
1842 assert(c
< MATRIX_NODES
+OFFSET
);
1843 COMPLEX
** m
= reinterpret_cast<COMPLEX
**>(mm
);
1845 assert(m
[r
-OFFSET
]);
1846 return reinterpret_cast<double*>(&(m
[r
-OFFSET
][c
-OFFSET
]));
1849 //------------------------------------------------
1851 int IFnewUid(GENERIC
*,IFuid
*,IFuid
,char*,int,GENERIC
**) {incomplete(); return 0;}
1852 int INPpName(char*,IFvalue
*,GENERIC
*,int,GENERIC
*) {incomplete(); return 0;}
1853 char *INPdevErr(char *) {incomplete(); return NULL
;}
1854 char *INPerror(int) {incomplete(); return NULL
;}
1855 spREAL
*spGetElement(char* s
, int r
, int c
) {return SMPmakeElt(s
,r
,c
);}
1856 char *INPerrCat(char *, char *) {incomplete(); return NULL
;}
1857 int INPgndInsert(GENERIC
*,char**,INPtables
*,GENERIC
**) {incomplete(); return 0;}
1858 char * INPdevParse(char**,GENERIC
*,int,GENERIC
*,double*,int*,INPtables
*) {incomplete(); return NULL
;}
1859 char *INPgetMod(GENERIC
*,char*,INPmodel
**,INPtables
*) {incomplete(); return NULL
;}
1860 int INPgetTok(char**,char**,int) {incomplete(); return 0;}
1861 int INPlookMod(char*) {incomplete(); return 0;}
1862 int INPtermInsert(GENERIC
*,char**,INPtables
*,GENERIC
**) {incomplete(); return 0;}
1863 int INPinsert(char**,INPtables
*) {incomplete(); return 0;}
1864 char *copy(char*) {incomplete(); return NULL
;}
1865 int NIsum(CKTcircuit
*,double*,int) {incomplete(); return 0;}
1866 double INPevaluate(char**,int*,int) {incomplete(); return NOT_VALID
;}
1867 IFvalue
*INPgetValue(GENERIC
*,char**,int,INPtables
*) {incomplete(); return NULL
;}
1870 /*--------------------------------------------------------------------------*/
1871 /*--------------------------------------------------------------------------*/
1872 // Verify that the layout of complex is as Spice assumes.
1873 // This is not guaranteed by the standard, but is believed to always be true.
1874 static struct COMPLEX_TEST
{
1878 double* prx
= &x
.real();
1879 double* pix
= &x
.imag();
1880 assert(reinterpret_cast<void*>(prx
) == reinterpret_cast<void*>(px
));
1881 assert(reinterpret_cast<void*>(pix
-1) == reinterpret_cast<void*>(px
));
1886 /*--------------------------------------------------------------------------*/
1887 /*--------------------------------------------------------------------------*/
1888 int MODEL_SPICE::_count
= -1;
1889 int DEV_SPICE::_count
= -1;
1891 static DEV_SPICE p0
;
1892 static DISPATCHER
<CARD
>::INSTALL
1893 d0(&device_dispatcher
, std::string(SPICE_LETTER
) + "|" + DEVICE_TYPE
, &p0
);
1895 static MODEL_SPICE
p1(&p0
);
1896 static DISPATCHER
<MODEL_CARD
>::INSTALL
1897 d1(&model_dispatcher
, MODEL_TYPE
, &p1
);
1898 /*--------------------------------------------------------------------------*/
1899 /*--------------------------------------------------------------------------*/
1900 // vim:ts=8:sw=2:noet: