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 /*--------------------------------------------------------------------------*/
62 //#include "globals.h"
64 #include "e_paramlist.h"
69 /*--------------------------------------------------------------------------*/
70 // customization -- must be last
72 #if !defined(UNCONNECTED_NODES)
73 #define UNCONNECTED_NODES uDISALLOW
74 #if (MIN_NET_NODES != MAX_NET_NODES)
75 #error "What should I do with the unconnected nodes?"
78 #if !defined(VALUE_NAME)
79 #define VALUE_NAME "#"
81 #if !defined(TAIL_SIZE)
84 #if !defined(IS_VALID)
85 #define IS_VALID {return MODEL_CARD::is_valid(d);}
87 /*--------------------------------------------------------------------------*/
89 const int SPICE_INVALID_NODE
= 0;
90 const uint_t SPICE_UNCONNECTED_NODE
= -2;
92 enum {uGROUND
=1, uFLOAT
=2, uDISALLOW
=3};
93 const uint_t MATRIX_NODES
= (MAX_NET_NODES
+ INTERNAL_NODES
);
96 static COMMON_PARAMLIST
Default_Params(CC_STATIC
);
97 /*--------------------------------------------------------------------------*/
98 /* function mapping: see devdefs.h
99 * DEVparam DEV_SPICE::parse_spice
100 * DEVmodParam MODEL_SPICE::parse_params
101 * DEVload DEV_SPICE::do_tr
102 * DEVsetup MODEL_SPICE::precalc, DEV_SPICE::expand
103 * DEVunsetup not used -- spice baggage -- just zeros some nodes
104 * DEVpzSetup not used -- pole-zero
105 * DEVtemperature DEV_SPICE::internal_precalc
106 * DEVtrunc DEV_SPICE::tr_review
107 * DEVfindBranch not used -- current probes for current controlled source
108 * DEVacLoad DEV_SPICE::do_ac
109 * DEVaccept not used -- sets break points //BUG// need for: isrc, ltra, tra, vsrc, cpl, txl
110 * DEVdestroy not used -- spice baggage -- deletes a list
111 * DEVmodDelete not used -- spice baggage -- delete one model
112 * DEVdelete not used -- spice baggage -- delete one instance
113 * DEVsetic not used -- "getic" -- initial conditions //BUG// need this
114 * DEVask DEV_SPICE::print_args, DEV_SPICE::tr_probe_num
115 * DEVmodAsk MODEL_SPICE::print_params, MODEL_SPICE::print_calculated
116 * DEVpzLoad not used -- pole zero -- should use for AC
117 * DEVconvTest DEV_SPICE::do_tr
118 * DEVsenSetup not used -- sensitivity
119 * DEVsenLoad not used -- sensitivity
120 * DEVsenUpdate not used -- sensitivity
121 * DEVsenAcLoad not used -- sensitivity
122 * DEVsenPrint not used -- sensitivity
123 * DEVsenTrunc not used -- sensitivity
124 * DEVdisto not used -- distortion
125 * DEVnoise not used -- noise
127 /*--------------------------------------------------------------------------*/
128 union SPICE_MODEL_DATA
{
129 mutable GENmodel _gen
;// generic -- use this one
130 MODEL _full
; // determines size
131 char _space
; // char pointer for fill_n
134 std::fill_n(&_space
, sizeof(MODEL
), '\0');
136 SPICE_MODEL_DATA(const SPICE_MODEL_DATA
& p
)
140 /*--------------------------------------------------------------------------*/
141 class MODEL_SPICE
: public MODEL_CARD
{
144 static CKTcircuit _ckt
;
146 SPICE_MODEL_DATA _spice_model
;
151 explicit MODEL_SPICE(const MODEL_SPICE
& p
); // for clone
153 explicit MODEL_SPICE(const DEV_SPICE
* p
); // for dispatcher
155 public: // override virtual
156 MODEL_CARD
* clone()const {return new MODEL_SPICE(*this);}
157 bool is_valid(const COMPONENT
* d
)const IS_VALID
159 void precalc_first();
162 void set_dev_type(const std::string
& nt
);
163 std::string
dev_type()const { return _key
;}
165 public: // parameters
166 bool param_is_printable(int)const;
167 std::string
param_name(int)const;
168 std::string
param_name(int i
, int j
)const;
169 std::string
param_value(int)const;
170 void set_param_by_name(std::string Name
, std::string Value
);
171 void set_param_by_index(int, std::string
&, int);
172 int param_count_dont_print()const {return MODEL_CARD::param_count();}
173 int param_count()const { return (static_cast<int>(_params
.size()) + MODEL_CARD::param_count());}
175 void Set_param_by_name(std::string Name
, std::string Value
);
177 public: // not virtual
178 static int count() {untested(); return _count
;}
179 static CKTcircuit
* ckt() {return &_ckt
;}
180 static void init_ckt();
182 /*--------------------------------------------------------------------------*/
183 class DEV_SPICE
: public STORAGE
{
189 mutable GENinstance _spice_instance
;
193 std::string _modelname
;
194 const MODEL_SPICE
* _model
;
195 const SPICE_MODEL_DATA
* _spice_model
;
196 node_t _nodes
[MATRIX_NODES
];
197 COMPLEX
* _matrix
[MATRIX_NODES
+OFFSET
]; // For tran, real is now, imag is saved.
198 COMPLEX _matrix_core
[MATRIX_NODES
+OFFSET
][MATRIX_NODES
+OFFSET
];
200 double _i0
[MATRIX_NODES
+OFFSET
]; // right side - current offsets or ac real part
201 double _i1
[MATRIX_NODES
+OFFSET
]; // right side - saved ......... or ac imag part
202 double _v1
[MATRIX_NODES
+OFFSET
]; // input voltages
203 double* (_states
[8]); // array of 8 pointers
208 explicit DEV_SPICE(const DEV_SPICE
& p
);
210 explicit DEV_SPICE();
212 protected: // override virtual
213 char id_letter()const {untested();return SPICE_LETTER
[0];}
214 bool print_type_in_spice()const {return true;}
215 std::string
value_name()const {return VALUE_NAME
;}
216 uint_t
max_nodes()const {return MAX_NET_NODES
;}
217 uint_t
min_nodes()const {return MIN_NET_NODES
;}
218 uint_t
matrix_nodes()const {return MATRIX_NODES
;}
219 uint_t
net_nodes()const {return _net_nodes
;}
220 uint_t
int_nodes()const {return INTERNAL_NODES
;}
221 CARD
* clone()const {return new DEV_SPICE(*this);}
222 //void precalc_first(); //ELEMENT
225 //void map_nodes(); //ELEMENT
226 void internal_precalc();
228 void tr_iwant_matrix() {tr_iwant_matrix_extended();}
229 void tr_begin() {STORAGE::tr_begin(); internal_precalc();}
230 void tr_restore() {STORAGE::tr_restore(); internal_precalc();}
231 void dc_advance() {STORAGE::dc_advance(); internal_precalc();}
234 bool tr_needs_eval()const;
235 //void tr_queue_eval(); //ELEMENT
238 TIME_PAIR
tr_review();
241 hp_float_t
tr_involts()const {unreachable();return NOT_VALID
;}
242 //double tr_input()const //ELEMENT
243 hp_float_t
tr_involts_limited()const {unreachable();return NOT_VALID
;}
244 //double tr_input_limited()const //ELEMENT
245 double tr_amps()const {itested();return NOT_VALID
;}
246 double tr_probe_num(const std::string
&)const;
248 void ac_iwant_matrix() {ac_iwant_matrix_extended();}
252 COMPLEX
ac_involts()const {unreachable();return NOT_VALID
;}
253 COMPLEX
ac_amps()const {unreachable();return NOT_VALID
;}
254 XPROBE
ac_probe_ext(const std::string
&)const {itested(); return XPROBE(NOT_VALID
, mtNONE
);}
255 uint_t
tail_size()const {return TAIL_SIZE
;}
257 void set_dev_type(const std::string
& nt
);
258 std::string
dev_type()const {return _modelname
;}
260 // bool port_exists(int i)const //COMPONENT
261 std::string
port_name(uint_t i
)const {itested();
262 assert(i
< MAX_NET_NODES
);
263 return port_names
[i
];
265 // const std::string& port_value(int i)const; //COMPONENT
266 //void set_port_by_name(std::string& name, std::string& value);
267 //void set_port_by_index(int index, std::string& value);
268 private: // parameters
269 //bool Param_exists(int i)const; // {return Param_name(i) != "";}
270 //bool Param_is_printable(int)const;
271 //std::string Param_name(int)const;
272 //std::string Param_name(int i, int j)const {return STORAGE::Param_name(i, j);}
273 //std::string Param_value(int)const;
274 void set_param_by_name(std::string Name
, std::string Value
);
275 void Set_param_by_name(std::string Name
, std::string Value
);
276 void Set_param_by_index(int, std::string
&, int);
277 int param_count_dont_print()const {return common()->COMMON_COMPONENT::param_count();}
279 CKTcircuit
* ckt()const {return MODEL_SPICE::ckt();}
280 void init_ckt() {MODEL_SPICE::init_ckt();}
281 void update_ckt()const;
282 void localize_ckt()const;
283 int* spice_nodes()const {return &(_spice_instance
.GENnode1
);}
289 /*--------------------------------------------------------------------------*/
290 /*--------------------------------------------------------------------------*/
291 CKTcircuit
MODEL_SPICE::_ckt
;
293 * used as intended, copy-out, matters: CKTnoncon, CKTtroubleElt
295 * used as intended, func specific: CKTmode, CKTcurrentAnalysis
297 * used as intended, localized, matters: CKTstates, CKTdelta, CKTdeltaOld,
298 * CKTag(broken), CKTorder(broken), CKTrhs, CKTrhsOld, CKTirhs,
299 * CKTtimePoints(broken,ltra?)
301 * used as intended, updated, matters: CKTtime, CKTtemp, CKTomega
303 * used as intended, constant, matters: CKTnomTemp, CKTabstol,
304 * CKTreltol, CKTvoltTol, CKTgmin, CKTsrcFact(broken),
305 * CKTdefaultMosL, CKTdefaultMosW, CKTdefaultMosAD, CKTdefaultMosAS,
307 * used almost as intended, matters, probably ok:
308 * CKTbypass: false to disable
309 * CKTintegrateMethod: used only by Jspice -- set to 0 to disable
310 * CKTsenInfo: used by sens, NULL to disable
311 * CKTfixLimit(mos1236): 1 for Spice-2 mode
312 * CKTbadMos3(mos3): false for Spice-3 mode
314 * misused: (not used by spice devs, use to pass gnucap stuff through)
315 * CKTstat: the device (type DEV_SPICE)
316 * CKTmaxEqNum: use as counter for internal nodes, pass to CKTmkVolt
318 * need to handle (ind): CKThead(ind,load)
319 * need to handle (cpl,txl): CKTnodes(cpl,txl),
321 * need to handle ([iv]src):
322 * CKTbreak([iv]src,accept), CKTfinalTime([iv]src,load), CKTstep([iv]src,load),
324 * need to handle (ltra):
325 * CKTminBreak(ltra,tra,accept), CKTtrtol(ltra,trunc),
326 * CKTmaxStep(ltra,temp), CKTtimeListSize(ltra,Jspice,accept),
327 * CKTtimeIndex(ltra), CKTsizeIncr(ltra), CKTtryToCompact(ltra)
329 * used by "predictor": CKTagp, CKTpred, CKTsols
330 * used by "sens": CKTirhsOld, CKTrhsOp
331 * used by noise&distortion: CKTcurJob
333 * not used: CKTvt, CKTmaxOrder, CKTmatrix, CKTniState, CKTrhsSpare,
334 * CKTirhsSpare, CKTsenRhs, CKTseniRhs, CKTlastNode, CKTnumStates,
335 * CKTdcMaxIter, CKTdcTrcvMaxIter, CKTtranMaxIter, CKTbreakSize, CKTsaveDelta,
336 * CKTbreaks, CKTpivotAbsTol, CKTpivotRelTol, CKTchgtol, CKTlteReltol, CKTlteAbstol,
337 * CKTdelmin, CKTinitTime, CKTdiagGmin, CKTnumSrcSteps, CKTnumGminSteps, CKThadNodeset,
338 * CKTnoOpIter, CKTisSetup, CKTdeltaList, CKTkeepOpInfo, CKTtroubleNode
340 #define assert_ckt_initialized(ckt) { \
342 assert((ckt)->CKTnomTemp == OPT::tnom_c + CONSTCtoK); \
343 assert(((ckt)->CKTcurrentAnalysis == DOING_DCOP) == CKT_BASE::_sim->command_is_op()); \
344 assert(((ckt)->CKTcurrentAnalysis == DOING_TRCV) == CKT_BASE::_sim->command_is_dc()); \
345 assert(((ckt)->CKTcurrentAnalysis == DOING_AC ) == CKT_BASE::_sim->analysis_is_ac()); \
346 assert(((ckt)->CKTcurrentAnalysis == DOING_TRAN) == CKT_BASE::_sim->analysis_is_tran()); \
347 assert((ckt)->CKTbypass == false); \
348 assert((ckt)->CKTabstol == OPT::abstol); \
349 assert((ckt)->CKTreltol == OPT::reltol); \
350 assert((ckt)->CKTvoltTol == OPT::vntol); \
351 assert((ckt)->CKTsrcFact == 1.); \
352 assert((ckt)->CKTdefaultMosL == OPT::defl); \
353 assert((ckt)->CKTdefaultMosW == OPT::defw); \
354 assert((ckt)->CKTdefaultMosAD == OPT::defad); \
355 assert((ckt)->CKTdefaultMosAS == OPT::defas); \
358 void MODEL_SPICE::init_ckt()
361 ckt()->CKTtime
= _sim
->_time0
;
362 ckt()->CKTtemp
= _sim
->_temp_c
+ CONSTCtoK
; //manage by update
363 ckt()->CKTnomTemp
= OPT::tnom_c
+ CONSTCtoK
;
364 ckt()->CKTintegrateMethod
= 0; // disable
365 if (_sim
->command_is_op()) {
366 ckt()->CKTcurrentAnalysis
= DOING_DCOP
;
367 }else if (_sim
->command_is_dc()) {
368 ckt()->CKTcurrentAnalysis
= DOING_TRCV
;
369 }else if (_sim
->command_is_ac()) {
370 ckt()->CKTcurrentAnalysis
= DOING_AC
;
371 }else if (_sim
->analysis_is_tran()) {
372 ckt()->CKTcurrentAnalysis
= DOING_TRAN
;
373 }else{ // probably probe
374 ckt()->CKTcurrentAnalysis
= 0;
376 ckt()->CKTmode
= 0; // wrong but safe
377 ckt()->CKTbypass
= false; // manage this elsewhere
378 ckt()->CKTabstol
= OPT::abstol
;
379 ckt()->CKTreltol
= OPT::reltol
;
380 ckt()->CKTvoltTol
= OPT::vntol
;
381 ckt()->CKTgmin
= OPT::gmin
;
382 ckt()->CKTsrcFact
= 1.; // source stepping kluge
383 ckt()->CKTdefaultMosL
= OPT::defl
;
384 ckt()->CKTdefaultMosW
= OPT::defw
;
385 ckt()->CKTdefaultMosAD
= OPT::defad
;
386 ckt()->CKTdefaultMosAS
= OPT::defas
;
387 ckt()->CKTfixLimit
= false; // limiting kluge 1 == spice2
389 ckt()->CKTbadMos3
= false; // 1 = spice2 compat
390 ckt()->CKTsenInfo
= NULL
; // used as flag to print sens info
393 ckt()->CKTdefaultMosM
= 1.;
394 ckt()->CKTcopyNodesets
= false;
396 assert_ckt_initialized(ckt());
399 #define assert_ckt_up_to_date(ckt) { \
400 assert_ckt_initialized(ckt); \
401 assert((ckt)->CKTtime == CKT_BASE::_sim->_time0); \
402 assert((ckt)->CKTtemp == CKT_BASE::_sim->_temp_c + CONSTCtoK); \
405 void DEV_SPICE::update_ckt()const
407 assert_ckt_initialized(ckt());
408 ckt()->CKTgmin
= OPT::gmin
;
409 ckt()->CKTstat
= NULL
; // mark as not localized
410 ckt()->CKTtime
= _sim
->_time0
;
411 ckt()->CKTdelta
= NOT_VALID
; // localized
412 ckt()->CKTtemp
= _sim
->_temp_c
+ CONSTCtoK
;
414 ckt()->CKTomega
= _sim
->_jomega
.imag();
415 assert_ckt_up_to_date(ckt());
418 #define assert_ckt_localized(ckt) { \
419 assert_ckt_up_to_date(ckt); \
420 assert((ckt)->CKTstat); \
421 DEV_SPICE* d = reinterpret_cast<DEV_SPICE*>((ckt)->CKTstat);\
423 assert(dynamic_cast<DEV_SPICE*>(d)); \
424 assert((ckt)->CKTdelta == d->_dt); \
425 if (d->_dt == 0) {untested(); \
426 assert((ckt)->CKTag[0] == 0); \
427 assert((ckt)->CKTorder == 1); \
428 }else if (d->_time[1] != 0 && d->_method_a == mTRAP) { \
429 assert(conchk((ckt)->CKTag[0], 2 / d->_dt)); \
430 assert((ckt)->CKTorder == 2); \
432 assert(conchk((ckt)->CKTag[0], 1 / d->_dt)); \
433 assert((ckt)->CKTorder == 1); \
435 assert((ckt)->CKTag[0] == (ckt)->CKTag[0]); \
436 assert((ckt)->CKTrhs == d->_i0); \
437 assert((ckt)->CKTrhsOld == d->_v1); \
438 assert((ckt)->CKTirhs == d->_i1); \
439 assert((ckt)->CKTtimePoints == d->_time); \
442 void DEV_SPICE::localize_ckt()const
444 assert_ckt_up_to_date(ckt());
445 ckt()->CKTstat
= reinterpret_cast<STATistics
*>(const_cast<DEV_SPICE
*>(this));
446 assert(OPT::_keep_time_steps
<= 8);
447 for (uint_t ii
=0; ii
<8; ++ii
) {
448 ckt()->CKTstates
[ii
] = _states
[ii
];
450 //assert(ckt()->CKTtime == _time[0]); //BUG// can fail in ac
451 ckt()->CKTdelta
= _dt
;
452 for (uint_t ii
=0; ii
<OPT::_keep_time_steps
-1; ++ii
) {
453 ckt()->CKTdeltaOld
[ii
] = _time
[ii
] - _time
[ii
+1];
455 assert(_dt
== NOT_VALID
|| conchk(ckt()->CKTdelta
, ckt()->CKTdeltaOld
[0]));
457 //ckt()->CKTag[0] = tr_c_to_g(1, ckt()->CKTag[0]);
458 // defer fixing this -- GEAR not here
459 if (_dt
== 0) {untested();
460 ckt()->CKTag
[1] = ckt()->CKTag
[0] = 0;
462 }else if (_time
[1] != 0 && _method_a
== mTRAP
) {
463 ckt()->CKTag
[0] = 2 / _dt
;
467 ckt()->CKTag
[0] = 1 / _dt
;
468 ckt()->CKTag
[1] = -1 / _dt
;
471 ckt()->CKTrhs
= const_cast<double*>(_i0
);
472 ckt()->CKTrhsOld
= const_cast<double*>(_v1
);
473 ckt()->CKTirhs
= const_cast<double*>(_i1
);
475 ckt()->CKTtimePoints
= const_cast<double*>(_time
);
476 assert_ckt_localized(ckt());
479 #define assert_model_raw() { \
480 assert(_spice_model._gen.GENmodType == 0); \
481 assert(_spice_model._gen.GENnextModel == NULL); \
482 assert(_spice_model._gen.GENinstances == NULL); \
484 #define assert_model_unlocalized() { \
485 assert(_model->_spice_model._gen.GENinstances == NULL);\
486 assert(_spice_model); \
487 assert(_spice_model->_gen.GENmodType == 0); \
488 assert(_spice_model->_gen.GENnextModel == NULL); \
489 assert(_spice_model->_gen.GENinstances == NULL); \
490 assert(_spice_model->_gen.GENmodName); \
492 #define assert_model_localized() { \
493 assert(_spice_model); \
494 assert(_spice_model->_gen.GENmodType == 0); \
495 assert(_spice_model->_gen.GENnextModel == NULL); \
496 assert(_spice_model->_gen.GENinstances); \
497 assert(_spice_model->_gen.GENmodName); \
499 #define assert_instance() { \
500 assert(_spice_instance.GENnextInstance == NULL); \
501 assert(_spice_instance.GENname == NULL); \
503 /*--------------------------------------------------------------------------*/
504 /*--------------------------------------------------------------------------*/
505 /*--------------------------------------------------------------------------*/
509 IFVA(IFvalue
* v
, int t
) :_v(v
), _type(t
) {assert(v
);}
511 void operator=(const std::string
& s
)
513 CS
cmd(CS::_STRING
, s
);
515 int datatype
= _type
;
516 if (datatype
& IF_SET
) {
517 if (datatype
& IF_VECTOR
) {untested();
521 switch (datatype
& 0xff) {
522 case IF_FLAG
: _v
->iValue
= true; break;
523 case IF_INTEGER
: cmd
>> _v
->iValue
; break;
524 case IF_REAL
: cmd
>> _v
->rValue
; break;
525 case IF_COMPLEX
:untested();
529 case IF_NODE
:untested(); incomplete(); break;
532 //assert(!(_v->sValue));
533 //BUG//memory leak -- this is never deleted
534 _v
->sValue
= new char[s
.length()+1];
535 strcpy(_v
->sValue
, s
.c_str());
538 case IF_INSTANCE
: untested(); incomplete(); break;
539 case IF_PARSETREE
:untested(); incomplete(); break;
540 default: unreachable(); break;
546 /*--------------------------------------------------------------------------*/
547 /*--------------------------------------------------------------------------*/
548 MODEL_SPICE::MODEL_SPICE(const DEV_SPICE
* p
)
557 /*--------------------------------------------------------------------------*/
558 MODEL_SPICE::MODEL_SPICE(const MODEL_SPICE
& p
)
560 _spice_model(p
._spice_model
),
567 /*--------------------------------------------------------------------------*/
568 MODEL_SPICE::~MODEL_SPICE()
572 /*--------------------------------------------------------------------------*/
573 void MODEL_SPICE::Set_param_by_name(std::string Name
, std::string new_value
)
576 assert(info
.DEVpublic
.numModelParms
);
577 assert(info
.DEVpublic
.modelParms
);
578 assert(info
.DEVmodParam
);
580 int num_params
= *(info
.DEVpublic
.numModelParms
);
581 for (int i
= 0; i
< num_params
; ++i
) {
582 IFparm Parms
= info
.DEVpublic
.modelParms
[i
];
583 if (Name
== Parms
.keyword
) {
585 IFVA
v(&Value
, Parms
.dataType
);
587 int ok
= info
.DEVmodParam(Parms
.id
, &Value
, &_spice_model
._gen
);
593 if (Name
!= "level") {
594 throw Exception_No_Match(Name
);
598 /*--------------------------------------------------------------------------*/
599 void MODEL_SPICE::set_param_by_name(std::string Name
, std::string Value
)
601 if (OPT::case_insensitive
) {
602 notstd::to_lower(&Name
);
605 _params
.set(Name
, Value
);
606 Set_param_by_name(Name
, ::to_string(_params
[Name
].e_val(1,scope())));
609 /*--------------------------------------------------------------------------*/
610 void MODEL_SPICE::precalc_first()
612 MODEL_CARD::precalc_first();
614 Set_param_by_name(_key
, "1");
616 // push down parameters into raw spice data
617 for (PARAM_LIST::iterator i
= _params
.begin(); i
!= _params
.end(); ++i
) {
618 if (i
->second
.has_hard_value()) {
620 Set_param_by_name(i
->first
, ::to_string(i
->second
.e_val(1,scope())));
621 }catch (Exception_No_Match
&) {
622 error(bTRACE
, long_label() + ": bad parameter: " + i
->first
+ ", ignoring\n");
631 int ok
= info
.DEVsetup(NULL
, &_spice_model
._gen
, ckt(), NULL
);
636 /*--------------------------------------------------------------------------*/
637 void MODEL_SPICE::set_dev_type(const std::string
& new_type
)
641 //_spice_model._gen.set_mod_name(short_label());
642 std::string s
= short_label();
643 char* p
= new char[s
.length()+1]; //BUG//memory leak
644 s
.copy(p
, std::string::npos
);
645 p
[s
.length()] = '\0';
646 _spice_model
._gen
.GENmodName
= p
;
649 if (OPT::case_insensitive
) {
650 notstd::to_lower(&_key
);
654 /*--------------------------------------------------------------------------*/
655 bool MODEL_SPICE::param_is_printable(int i
)const
657 assert(i
< MODEL_SPICE::param_count());
658 if (i
>= MODEL_CARD::param_count()) {
659 return _params
.is_printable(MODEL_SPICE::param_count() - 1 - i
);
661 return MODEL_CARD::param_is_printable(i
);
664 /*--------------------------------------------------------------------------*/
665 std::string
MODEL_SPICE::param_name(int i
)const
667 assert(i
< MODEL_SPICE::param_count());
668 if (i
>= MODEL_CARD::param_count()) {
669 return _params
.name(MODEL_SPICE::param_count() - 1 - i
);
671 return MODEL_CARD::param_name(i
);
674 /*--------------------------------------------------------------------------*/
675 std::string
MODEL_SPICE::param_name(int i
, int j
)const
677 assert(i
< MODEL_SPICE::param_count());
678 if (j
== 0) {untested();
679 return param_name(i
);
680 }else if (i
>= MODEL_CARD::param_count()) {untested();
683 return MODEL_CARD::param_name(i
);
686 /*--------------------------------------------------------------------------*/
687 std::string
MODEL_SPICE::param_value(int i
)const
689 assert(i
< MODEL_SPICE::param_count());
690 if (i
>= MODEL_CARD::param_count()) {
691 return _params
.value(MODEL_SPICE::param_count() - 1 - i
);
693 return MODEL_CARD::param_value(i
);
696 /*--------------------------------------------------------------------------*/
697 void MODEL_SPICE::set_param_by_index(int, std::string
&, int)
701 /*--------------------------------------------------------------------------*/
702 /*--------------------------------------------------------------------------*/
703 DEV_SPICE::DEV_SPICE()
719 attach_common(&Default_Params
);
720 std::fill_n(&_inst_space
, sizeof(INSTANCE
), '\0');
724 int* node
= spice_nodes();
725 for (uint_t ii
= 0; ii
< matrix_nodes(); ++ii
) {
726 node
[ii
] = SPICE_INVALID_NODE
;
730 for (uint_t ii
= 0; ii
< matrix_nodes(); ++ii
) {
731 assert(!(_n
[ii
].n_()));
734 for (uint_t ii
= 0; ii
< matrix_nodes()+OFFSET
; ++ii
) {
735 _matrix
[ii
] = _matrix_core
[ii
];
739 assert(OPT::_keep_time_steps
<= 8);
740 for (uint_t ii
=0; ii
<8; ++ii
) {
747 /*--------------------------------------------------------------------------*/
748 DEV_SPICE::DEV_SPICE(const DEV_SPICE
& p
)
751 _modelname(p
._modelname
),
753 _spice_model(p
._spice_model
),
761 _num_states(p
._num_states
),
762 _maxEqNum(p
._maxEqNum
)
767 int* node
= spice_nodes();
768 for (uint_t ii
= 0; ii
< matrix_nodes(); ++ii
) {
769 assert(node
[ii
] == SPICE_INVALID_NODE
);
773 for (uint_t ii
= 0; ii
< matrix_nodes(); ++ii
) {
777 for (uint_t ii
= 0; ii
< matrix_nodes()+OFFSET
; ++ii
) {
778 _matrix
[ii
] = _matrix_core
[ii
];
782 assert(OPT::_keep_time_steps
<= 8);
783 for (uint_t ii
=0; ii
<8; ++ii
) {
790 /*--------------------------------------------------------------------------*/
791 DEV_SPICE::~DEV_SPICE()
799 for (uint_t ii
=0; ii
<OPT::_keep_time_steps
; ++ii
) {
801 delete [] _states
[ii
];
807 assert(OPT::_keep_time_steps
<= 8);
808 for (uint_t ii
=0; ii
<8; ++ii
) {
809 assert(!_states
[ii
]);
812 assert(!_spice_model
);
815 /*--------------------------------------------------------------------------*/
816 void DEV_SPICE::set_dev_type(const std::string
& new_type
)
818 _modelname
= new_type
;
820 /*--------------------------------------------------------------------------*/
821 void DEV_SPICE::Set_param_by_name(std::string Name
, std::string new_value
)
824 assert(info
.DEVpublic
.numInstanceParms
);
825 assert(info
.DEVpublic
.instanceParms
);
826 assert(info
.DEVparam
);
828 int num_params
= *(info
.DEVpublic
.numInstanceParms
);
829 for (int i
= 0; i
< num_params
; ++i
) {
830 IFparm Parms
= info
.DEVpublic
.instanceParms
[i
];
831 if (Name
== Parms
.keyword
) {
832 Set_param_by_index(i
, new_value
, 0);
837 mutable_common()->COMMON_COMPONENT::Set_param_by_name(Name
, new_value
);
839 /*--------------------------------------------------------------------------*/
840 void DEV_SPICE::set_param_by_name(std::string Name
, std::string Value
)
842 if (OPT::case_insensitive
) {
843 notstd::to_lower(&Name
);
846 COMPONENT::set_param_by_name(Name
, Value
);
847 COMMON_PARAMLIST
* c
= dynamic_cast<COMMON_PARAMLIST
*>(mutable_common());
849 Set_param_by_name(Name
, ::to_string(c
->_params
[Name
].e_val(1,scope())));
851 /*--------------------------------------------------------------------------*/
852 void DEV_SPICE::Set_param_by_index(int i
, std::string
& new_value
, int offset
)
855 assert(info
.DEVpublic
.numInstanceParms
);
856 assert(info
.DEVpublic
.instanceParms
);
857 assert(info
.DEVparam
);
859 int num_params
= *(info
.DEVpublic
.numInstanceParms
);
860 if (i
< num_params
) {
861 IFparm Parms
= info
.DEVpublic
.instanceParms
[i
];
863 IFVA
v(&Value
, Parms
.dataType
);
866 int ok
= info
.DEVparam(ckt(), Parms
.id
, &Value
, &_spice_instance
, NULL
);
868 int ok
= info
.DEVparam(Parms
.id
, &Value
, &_spice_instance
, NULL
);
872 STORAGE::set_param_by_index(i
-num_params
, new_value
, offset
+num_params
);
876 /*--------------------------------------------------------------------------*/
877 void DEV_SPICE::expand()
880 assert(info
.DEVsetup
);
886 { //-------- fix up external nodes
887 int* node
= spice_nodes();
888 for (uint_t ii
= 0; ii
< net_nodes(); ++ii
) {
889 node
[ii
] = ii
+OFFSET
;
891 if (UNCONNECTED_NODES
== uGROUND
) {
892 for (uint_t ii
= net_nodes(); ii
< max_nodes(); ++ii
) {itested();
893 node
[ii
] = ii
+OFFSET
;
895 }else if (UNCONNECTED_NODES
== uFLOAT
) {
896 for (uint_t ii
= net_nodes(); ii
< max_nodes(); ++ii
) {untested();
897 node
[ii
] = SPICE_UNCONNECTED_NODE
;
900 assert(UNCONNECTED_NODES
== uDISALLOW
);
901 assert(min_nodes() == max_nodes());
902 assert(net_nodes() == max_nodes());
904 ckt()->CKTmaxEqNum
= max_nodes();
906 for (uint_t ii
= max_nodes(); ii
< matrix_nodes(); ++ii
) {
911 { //------- attach model, set up matrix pointers
912 _model
= dynamic_cast<const MODEL_SPICE
*>(find_model(_modelname
));
914 throw Exception_Model_Type_Mismatch(long_label(), _modelname
, DEVICE_TYPE
);
916 SMPmatrix
* matrix
= reinterpret_cast<SMPmatrix
*>(_matrix
);
919 _spice_instance
.GENmodPtr
= &(_model
->_spice_model
._gen
);
920 _spice_model
= &(_model
->_spice_model
);
921 SPICE_MODEL_DATA
spice_model_copy(*_spice_model
);
922 spice_model_copy
._gen
.GENinstances
= &_spice_instance
;
924 int ok
= info
.DEVsetup(matrix
, &(spice_model_copy
._gen
), ckt(), &_num_states
);
925 // memory pointer setup, and sets _num_states
926 // undesired side effects: sets values, messes up model
929 _maxEqNum
= ckt()->CKTmaxEqNum
;
930 trace1("expand", ckt()->CKTmaxEqNum
);
931 assert_model_unlocalized();
935 //-------- allocate state vectors
937 for (uint_t ii
=0; ii
<OPT::_keep_time_steps
; ++ii
) {
938 assert(!_states
[ii
]);
939 _states
[ii
] = new double[_num_states
];
941 _states_1
= new double[_num_states
];
944 for (uint_t ii
=0; ii
<OPT::_keep_time_steps
; ++ii
) {
946 std::fill_n(_states
[ii
], _num_states
, 0);
949 std::fill_n(_states_1
, _num_states
, 0);
951 //std::fill_n(_i1, matrix_nodes()+OFFSET, 0);
952 //std::fill_n(_v1, matrix_nodes()+OFFSET, 0);
954 //-------- fix up internal nodes
955 if (_sim
->is_first_expand()) {
956 int start_internal
= 0;
957 if (UNCONNECTED_NODES
== uGROUND
) {
958 for (uint_t ii
= net_nodes(); ii
< max_nodes(); ++ii
) {itested();
959 _n
[ii
].set_to_ground(this);
961 start_internal
= max_nodes();
963 assert(UNCONNECTED_NODES
== uDISALLOW
|| UNCONNECTED_NODES
== uFLOAT
);
964 start_internal
= net_nodes();
966 assert(start_internal
!= 0);
968 int* node
= spice_nodes(); // treat as array
969 char fake_name
[] = "a";
970 for (uint_t ii
= start_internal
; ii
< matrix_nodes(); ++ii
) {
971 if (node
[ii
] >= start_internal
+OFFSET
) {
972 // real internal node
973 _n
[ii
].new_model_node("." + short_label() + '_' + fake_name
, this);
974 trace3("new int", node
[ii
], _n
[ii
].t_(), short_label());
976 }else if (node
[ii
] >= 0+OFFSET
) {
977 // collapsed to an external node
978 trace2("collapse", node
[ii
], _n
[ii
].t_());
979 _n
[ii
] = _n
[node
[ii
]-OFFSET
];
983 trace2("not used", node
[ii
], _n
[ii
].t_());
984 assert(!_n
[ii
].n_());
989 for (uint_t ii
= 0; ii
< matrix_nodes(); ++ii
) {
990 trace2((_n
[ii
].n_()) ? (_n
[ii
].n_()->short_label().c_str()) : ("NULL"), ii
, node
[ii
]);
993 // This could be one loop, but doing it this way gives more info.
994 for (uint_t ii
= 0; ii
< min_nodes(); ++ii
) {
997 for (uint_t ii
= min_nodes(); ii
< net_nodes(); ++ii
) {
1000 for (uint_t ii
= net_nodes(); ii
< max_nodes(); ++ii
) {itested();
1001 //assert(_n[ii].n_());
1003 for (uint_t ii
= max_nodes(); ii
< matrix_nodes(); ++ii
) {
1004 assert(_n
[ii
].n_() || !node
[ii
]);
1008 assert_model_unlocalized();
1011 /*--------------------------------------------------------------------------*/
1012 void DEV_SPICE::precalc_last()
1016 assert(info
.DEVsetup
);
1018 STORAGE::precalc_last();
1021 // push down parameters into spice data
1022 COMMON_PARAMLIST
* c
= dynamic_cast<COMMON_PARAMLIST
*>(mutable_common());
1024 for (PARAM_LIST::iterator i
= c
->_params
.begin(); i
!= c
->_params
.end(); ++i
) {
1025 if (i
->second
.has_hard_value()) {
1027 Set_param_by_name(i
->first
, ::to_string(i
->second
.e_val(1,scope())));
1028 }catch (Exception_No_Match
&) {
1029 error(bTRACE
, long_label() + ": bad parameter: " + i
->first
+ ", ignoring\n");
1035 int* node
= spice_nodes(); // treat as array //
1036 int node_stash
[MATRIX_NODES
]; //
1037 notstd::copy_n(node
, matrix_nodes(), node_stash
); // save the real nodes
1039 { //-------- fix up external nodes, again ........
1040 // put the originals back, so DEVsetup can mess them up the same as last time
1041 int* node
= spice_nodes();
1042 for (uint_t ii
= 0; ii
< net_nodes(); ++ii
) {
1043 node
[ii
] = ii
+OFFSET
;
1045 if (UNCONNECTED_NODES
== uGROUND
) {
1046 for (uint_t ii
= net_nodes(); ii
< max_nodes(); ++ii
) {itested();
1047 node
[ii
] = ii
+OFFSET
;
1049 }else if (UNCONNECTED_NODES
== uFLOAT
) {
1050 for (uint_t ii
= net_nodes(); ii
< max_nodes(); ++ii
) {untested();
1051 node
[ii
] = SPICE_UNCONNECTED_NODE
;
1054 assert(UNCONNECTED_NODES
== uDISALLOW
);
1055 assert(min_nodes() == max_nodes());
1056 assert(net_nodes() == max_nodes());
1058 ckt()->CKTmaxEqNum
= max_nodes();
1060 for (uint_t ii
= max_nodes(); ii
< matrix_nodes(); ++ii
) {
1066 SMPmatrix
* matrix
= reinterpret_cast<SMPmatrix
*>(_matrix
);
1067 int num_states_garbage
= 0;
1069 assert(_spice_model
== &(_model
->_spice_model
));
1070 SPICE_MODEL_DATA
spice_model_copy(*_spice_model
);
1071 spice_model_copy
._gen
.GENinstances
= &_spice_instance
;
1073 int ok
= info
.DEVsetup(matrix
, &(spice_model_copy
._gen
), ckt(), &num_states_garbage
);
1076 assert(num_states_garbage
== _num_states
);
1077 trace3("precalc", _maxEqNum
, ckt()->CKTmaxEqNum
, (_maxEqNum
== ckt()->CKTmaxEqNum
));
1078 assert(_maxEqNum
== ckt()->CKTmaxEqNum
);
1079 notstd::copy_n(node_stash
, matrix_nodes(), node
); // put back real nodes
1080 // hopefully, the matrix pointers are the same as last time!
1082 assert(!is_constant());
1083 assert_model_unlocalized();
1086 /*--------------------------------------------------------------------------*/
1087 void DEV_SPICE::internal_precalc()
1091 if (info
.DEVtemperature
) {
1094 assert_model_unlocalized();
1095 _spice_model
->_gen
.GENinstances
= &_spice_instance
;
1096 assert_model_localized();
1098 // ELEMENT::precalc(); .. don't call .. more analysis needed
1100 int ok
= info
.DEVtemperature(&(_spice_model
->_gen
), ckt());
1104 _spice_model
->_gen
.GENinstances
= NULL
;
1106 assert(!is_constant());
1110 assert_model_unlocalized();
1112 /*--------------------------------------------------------------------------*/
1113 void DEV_SPICE::tr_advance()
1115 STORAGE::tr_advance();
1118 double* t
= _states
[OPT::_keep_time_steps
-1];
1119 for (uint_t ii
= OPT::_keep_time_steps
-1; ii
> 0; --ii
) {
1120 _states
[ii
] = _states
[ii
-1];
1123 notstd::copy_n(_states
[1], _num_states
, _states
[0]);
1125 /*--------------------------------------------------------------------------*/
1126 void DEV_SPICE::tr_regress()
1128 ELEMENT::tr_regress();
1131 /*--------------------------------------------------------------------------*/
1132 bool DEV_SPICE::tr_needs_eval()const
1134 if (is_q_for_eval()) {
1136 }else if (!converged()) {
1138 }else if (_sim
->is_advance_iteration()) {
1140 }else if (_time
[1] == 0) {
1141 //BUG// needed for ngspice jfet, but not for spice3f5 jfet
1144 int* node
= spice_nodes();
1145 // check the node voltages, reference to ground
1146 for (uint_t ii
=0; ii
<matrix_nodes(); ++ii
) {
1147 if ((node
[ii
] != SPICE_INVALID_NODE
)
1148 && !conchk(_v1
[node
[ii
]], _n
[ii
].v0(), 0, OPT::reltol
*OPT::bypasstol
)) {
1153 // check the node voltages, reference to each other
1154 for (uint_t ii
=0; ii
<matrix_nodes(); ++ii
) {
1155 for (uint_t jj
=0; jj
<ii
; ++jj
) {
1156 if ((node
[ii
] != SPICE_INVALID_NODE
) && (node
[jj
] != SPICE_INVALID_NODE
)
1157 && !conchk((_v1
[node
[ii
]] - _v1
[node
[jj
]]),
1158 (_n
[ii
].v0() - _n
[jj
].v0()),
1159 0, OPT::reltol
*OPT::bypasstol
)) {
1168 /*--------------------------------------------------------------------------*/
1169 // MODEINITFLOAT = normal iteration
1170 // MODEINITPRED = 1st iter at a new time point
1171 // MODEINITTRAN = 1st iter at 1st time pt after initial DC
1172 // MODEINITFIX = like FLOAT, but honor options like "off"
1173 // MODEINITJCT = initial guess
1174 // MODEINITSMSIG = like FLOAT, but setup for small signal, don't load arrays
1175 /*--------------------------------------------------------------------------*/
1176 bool DEV_SPICE::do_tr()
1179 assert(info
.DEVload
);
1180 assert(_num_states
>= 0);
1184 assert_model_unlocalized();
1185 _spice_model
->_gen
.GENinstances
= &_spice_instance
;
1186 assert_model_localized();
1188 if (_sim
->analysis_is_tran_dynamic()) {
1189 if ((_time
[1] == 0) && _sim
->is_first_iteration()) {
1190 ckt()->CKTmode
= MODETRAN
| MODEINITTRAN
;
1192 ckt()->CKTmode
= MODETRAN
| MODEINITFLOAT
;
1195 if (_sim
->analysis_is_tran_static()) {
1196 ckt()->CKTmode
= MODETRANOP
;
1197 }else if (_sim
->analysis_is_tran_restore()) {
1198 ckt()->CKTmode
= MODETRAN
;
1199 }else if (_sim
->command_is_dc()) {
1200 ckt()->CKTmode
= MODEDCTRANCURVE
;
1201 }else if (_sim
->command_is_op()) {
1202 ckt()->CKTmode
= MODEDCOP
;
1203 }else{unreachable();
1206 if (_sim
->uic_now()) {
1207 ckt()->CKTmode
|= MODEINITFIX
;
1208 ckt()->CKTmode
|= MODEUIC
;
1209 }else if (_sim
->is_initial_step()) {
1210 ckt()->CKTmode
|= MODEINITJCT
;
1212 ckt()->CKTmode
|= MODEINITFLOAT
;
1217 int* node
= spice_nodes();
1218 assert(ckt()->CKTrhsOld
== _v1
);
1219 std::fill_n(_v1
, matrix_nodes()+OFFSET
, 0);
1220 for (uint_t ii
= 0; ii
< matrix_nodes(); ++ii
) {
1221 if (node
[ii
] != SPICE_INVALID_NODE
) {
1222 _v1
[node
[ii
]] = _n
[ii
].v0();
1227 { // clear for copy out
1228 ckt()->CKTtroubleElt
= NULL
;
1229 ckt()->CKTnoncon
= 0;
1231 assert(ckt()->CKTrhs
== _i0
);
1232 std::fill_n(_i0
, matrix_nodes()+OFFSET
, 0);
1234 for (uint_t ii
= 0; ii
< matrix_nodes()+OFFSET
; ++ii
) {
1235 for (uint_t jj
= 0; jj
< matrix_nodes()+OFFSET
; ++jj
) {
1236 _matrix
[ii
][jj
].real(0.);
1241 // do the work -- it might also do convergence checking, might not
1243 info
.DEVload(&(_spice_model
->_gen
), ckt());
1245 // convergence check -- gnucap method
1246 unsigned trouble
= ckt()->CKTnoncon
;
1247 double ramptol
= 1e12
*OPT::gmin
;
1249 set_converged(!trouble
);
1250 for (int ii
= 0; ii
< _num_states
; ++ii
) {
1252 bool c
= conchk(_states
[0][ii
], _states_1
[ii
], OPT::abstol
*ramptol
);
1253 if(!c
) trouble
= 10;
1256 trace3("", ii
, _states_1
[ii
], _states
[0][ii
]);
1257 _states_1
[ii
] = _states
[0][ii
];
1259 for (uint_t ii
= 0; converged() && ii
< matrix_nodes()+OFFSET
; ++ii
) {
1260 bool c
= conchk(_i0
[ii
], _i1
[ii
], OPT::abstol
*ramptol
);
1261 if(!c
) trouble
= 20;
1264 for (uint_t ii
= 0; converged() && ii
< matrix_nodes()+OFFSET
; ++ii
) {
1265 for (uint_t jj
= 0; converged() && jj
< matrix_nodes()+OFFSET
; ++jj
) {
1266 bool c
= conchk(_matrix
[ii
][jj
].real(), _matrix
[ii
][jj
].imag(), OPT::abstol
*ramptol
);
1267 if(!c
) trouble
= 30;
1275 // convergence check -- Spice method
1276 // not sure if it is worth the effort
1277 if (converged() && info
.DEVconvTest
) {
1278 ckt()->CKTnoncon
= 0;
1279 ckt()->CKTrhs
= _v1
; // Spice overlaps _i0 with _v1 as CKTrhs
1280 info
.DEVconvTest(&(_spice_model
->_gen
), ckt());
1281 set_converged(ckt()->CKTnoncon
== 0);
1283 // either no separate test or already failed
1286 bool needs_load
= !converged();
1287 for (uint_t ii
= 0; !needs_load
&& ii
< matrix_nodes()+OFFSET
; ++ii
) {
1288 needs_load
= !conchk(_i0
[ii
], _i1
[ii
], 0, OPT::reltol
*OPT::loadtol
);
1290 for (uint_t ii
= 0; !needs_load
&& ii
< matrix_nodes()+OFFSET
; ++ii
) {
1291 for (uint_t jj
= 0; !needs_load
&& jj
< matrix_nodes()+OFFSET
; ++jj
) {
1292 needs_load
= !conchk(_matrix
[ii
][jj
].real(), _matrix
[ii
][jj
].imag(),
1293 0, OPT::reltol
*OPT::loadtol
);
1302 assert_model_localized();
1303 _spice_model
->_gen
.GENinstances
= NULL
;
1304 assert_model_unlocalized();
1307 /*--------------------------------------------------------------------------*/
1308 void DEV_SPICE::tr_load()
1311 if (_loaditer
== _sim
->iteration_tag()) {untested();
1312 error(bDANGER
, long_label() + " internal error: double load\n");
1314 _loaditer
= _sim
->iteration_tag();
1317 int ihit
[MATRIX_NODES
+OFFSET
];
1318 int jhit
[MATRIX_NODES
+OFFSET
];
1320 std::fill_n(ihit
, matrix_nodes()+OFFSET
, 0);
1321 std::fill_n(jhit
, matrix_nodes()+OFFSET
, 0);
1323 int* node
= spice_nodes();
1324 for (uint_t ii
= 0; ii
< matrix_nodes(); ++ii
) {
1326 if (ni
&& !ihit
[ni
]) {
1328 int nii
= ni
-OFFSET
;
1329 trace4("", ii
, ni
, _i0
[ni
], _i1
[ni
]);
1330 tr_load_source_point(_n
[ii
], &(_i0
[ni
]), &(_i1
[ni
]));
1331 for (uint_t jj
= 0; jj
< matrix_nodes(); ++jj
) {
1333 if (nj
&& jhit
[nj
] != ni
) {
1335 int njj
= nj
-OFFSET
;
1337 trace2("", _matrix
[nii
][njj
].real(), _matrix
[nii
][njj
].imag());
1338 tr_load_point(_n
[ii
], _n
[jj
], &reinterpret_cast<double(&)[2]>(_matrix
[nii
][njj
])[0] , &reinterpret_cast<double(&)[2]>(_matrix
[nii
][njj
])[1]);
1340 trace2("skip", jj
, nj
);
1344 trace2("=========skip", ii
, ni
);
1348 /*--------------------------------------------------------------------------*/
1349 void DEV_SPICE::tr_unload()
1350 {untested();incomplete();
1352 for (uint_t ii
= 0; ii
< matrix_nodes(); ++ii
) {untested();
1353 for (uint_t jj
= 0; jj
< matrix_nodes(); ++jj
) {untested();
1354 _matrix
[ii
][jj
].real(0);
1357 _sim
->mark_inc_mode_bad();
1360 /*--------------------------------------------------------------------------*/
1361 TIME_PAIR
DEV_SPICE::tr_review()
1363 // not calling STORAGE::tr_review();
1365 if (info
.DEVtrunc
) {
1370 assert_model_unlocalized();
1371 _spice_model
->_gen
.GENinstances
= &_spice_instance
;
1372 assert_model_localized();
1374 ckt()->CKTtroubleElt
= NULL
;
1375 double timestep
= NEVER
;
1377 info
.DEVtrunc(&(_spice_model
->_gen
), ckt(), ×tep
);
1380 _time_by
._error_estimate
= tr_review_check_and_convert(timestep
);
1381 _time_by
._event
= NEVER
;
1383 _spice_model
->_gen
.GENinstances
= NULL
;
1384 assert_model_unlocalized();
1387 return TIME_PAIR(NEVER
,NEVER
);
1390 /*--------------------------------------------------------------------------*/
1391 void DEV_SPICE::tr_accept()
1393 assert_model_unlocalized();
1394 _spice_model
->_gen
.GENinstances
= &_spice_instance
;
1395 assert_model_localized();
1397 //STORAGE::tr_accept(); // doesn't do anything
1399 if (_sim
->analysis_is_dcop() || _sim
->analysis_is_ac()) {
1403 assert(ckt()->CKTrhsOld
== _v1
);
1404 // _v1 already has correct values
1405 // _n[ii].v0() is not correct -- may have been cleared
1407 ckt()->CKTmode
= MODEINITSMSIG
;
1408 info
.DEVload(&(_spice_model
->_gen
), ckt());
1411 assert_model_localized();
1412 _spice_model
->_gen
.GENinstances
= NULL
;
1413 assert_model_unlocalized();
1415 /*--------------------------------------------------------------------------*/
1416 double DEV_SPICE::tr_probe_num(const std::string
& x
)const
1419 assert_ckt_up_to_date(ckt());
1422 // all of the "states" in state array
1423 int num_probe_states
= std::min(_num_states
, int(sizeof(state_names
)/sizeof(std::string
)));
1424 for (int ii
=0; ii
<num_probe_states
&& state_names
[ii
]!=""; ++ii
) {
1425 if (Umatch(x
, state_names
[ii
] + ' ')) {
1426 return _states
[0][ii
];
1432 if (Umatch(x
, "trouble ")) {
1438 // data that Spice has, through "ask"
1439 assert(info
.DEVpublic
.numInstanceParms
);
1440 assert(info
.DEVpublic
.instanceParms
);
1442 for (int ii
=0; ii
<(*(info
.DEVpublic
.numInstanceParms
)); ++ii
) {
1443 IFparm Parms
= info
.DEVpublic
.instanceParms
[ii
];
1444 int datatype
= Parms
.dataType
;
1445 if (datatype
& IF_ASK
&& Umatch(x
, std::string(Parms
.keyword
) + ' ')) {
1447 int ok
= info
.DEVask(ckt(), &_spice_instance
, Parms
.id
, &v
, NULL
);
1449 switch (datatype
& 0xff) {
1458 // make believe it is not a match
1460 break; // break switch, continue loop
1463 // match, but not useful here.
1469 // maybe there is more than one match, so continue loop
1472 // really not a match, keep looking
1476 // no DEVask .. can't do anything.
1478 return STORAGE::tr_probe_num(x
);
1480 /*--------------------------------------------------------------------------*/
1481 void DEV_SPICE::ac_begin()
1483 STORAGE::ac_begin();
1487 /*--------------------------------------------------------------------------*/
1488 void DEV_SPICE::do_ac()
1490 if (info
.DEVacLoad
|| info
.DEVpzLoad
) {
1492 assert(_num_states
>= 0);
1494 assert_model_unlocalized();
1495 _spice_model
->_gen
.GENinstances
= &_spice_instance
;
1496 assert_model_localized();
1499 ckt()->CKTmode
= MODEAC
;
1500 ckt()->CKTomega
= _sim
->_jomega
.imag();
1502 // clear for copy out
1503 ckt()->CKTtroubleElt
= NULL
;
1504 std::fill_n(_i0
, matrix_nodes()+OFFSET
, 0);
1505 std::fill_n(_i1
, matrix_nodes()+OFFSET
, 0);
1506 for (uint_t ii
= 0; ii
< matrix_nodes()+OFFSET
; ++ii
) {
1507 for (uint_t jj
= 0; jj
< matrix_nodes()+OFFSET
; ++jj
) {
1508 _matrix
[ii
][jj
] = 0;
1512 if (info
.DEVpzLoad
) {
1513 info
.DEVpzLoad(&(_spice_model
->_gen
), ckt(), reinterpret_cast<SPcomplex
*>(&_sim
->_jomega
));
1514 }else if (info
.DEVacLoad
) {
1515 info
.DEVacLoad(&(_spice_model
->_gen
), ckt());
1516 }else{unreachable();
1520 assert_model_localized();
1521 _spice_model
->_gen
.GENinstances
= NULL
;
1522 assert_model_unlocalized();
1524 // there is no acLoad function
1527 /*--------------------------------------------------------------------------*/
1528 void DEV_SPICE::ac_load()
1530 if (info
.DEVacLoad
) {
1531 assert_ckt_up_to_date(ckt());
1533 int ihit
[MATRIX_NODES
+OFFSET
];
1534 int jhit
[MATRIX_NODES
+OFFSET
];
1536 std::fill_n(ihit
, matrix_nodes()+OFFSET
, 0);
1537 std::fill_n(jhit
, matrix_nodes()+OFFSET
, 0);
1539 int* node
= spice_nodes();
1540 for (uint_t ii
= 0; ii
< matrix_nodes(); ++ii
) {
1542 if (ni
&& !ihit
[ni
]) {
1544 int nii
= ni
-OFFSET
;
1545 trace3("", ii
, ni
, nii
);
1546 ac_load_source_point(_n
[ii
], COMPLEX(_i0
[ni
], _i1
[ni
]));
1547 for (uint_t jj
= 0; jj
< matrix_nodes(); ++jj
) {
1549 if (nj
&& jhit
[nj
] != ni
) {
1551 int njj
= nj
-OFFSET
;
1552 trace3("", jj
, nj
, njj
);
1553 trace2("", _matrix
[nii
][njj
].real(), _matrix
[nii
][njj
].imag());
1554 ac_load_point(_n
[ii
], _n
[jj
], _matrix
[nii
][njj
]);
1556 trace2("skip", jj
, nj
);
1560 trace2("=========skip", ii
, ni
);
1564 // there is no acLoad function
1567 /*--------------------------------------------------------------------------*/
1568 /*--------------------------------------------------------------------------*/
1570 // needed to satisfy references. Supposedly unreachable. Stubs.
1571 char *errMsg
= NULL
;
1572 char *errRtn
= NULL
;
1573 char* tmalloc(int size
) {itested(); return static_cast<char*>(calloc(size
,1));}
1574 char* trealloc(char*, int) {untested();incomplete(); return NULL
;} //DEVnoise
1575 void txfree(char *ptr
) {
1576 if (ptr
) {itested();
1582 static class FT_CURCKT
: public circ
{
1587 ci_curTask
= reinterpret_cast<char*>(&junk
);
1588 //::ft_curckt = this;
1590 } stupid_ft_circ_pointer_to_pointer_hack
;
1592 circ
*ft_curckt
= &stupid_ft_circ_pointer_to_pointer_hack
;
1594 IFuid
CKTnodName(CKTcircuit
*,int) {incomplete();return IFuid();} //DEVsenPrint
1596 double D1i2F1(double, double, double) {incomplete(); return NOT_VALID
;} //DEVdisto
1597 double D1i3F1(double, double, double, double, double, double) {incomplete(); return NOT_VALID
;}
1598 double D1iF12(double, double, double, double, double) {incomplete(); return NOT_VALID
;}
1599 double D1i2F12(double, double, double, double, double, double, double, double, double,
1600 double) {incomplete(); return NOT_VALID
;}
1601 double D1n2F1(double, double, double) {incomplete(); return NOT_VALID
;}
1602 double D1n3F1(double, double, double, double, double, double) {incomplete(); return NOT_VALID
;}
1603 double D1nF12(double, double, double, double, double) {incomplete(); return NOT_VALID
;}
1604 double D1n2F12(double, double, double, double, double, double, double, double, double,
1605 double) {incomplete(); return NOT_VALID
;}
1606 double DFn2F1(double, double, double, double, double, double, double, double, double,
1607 double, double, double) {incomplete(); return NOT_VALID
;}
1608 double DFi2F1(double, double, double, double, double, double, double, double, double,
1609 double, double, double) {incomplete(); return NOT_VALID
;}
1610 double DFi3F1(double, double, double, double, double, double, double, double, double,
1611 double, double, double, double, double, double, double, double, double,
1612 double, double, double, double, double, double, double, double, double,
1613 double) {incomplete(); return NOT_VALID
;}
1614 double DFn3F1(double, double, double, double, double, double, double, double, double,
1615 double, double, double, double, double, double, double, double, double,
1616 double, double, double, double, double, double, double, double, double,
1617 double) {incomplete(); return NOT_VALID
;}
1618 double DFnF12(double, double, double, double, double, double, double, double,
1619 double, double, double, double, double, double, double, double,
1620 double, double) {incomplete(); return NOT_VALID
;}
1621 double DFiF12(double, double, double, double, double, double, double, double,
1622 double, double, double, double, double, double, double, double,
1623 double, double) {incomplete(); return NOT_VALID
;}
1624 struct DpassStr
; //DEVdisto
1625 double DFn2F12(DpassStr
*) {incomplete(); return NOT_VALID
;}
1626 double DFi2F12(DpassStr
*) {incomplete(); return NOT_VALID
;}
1628 void AtanDeriv(Dderivs
*, Dderivs
*) {incomplete();} //DEVdisto
1629 void CosDeriv(Dderivs
*, Dderivs
*) {incomplete();} //DEVdisto
1630 void CubeDeriv(Dderivs
*, Dderivs
*) {incomplete();} //DEVdisto
1631 void DivDeriv(Dderivs
*, Dderivs
*, Dderivs
*) {incomplete();} //DEVdisto
1632 void EqualDeriv(Dderivs
*, Dderivs
*) {incomplete();} //DEVdisto
1633 void ExpDeriv(Dderivs
*, Dderivs
*) {incomplete();} //DEVdisto
1634 void InvDeriv(Dderivs
*, Dderivs
*) {incomplete();} //DEVdisto
1635 void MultDeriv(Dderivs
*, Dderivs
*, Dderivs
*) {incomplete();} //DEVdisto
1636 void PlusDeriv(Dderivs
*, Dderivs
*, Dderivs
*) {incomplete();} //DEVdisto
1637 void PowDeriv(Dderivs
*, Dderivs
*, double) {incomplete();} //DEVdisto
1638 void SqrtDeriv(Dderivs
*, Dderivs
*) {incomplete();} //DEVdisto
1639 void TanDeriv(Dderivs
*, Dderivs
*) {incomplete();} //DEVdisto
1640 void TimesDeriv(Dderivs
*, Dderivs
*, double) {incomplete();} //DEVdisto
1642 double Nintegrate(double, double, double, GENERIC
*) {incomplete(); return NOT_VALID
;} //DEVnoise
1644 double Nintegrate(double, double, double, Ndata
*) {incomplete(); return NOT_VALID
;} //DEVnoise
1646 void NevalSrc(double*, double*, CKTcircuit
*, int, int, int, double) {incomplete();} //DEVnoise
1647 void NevalSrc2(double*, double*, CKTcircuit
*, int, int, int, double, double) {incomplete();}
1648 //------------------------------------------------
1649 // should be constants, but spice wants them to be variables.
1650 double CONSTroot2(sqrt(2.));
1651 double CONSTvt0(P_CELSIUS0
*P_K_Q
);
1652 double CONSTKoverQ(P_K_Q
);
1654 //------------------------------------------------
1658 IFsimulator
*ft_sim
;
1659 //------------------------------------------------
1660 //------------------------------------------------
1661 int IFerror(int flags
, char* format
, IFuid
* names
) /* output an error or warning message */
1663 static struct mesg
{
1667 { "Warning", ERR_WARNING
} ,
1668 { "Fatal error", ERR_FATAL
} ,
1669 { "Panic", ERR_PANIC
} ,
1670 { "Note", ERR_INFO
} ,
1675 char buf
[10000], *s
, *bptr
;
1678 for (m
= msgs
; m
->flag
; m
++) {
1679 if (flags
& m
->flag
) {
1680 error(bDANGER
, "%s: ", m
->string
);
1685 for (s
= format
, bptr
= buf
; *s
; s
++) {
1686 if (*s
== '%' && (s
== format
|| *(s
-1) != '%') && *(s
+1) == 's') {
1687 if (names
[nindex
]) {
1688 strcpy(bptr
, reinterpret_cast<char*>(names
[nindex
]));
1690 strcpy(bptr
, "(null)");
1692 bptr
+= strlen(bptr
);
1701 case ERR_WARNING
:error(bWARNING
,buf
); break;
1702 case ERR_FATAL
: error(bDANGER
, buf
); throw Exception("");
1703 case ERR_PANIC
: error(bDANGER
, buf
); throw Exception("");
1704 case ERR_INFO
: error(bTRACE
, buf
); break;
1705 default: error(bDANGER
, buf
); break;
1709 void internalerror(char *message
)
1711 error(bDANGER
, "internal error: %s\n", message
);
1715 int CKTinst2Node(void*, void*, int, CKTnode
**, IFuid
*)
1716 {untested();incomplete();
1721 static IFfrontEnd fe
= {
1722 NULL
, //int ((*IFnewUid)()); /* create a new UID in the circuit */ noise, urcsetup
1723 NULL
, //int ((*IFpauseTest)()); /* should we stop now? */ noisean.c only
1724 NULL
, //double ((*IFseconds)()); /* what time is it? */ bjtdisto unused ifdef only (unused)
1725 IFerror
, //int ((*IFerror)()); /* output an error or warning message */ temp, setup
1733 static IFfrontEnd fe
= {
1734 NULL
, //int ((*IFnewUid)()); /* create a new UID in the circuit */ noise, urcsetup
1735 NULL
, //int ((*IFdelUid)()); /* create a new UID in the circuit */ not used
1736 NULL
, //int ((*IFpauseTest)()); /* should we stop now? */ noisean.c only
1737 NULL
, //double ((*IFseconds)()); /* what time is it? */ bjtdisto unused ifdef only (unused)
1738 IFerror
, //int ((*IFerror)()); /* output an error or warning message */ temp, setup
1739 NULL
, //int ((*OUTpBeginPlot)()); /* start pointwise output plot */ noisean.c only
1740 NULL
, //int ((*OUTpData)()); /* data for pointwise plot */ noisean.c only
1741 NULL
, //int ((*OUTwBeginPlot)()); /* start windowed output plot */ not used
1742 NULL
, //int ((*OUTwReference)()); /* independent vector for windowed plot */ not used
1743 NULL
, //int ((*OUTwData)()); /* data for windowed plot */ not used
1744 NULL
, //int ((*OUTwEnd)()); /* signal end of windows */ not used
1745 NULL
, //int ((*OUTendPlot)()); /* end of plot */ not used
1746 NULL
, //int ((*OUTbeginDomain)()); /* start nested domain */ not used
1747 NULL
, //int ((*OUTendDomain)()); /* end nested domain */ not used
1748 NULL
//int ((*OUTattributes)()); /* specify output attributes of node */ noisean.c only
1751 IFfrontEnd
* SPfrontEnd
= &fe
;
1752 //------------------------------------------------
1753 //------------------------------------------------
1754 int CKTsetBreak(CKTcircuit
* ckt
, double time
)
1756 if (time
< ckt
->CKTminBreak
) {untested();
1757 ckt
->CKTminBreak
= time
;
1762 //------------------------------------------------
1763 void CKTterr(int qcap
, CKTcircuit
* ckt
,double *time_step
)
1765 assert_ckt_localized(ckt
);
1767 std::valarray
<FPOLY1
> q(OPT::_keep_time_steps
);
1769 for (uint_t ii
= 0; ii
< OPT::_keep_time_steps
; ++ii
) {
1770 assert(ckt
->CKTstates
[ii
]);
1771 q
[ii
].x
= NOT_VALID
;
1772 q
[ii
].f0
= ckt
->CKTstates
[ii
][qcap
];
1773 q
[ii
].f1
= NOT_VALID
;
1776 DEV_SPICE
* d
= reinterpret_cast<DEV_SPICE
*>(ckt
->CKTstat
);
1778 assert(dynamic_cast<DEV_SPICE
*>(d
));
1780 *time_step
= std::min(d
->tr_review_trunc_error(&q
[0]), *time_step
);
1782 //------------------------------------------------
1783 int NIintegrate(CKTcircuit
* ckt
,double* geq
,double* ceq
,double cap
,int qcap
)
1784 { //-- used by DEVload (not DC)
1785 assert_ckt_localized(ckt
);
1788 if (ckt
->CKTorder
== 1) {
1791 assert(ckt
->CKTtimePoints
[1] != 0.);
1792 assert(ckt
->CKTorder
== 2);
1796 std::valarray
<FPOLY1
> q(OPT::_keep_time_steps
);
1797 std::valarray
<FPOLY1
> i(OPT::_keep_time_steps
);
1799 for (uint_t ii
= 0; ii
< OPT::_keep_time_steps
; ++ii
) {
1800 assert(ckt
->CKTstates
[ii
]);
1801 q
[ii
].x
= NOT_VALID
;
1802 q
[ii
].f0
= ckt
->CKTstates
[ii
][qcap
];
1804 trace3("", ii
, q
[ii
].f0
, q
[ii
].f1
);
1805 i
[ii
].x
= NOT_VALID
;
1806 i
[ii
].f0
= ckt
->CKTstates
[ii
][qcap
+1];
1807 i
[ii
].f1
= q
[ii
].f1
* ckt
->CKTag
[0];
1808 trace3("", ii
, i
[ii
].f0
, i
[ii
].f1
);
1809 assert(q
[ii
].f0
== q
[ii
].f0
);
1810 assert(q
[ii
].f1
== q
[ii
].f1
);
1811 assert(i
[ii
].f0
== i
[ii
].f0
);
1812 assert(i
[ii
].f1
== i
[ii
].f1
);
1815 i
[0] = differentiate(&q
[0], &i
[0], ckt
->CKTtimePoints
, method
);
1816 assert(i
[0].f0
== i
[0].f0
);
1817 assert(i
[0].f1
== i
[0].f1
);
1818 trace2("", i
[0].f0
, i
[0].f1
);
1820 ckt
->CKTstates
[0][qcap
+1] = i
[0].f0
;
1822 assert(ckt
->CKTdelta
!= 0. || (ckt
->CKTag
[0] == 0. && i
[0].f0
== 0.));
1823 *ceq
= i
[0].f0
- q
[0].f0
* ckt
->CKTag
[0];
1825 assert(*ceq
== *ceq
);
1826 assert(*geq
== *geq
);
1827 trace2("", *ceq
, *geq
);
1830 //------------------------------------------------
1831 //------------------------------------------------
1832 int CKTmkVolt(CKTcircuit
* ckt
, CKTnode
** n
, IFuid
, char*)
1833 { // get a new node number. -- used by DEVsetup
1834 assert_ckt_initialized(ckt
);
1836 static CKTnode n_static
; // always used only on next line
1837 *n
= &n_static
; // so reuse static structure
1838 (*n
)->number
= ((ckt
->CKTmaxEqNum
)++)+OFFSET
;
1839 trace1(__FUNCTION__
, (*n
)->number
);
1840 // local number (- == internal) only number is used
1843 int CKTmkCur(CKTcircuit
* ckt
, CKTnode
** n
, IFuid i
, char* c
)
1845 return CKTmkVolt(ckt
, n
, i
, c
);
1847 //------------------------------------------------
1848 int CKTdltNNum(void*,int)
1849 {untested(); // complement to CKTmkVolt. -- used by DEVunsetup
1850 // deletes what was new in CKTmkVolt
1851 // Nothing, because of no alloc there.
1854 //------------------------------------------------
1855 //------------------------------------------------
1856 double* SMPmakeElt(SMPmatrix
* mm
, int r
, int c
)
1857 { // returns a pointer m[r][c] -- used by DEVsetup
1860 if (r
== 0 || c
== 0) {
1861 static double trash
;
1865 assert(r
>= 0+OFFSET
);
1866 assert(r
< int(MATRIX_NODES
)+OFFSET
);
1867 assert(c
>= 0+OFFSET
);
1868 assert(c
< int(MATRIX_NODES
)+OFFSET
);
1869 COMPLEX
** m
= reinterpret_cast<COMPLEX
**>(mm
);
1871 assert(m
[r
-OFFSET
]);
1872 return reinterpret_cast<double*>(&(m
[r
-OFFSET
][c
-OFFSET
]));
1875 //------------------------------------------------
1877 int IFnewUid(GENERIC
*,IFuid
*,IFuid
,char*,int,GENERIC
**) {incomplete(); return 0;}
1878 int INPpName(char*,IFvalue
*,GENERIC
*,int,GENERIC
*) {incomplete(); return 0;}
1879 char *INPdevErr(char *) {incomplete(); return NULL
;}
1880 char *INPerror(int) {incomplete(); return NULL
;}
1881 spREAL
*spGetElement(char* s
, int r
, int c
) {return SMPmakeElt(s
,r
,c
);}
1882 char *INPerrCat(char *, char *) {incomplete(); return NULL
;}
1883 int INPgndInsert(GENERIC
*,char**,INPtables
*,GENERIC
**) {incomplete(); return 0;}
1884 char * INPdevParse(char**,GENERIC
*,int,GENERIC
*,double*,int*,INPtables
*) {incomplete(); return NULL
;}
1885 char *INPgetMod(GENERIC
*,char*,INPmodel
**,INPtables
*) {incomplete(); return NULL
;}
1886 int INPgetTok(char**,char**,int) {incomplete(); return 0;}
1887 int INPlookMod(char*) {incomplete(); return 0;}
1888 int INPtermInsert(GENERIC
*,char**,INPtables
*,GENERIC
**) {incomplete(); return 0;}
1889 int INPinsert(char**,INPtables
*) {incomplete(); return 0;}
1890 char *copy(char*) {incomplete(); return NULL
;}
1891 int NIsum(CKTcircuit
*,double*,int) {incomplete(); return 0;}
1892 double INPevaluate(char**,int*,int) {incomplete(); return NOT_VALID
;}
1893 IFvalue
*INPgetValue(GENERIC
*,char**,int,INPtables
*) {incomplete(); return NULL
;}
1896 /*--------------------------------------------------------------------------*/
1897 /*--------------------------------------------------------------------------*/
1898 // Verify that the layout of complex is as Spice assumes.
1899 // This is not guaranteed by the standard, but is believed to always be true.
1900 static struct COMPLEX_TEST
{
1904 double* prx
= &reinterpret_cast<double(&)[2]>(x
)[0];
1905 double* pix
= &reinterpret_cast<double(&)[2]>(x
)[1];
1906 assert(reinterpret_cast<void*>(prx
) == reinterpret_cast<void*>(px
));
1907 assert(reinterpret_cast<void*>(pix
-1) == reinterpret_cast<void*>(px
));
1912 /*--------------------------------------------------------------------------*/
1913 /*--------------------------------------------------------------------------*/
1914 int MODEL_SPICE::_count
= -1;
1915 int DEV_SPICE::_count
= -1;
1917 static DEV_SPICE p0
;
1918 static DISPATCHER
<CARD
>::INSTALL
1919 d0(&device_dispatcher
, std::string(SPICE_LETTER
) + "|" + DEVICE_TYPE
, &p0
);
1921 static MODEL_SPICE
p1(&p0
);
1922 static DISPATCHER
<MODEL_CARD
>::INSTALL
1923 d1(&model_dispatcher
, MODEL_TYPE
, &p1
);
1924 /*--------------------------------------------------------------------------*/
1925 /*--------------------------------------------------------------------------*/
1926 // vim:ts=8:sw=2:noet: