turn {DEV,MODEL}_SUBCKT into base class
[gnucap-felix.git] / include / spice-wrapper.cc
blob0484490821a45ca2c426df140a889d0171efbc41
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 /*--------------------------------------------------------------------------*/
24 // spice includes
25 extern "C" {
26 #define _complex CompleX
27 #define NODE NodE
28 #define public PubliC
29 #define bool BooL
30 #define main MaiN
31 #include "capabil.h"
32 #include "const.h"
33 #include "iferrmsg.h"
34 #include "devdefs.h"
35 #include "ftedefs.h"
36 #include "optdefs.h"
37 #ifdef JSPICE3
38 #include "uflags.h"
39 #include "inpdefs.h"
40 #include "tskdefs.h"
41 #endif
42 #undef main
43 #undef bool
44 #undef public
45 #undef NODE
46 #undef _complex
48 #undef eq
49 #undef OPT
50 #undef LINEAR
51 #undef STRING
52 #undef BOOLEAN
54 #undef VT_BOOL
55 #undef VT_NUM
56 #undef VT_REAL
57 #undef VT_STRING
58 #undef VT_LIST
60 /*--------------------------------------------------------------------------*/
61 // gnucap includes
62 #include "globals.h"
63 #include "u_xprobe.h"
64 #include "d_subckt.h"
65 #include "e_storag.h"
66 #include "e_model.h"
67 /*--------------------------------------------------------------------------*/
68 // customization -- must be last
69 #include "wrapper.h"
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?"
74 #endif
75 #endif
76 #if !defined(VALUE_NAME)
77 #define VALUE_NAME "#"
78 #endif
79 #if !defined(TAIL_SIZE)
80 #define TAIL_SIZE 1
81 #endif
82 #if !defined(IS_VALID)
83 #define IS_VALID {return MODEL_CARD::is_valid(d);}
84 #endif
85 /*--------------------------------------------------------------------------*/
86 extern SPICEdev info;
87 const int SPICE_INVALID_NODE = 0;
88 const int SPICE_UNCONNECTED_NODE = -1;
89 const int OFFSET = 1;
90 enum {uGROUND=1, uFLOAT=2, uDISALLOW=3};
91 const int MATRIX_NODES = (MAX_NET_NODES + INTERNAL_NODES);
92 class DEV_SPICE;
93 class MODEL_SPICE;
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
131 SPICE_MODEL_DATA() {
132 std::fill_n(&_space, sizeof(MODEL), '\0');
134 SPICE_MODEL_DATA(const SPICE_MODEL_DATA& p)
135 : _full(p._full) {
138 /*--------------------------------------------------------------------------*/
139 class MODEL_SPICE : public MODEL_CARD{
140 private:
141 static int _count;
142 static CKTcircuit _ckt;
143 public:
144 SPICE_MODEL_DATA _spice_model;
145 std::string _key;
146 std::string _level;
147 PARAM_LIST _params;
148 protected:
149 explicit MODEL_SPICE(const MODEL_SPICE& p); // for clone
150 public:
151 explicit MODEL_SPICE(const DEV_SPICE* p); // for dispatcher
152 ~MODEL_SPICE();
153 public: // override virtual
154 MODEL_CARD* clone()const {return new MODEL_SPICE(*this);}
155 bool is_valid(const COMPONENT* d)const IS_VALID
156 //void expand();
157 void precalc_first();
159 public: // type
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 {
182 private:
183 static int _count;
184 public:
185 private:
186 union {
187 mutable GENinstance _spice_instance;
188 INSTANCE _inst;
189 char _inst_space;
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];
197 public:
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
202 double* _states_1;
203 int _num_states;
204 int _maxEqNum;
205 private:
206 explicit DEV_SPICE(const DEV_SPICE& p);
207 public:
208 explicit DEV_SPICE();
209 ~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
221 void expand();
222 void precalc_last();
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();}
230 void tr_advance();
231 void tr_regress();
232 bool tr_needs_eval()const;
233 //void tr_queue_eval(); //ELEMENT
234 bool do_tr();
235 void tr_load();
236 TIME_PAIR tr_review();
237 void tr_accept();
238 void tr_unload();
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();}
247 void ac_begin();
248 void do_ac();
249 void ac_load();
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;}
254 public: // type
255 void set_dev_type(const std::string& nt);
256 std::string dev_type()const {return _modelname;}
257 public: // ports
258 // bool port_exists(int i)const //COMPONENT
259 std::string port_name(int i)const {itested();
260 assert(i >= 0);
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();}
277 private:
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) { \
336 assert(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()
355 assert(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
383 #ifndef JSPICE3
384 ckt()->CKTbadMos3 = false; // 1 = spice2 compat
385 ckt()->CKTsenInfo = NULL; // used as flag to print sens info
386 #endif
387 #ifdef NGSPICE_17
388 ckt()->CKTdefaultMosM = 1.;
389 ckt()->CKTcopyNodesets = false;
390 #endif
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;
408 ckt()->CKTmode = 0;
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);\
417 assert(d); \
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); \
426 }else{ \
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;
456 ckt()->CKTorder = 1;
457 }else if (_time[1] != 0 && _method_a == mTRAP) {
458 ckt()->CKTag[0] = 2 / _dt;
459 ckt()->CKTag[1] = 1;
460 ckt()->CKTorder = 2;
461 }else{
462 ckt()->CKTag[0] = 1 / _dt;
463 ckt()->CKTag[1] = -1 / _dt;
464 ckt()->CKTorder = 1;
466 ckt()->CKTrhs = const_cast<double*>(_i0);
467 ckt()->CKTrhsOld = const_cast<double*>(_v1);
468 ckt()->CKTirhs = const_cast<double*>(_i1);
469 ckt()->CKTmode = 0;
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 /*--------------------------------------------------------------------------*/
501 struct IFVA {
502 IFvalue* _v;
503 int _type;
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);
509 assert(_v);
510 int datatype = _type;
511 if (datatype & IF_SET) {
512 if (datatype & IF_VECTOR) {untested();
513 incomplete();
514 }else{
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();
521 //cmd >> _v->cValue;
522 incomplete();
523 break;
524 case IF_NODE:untested(); incomplete(); break;
525 case IF_STRING:
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());
531 break;
533 case IF_INSTANCE: untested(); incomplete(); break;
534 case IF_PARSETREE:untested(); incomplete(); break;
535 default: unreachable(); break;
537 }else{untested();
541 /*--------------------------------------------------------------------------*/
542 /*--------------------------------------------------------------------------*/
543 MODEL_SPICE::MODEL_SPICE(const DEV_SPICE* p)
544 :MODEL_CARD(p),
545 _spice_model(),
546 _key(),
547 _level(),
548 _params()
550 assert_model_raw();
552 /*--------------------------------------------------------------------------*/
553 MODEL_SPICE::MODEL_SPICE(const MODEL_SPICE& p)
554 :MODEL_CARD(p),
555 _spice_model(p._spice_model),
556 _key(p._key),
557 _level(p._level),
558 _params(p._params)
560 assert_model_raw();
562 /*--------------------------------------------------------------------------*/
563 MODEL_SPICE::~MODEL_SPICE()
565 --_count;
567 /*--------------------------------------------------------------------------*/
568 void MODEL_SPICE::Set_param_by_name(std::string Name, std::string new_value)
570 assert_model_raw();
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) {
579 IFvalue Value;
580 IFVA v(&Value, Parms.dataType);
581 v = new_value;
582 int ok = info.DEVmodParam(Parms.id, &Value, &_spice_model._gen);
583 assert(ok == OK);
584 return;
585 }else{
588 if (Name != "level") {untested();
589 throw Exception_No_Match(Name);
590 }else{
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);
598 }else{
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()) {
613 try {
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");
618 }else{
622 init_ckt();
623 if (info.DEVsetup) {
624 assert_model_raw();
625 int ok = info.DEVsetup(NULL, &_spice_model._gen, ckt(), NULL);
626 assert(ok == OK);
627 }else{untested();
630 /*--------------------------------------------------------------------------*/
631 void MODEL_SPICE::set_dev_type(const std::string& new_type)
633 assert_model_raw();
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;
642 _key = new_type;
643 if (OPT::case_insensitive) {
644 notstd::to_lower(&_key);
645 }else{
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);
654 }else{
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);
664 }else{
665 return MODEL_CARD::param_name(i);
668 /*--------------------------------------------------------------------------*/
669 std::string MODEL_SPICE::param_name(int i, int j)const
670 {untested();
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();
675 return "";
676 }else{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);
686 }else{
687 return MODEL_CARD::param_value(i);
690 /*--------------------------------------------------------------------------*/
691 void MODEL_SPICE::set_param_by_index(int, std::string&, int)
692 {untested();
693 unreachable();
695 /*--------------------------------------------------------------------------*/
696 /*--------------------------------------------------------------------------*/
697 DEV_SPICE::DEV_SPICE()
698 :STORAGE(),
699 _inst(),
700 _modelname(""),
701 _model(NULL),
702 _spice_model(NULL),
703 _nodes(),
704 _matrix(),
705 _matrix_core(),
706 _i0(),
707 _i1(),
708 _v1(),
709 _states_1(NULL),
710 _num_states(0),
711 _maxEqNum(0)
713 attach_common(&Default_Params);
714 std::fill_n(&_inst_space, sizeof(INSTANCE), '\0');
715 assert_instance();
718 int* node = spice_nodes();
719 for (int ii = 0; ii < matrix_nodes(); ++ii) {
720 node[ii] = SPICE_INVALID_NODE;
723 _n = _nodes;
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];
730 assert(_matrix[ii]);
733 assert(OPT::_keep_time_steps <= 8);
734 for (int ii=0; ii<8; ++ii) {
735 _states[ii] = NULL;
738 ++_count;
739 assert_instance();
741 /*--------------------------------------------------------------------------*/
742 DEV_SPICE::DEV_SPICE(const DEV_SPICE& p)
743 :STORAGE(p),
744 _inst(p._inst),
745 _modelname(p._modelname),
746 _model(p._model),
747 _spice_model(p._spice_model),
748 _nodes(),
749 _matrix(),
750 _matrix_core(),
751 _i0(),
752 _i1(),
753 _v1(),
754 _states_1(NULL),
755 _num_states(p._num_states),
756 _maxEqNum(p._maxEqNum)
758 assert_instance();
761 int* node = spice_nodes();
762 for (int ii = 0; ii < matrix_nodes(); ++ii) {
763 assert(node[ii] == SPICE_INVALID_NODE);
766 _n = _nodes;
767 for (int ii = 0; ii < matrix_nodes(); ++ii) {
768 _n[ii] = p._n[ii];
771 for (int ii = 0; ii < matrix_nodes()+OFFSET; ++ii) {
772 _matrix[ii] = _matrix_core[ii];
773 assert(_matrix[ii]);
776 assert(OPT::_keep_time_steps <= 8);
777 for (int ii=0; ii<8; ++ii) {
778 _states[ii] = NULL;
781 ++_count;
782 assert_instance();
784 /*--------------------------------------------------------------------------*/
785 DEV_SPICE::~DEV_SPICE()
787 assert_instance();
789 --_count;
791 if (_states[0]) {
792 // regular instances
793 for (int ii=0; ii<OPT::_keep_time_steps; ++ii) {
794 assert(_states[ii]);
795 delete [] _states[ii];
797 assert(_states_1);
798 delete [] _states_1;
799 }else{
800 // prototype
801 assert(OPT::_keep_time_steps <= 8);
802 for (int ii=0; ii<8; ++ii) {
803 assert(!_states[ii]);
805 assert(!_states_1);
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)
817 assert_instance();
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);
827 return;
828 }else{
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);
838 }else{
840 COMPONENT::set_param_by_name(Name, Value);
841 COMMON_SUBCKT* c = dynamic_cast<COMMON_SUBCKT*>(mutable_common());
842 assert(c);
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)
848 assert_instance();
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];
856 IFvalue Value;
857 IFVA v(&Value, Parms.dataType);
858 v = new_value;
859 #ifdef JSPICE3
860 int ok = info.DEVparam(ckt(), Parms.id, &Value, &_spice_instance, NULL);
861 #else
862 int ok = info.DEVparam(Parms.id, &Value, &_spice_instance, NULL);
863 #endif
864 assert(ok == OK);
865 }else{untested();
866 STORAGE::set_param_by_index(i-num_params, new_value, offset+num_params);
868 assert_instance();
870 /*--------------------------------------------------------------------------*/
871 void DEV_SPICE::expand()
873 assert_instance();
874 assert(info.DEVsetup);
876 STORAGE::expand();
878 init_ckt();
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;
893 }else{
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) {
901 node[ii] = 0;
905 { //------- attach model, set up matrix pointers
906 _model = dynamic_cast<const MODEL_SPICE*>(find_model(_modelname));
907 if (!_model) {
908 throw Exception_Model_Type_Mismatch(long_label(), _modelname, DEVICE_TYPE);
909 }else{
910 SMPmatrix* matrix = reinterpret_cast<SMPmatrix*>(_matrix);
911 _num_states = 0;
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;
917 //-------------
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
921 //-------------
922 assert(ok == OK);
923 _maxEqNum = ckt()->CKTmaxEqNum;
924 trace1("expand", ckt()->CKTmaxEqNum);
925 assert_model_unlocalized();
929 //-------- allocate state vectors
930 if (!_states[0]) {
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];
936 }else{
938 for (int ii=0; ii<OPT::_keep_time_steps; ++ii) {
939 assert(_states[ii]);
940 std::fill_n(_states[ii], _num_states, 0);
942 assert(_states_1);
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();
956 }else{
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]);
969 assert(_n[ii].n_());
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]);
974 assert(_n[ii].n_());
975 }else{
976 // not assigned
977 trace1("not used", node[ii]);
978 assert(!_n[ii].n_());
980 ++(*fake_name);
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) {
989 assert(_n[ii].n_());
991 for (int ii = min_nodes(); ii < net_nodes(); ++ii) {
992 assert(_n[ii].n_());
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]);
1000 }else{untested();
1002 assert_model_unlocalized();
1003 assert_instance();
1005 /*--------------------------------------------------------------------------*/
1006 void DEV_SPICE::precalc_last()
1008 assert(_model);
1009 assert_instance();
1010 assert(info.DEVsetup);
1012 STORAGE::precalc_last();
1013 init_ckt();
1015 // push down parameters into spice data
1016 COMMON_SUBCKT* c = dynamic_cast<COMMON_SUBCKT*>(mutable_common());
1017 assert(c);
1018 for (PARAM_LIST::iterator i = c->_params.begin(); i != c->_params.end(); ++i) {
1019 if (i->second.has_hard_value()) {
1020 try {
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");
1025 }else{
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;
1047 }else{
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) {
1055 node[ii] = 0;
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);
1069 assert(ok == OK);
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();
1078 assert_instance();
1080 /*--------------------------------------------------------------------------*/
1081 void DEV_SPICE::internal_precalc()
1083 update_ckt();
1085 if (info.DEVtemperature) {
1086 assert_instance();
1088 assert_model_unlocalized();
1089 _spice_model->_gen.GENinstances = &_spice_instance;
1090 assert_model_localized();
1092 // ELEMENT::precalc(); .. don't call .. more analysis needed
1093 //-----
1094 int ok = info.DEVtemperature(&(_spice_model->_gen), ckt());
1095 assert(ok == OK);
1096 //-----
1097 set_converged();
1098 _spice_model->_gen.GENinstances = NULL;
1100 assert(!is_constant());
1101 assert_instance();
1102 }else{
1104 assert_model_unlocalized();
1106 /*--------------------------------------------------------------------------*/
1107 void DEV_SPICE::tr_advance()
1109 STORAGE::tr_advance();
1110 update_ckt();
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];
1116 _states[0] = t;
1117 notstd::copy_n(_states[1], _num_states, _states[0]);
1119 /*--------------------------------------------------------------------------*/
1120 void DEV_SPICE::tr_regress()
1122 ELEMENT::tr_regress();
1123 update_ckt();
1125 /*--------------------------------------------------------------------------*/
1126 bool DEV_SPICE::tr_needs_eval()const
1128 if (is_q_for_eval()) {
1129 return false;
1130 }else if (!converged()) {
1131 return true;
1132 }else if (_sim->is_advance_iteration()) {
1133 return true;
1134 }else if (_time[1] == 0) {
1135 //BUG// needed for ngspice jfet, but not for spice3f5 jfet
1136 return true;
1137 }else{
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)) {
1143 return true;
1144 }else{
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)) {
1154 return true;
1155 }else{
1159 return false;
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()
1172 assert_instance();
1173 assert(info.DEVload);
1174 assert(_num_states >= 0);
1176 localize_ckt();
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;
1185 }else{
1186 ckt()->CKTmode = MODETRAN | MODEINITFLOAT;
1188 }else{
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();
1198 ckt()->CKTmode = 0;
1200 if (_sim->uic_now()) {
1201 ckt()->CKTmode |= MODEINITFIX;
1202 ckt()->CKTmode |= MODEUIC;
1203 }else if (_sim->is_initial_step()) {
1204 ckt()->CKTmode |= MODEINITJCT;
1205 }else{
1206 ckt()->CKTmode |= MODEINITFLOAT;
1210 { // copy in
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();
1217 }else{
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
1236 //-----
1237 info.DEVload(&(_spice_model->_gen), ckt());
1238 //-----
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);
1262 }else{
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);
1277 if (needs_load) {
1278 q_load();
1279 }else{
1282 assert_model_localized();
1283 _spice_model->_gen.GENinstances = NULL;
1284 assert_model_unlocalized();
1285 return converged();
1287 /*--------------------------------------------------------------------------*/
1288 void DEV_SPICE::tr_load()
1290 #ifndef NDEBUG
1291 if (_loaditer == _sim->iteration_tag()) {untested();
1292 error(bDANGER, long_label() + " internal error: double load\n");
1294 _loaditer = _sim->iteration_tag();
1295 #endif
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) {
1305 int ni = node[ii];
1306 if (ni && !ihit[ni]) {
1307 ihit[ni] = 1;
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) {
1312 int nj = node[jj];
1313 if (nj && jhit[nj] != ni) {
1314 jhit[nj] = ni;
1315 int njj = nj-OFFSET;
1316 trace2("", jj, nj);
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()));
1319 }else{
1320 trace2("skip", jj, nj);
1323 }else{
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();
1338 tr_load();
1340 /*--------------------------------------------------------------------------*/
1341 TIME_PAIR DEV_SPICE::tr_review()
1343 // not calling STORAGE::tr_review();
1345 if (info.DEVtrunc) {
1346 localize_ckt();
1347 assert_instance();
1348 //q_accept();
1350 assert_model_unlocalized();
1351 _spice_model->_gen.GENinstances = &_spice_instance;
1352 assert_model_localized();
1354 ckt()->CKTtroubleElt = NULL;
1355 double timestep = NEVER;
1356 //-----
1357 info.DEVtrunc(&(_spice_model->_gen), ckt(), &timestep);
1358 //-----
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();
1365 return _time_by;
1366 }else{
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()) {
1380 localize_ckt();
1382 // don't copy in
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());
1389 }else{itested();
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
1398 localize_ckt();
1399 assert_ckt_up_to_date(ckt());
1400 assert_instance();
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];
1407 }else{
1411 if (info.DEVask) {
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) + ' ')) {
1420 IFvalue v;
1421 int ok = info.DEVask(ckt(), &_spice_instance, Parms.id, &v, NULL);
1422 if (ok == OK) {
1423 switch (datatype & 0xff) {
1424 case IF_FLAG:
1425 case IF_INTEGER:
1426 return v.iValue;
1427 case IF_REAL:
1428 return v.rValue;
1429 case IF_COMPLEX:
1430 case IF_STRING:
1431 default:
1432 // make believe it is not a match
1433 incomplete();
1434 break; // break switch, continue loop
1436 }else{untested();
1437 // match, but not useful here.
1438 assert(errMsg);
1439 free(errMsg);
1440 errMsg = NULL;
1441 assert(errRtn);
1442 errRtn = NULL;
1443 // maybe there is more than one match, so continue loop
1445 }else{
1446 // really not a match, keep looking
1449 }else{untested();
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();
1458 internal_precalc();
1459 tr_accept();
1461 /*--------------------------------------------------------------------------*/
1462 void DEV_SPICE::do_ac()
1464 if (info.DEVacLoad || info.DEVpzLoad) {
1465 assert_instance();
1466 assert(_num_states >= 0);
1468 assert_model_unlocalized();
1469 _spice_model->_gen.GENinstances = &_spice_instance;
1470 assert_model_localized();
1472 localize_ckt();
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();
1491 // nothing
1494 assert_model_localized();
1495 _spice_model->_gen.GENinstances = NULL;
1496 assert_model_unlocalized();
1497 }else{untested();
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) {
1515 int ni = node[ii];
1516 if (ni && !ihit[ni]) {
1517 ihit[ni] = 1;
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) {
1522 int nj = node[jj];
1523 if (nj && jhit[nj] != ni) {
1524 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]);
1529 }else{
1530 trace2("skip", jj, nj);
1533 }else{
1534 trace2("=========skip", ii, ni);
1537 }else{
1538 // there is no acLoad function
1541 /*--------------------------------------------------------------------------*/
1542 /*--------------------------------------------------------------------------*/
1543 extern "C" {
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();
1551 free(ptr);
1552 }else{untested();
1556 static class FT_CURCKT : public circ {
1557 TSKtask junk;
1558 public:
1559 FT_CURCKT() {
1560 junk.jobs = NULL;
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;}
1601 struct Dderivs;
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
1615 #ifdef JSPICE3
1616 double Nintegrate(double, double, double, GENERIC*) {incomplete(); return NOT_VALID;} //DEVnoise
1617 #else
1618 double Nintegrate(double, double, double, Ndata*) {incomplete(); return NOT_VALID;} //DEVnoise
1619 #endif
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);
1627 double CONSTe(M_E);
1628 //------------------------------------------------
1629 // ngspice baggage
1630 int ARCHme = 0;
1631 // jspice baggage
1632 IFsimulator *ft_sim;
1633 //------------------------------------------------
1634 //------------------------------------------------
1635 int IFerror(int flags, char* format, IFuid* names) /* output an error or warning message */
1636 {itested();
1637 static struct mesg {
1638 const char *string;
1639 long flag;
1640 } msgs[] = {
1641 { "Warning", ERR_WARNING } ,
1642 { "Fatal error", ERR_FATAL } ,
1643 { "Panic", ERR_PANIC } ,
1644 { "Note", ERR_INFO } ,
1645 { NULL, 0 }
1648 struct mesg *m;
1649 char buf[10000], *s, *bptr;
1650 int nindex = 0;
1652 for (m = msgs; m->flag; m++) {
1653 if (flags & m->flag) {
1654 error(bDANGER, "%s: ", m->string);
1655 }else{
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]));
1663 }else{
1664 strcpy(bptr, "(null)");
1666 bptr += strlen(bptr);
1667 s++;
1668 nindex++;
1669 } else {
1670 *bptr++ = *s;
1673 *bptr = '\0';
1674 switch (flags) {
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;
1681 return 0;
1683 void internalerror(char *message)
1684 {untested();
1685 error(bDANGER, "internal error: %s\n", message);
1688 #ifdef NGSPICE_17
1689 int CKTinst2Node(void*, void*, int, CKTnode**, IFuid*)
1690 {untested();incomplete();
1691 return 10;
1693 #endif
1694 #ifdef JSPICE3
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
1700 NULL,
1701 NULL,
1702 NULL,
1703 NULL,
1704 NULL
1706 #else
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
1724 #endif
1725 IFfrontEnd* SPfrontEnd = &fe;
1726 //------------------------------------------------
1727 //------------------------------------------------
1728 int CKTsetBreak(CKTcircuit* ckt, double time)
1729 {untested();
1730 if (time < ckt->CKTminBreak) {untested();
1731 ckt->CKTminBreak = time;
1732 }else{untested();
1734 return OK;
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);
1751 assert(d);
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);
1761 METHOD method;
1762 if (ckt->CKTorder == 1) {
1763 method = mEULER;
1764 }else{
1765 assert(ckt->CKTtimePoints[1] != 0.);
1766 assert(ckt->CKTorder == 2);
1767 method = mTRAP;
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];
1777 q[ii].f1 = cap;
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];
1798 *geq = i[0].f1;
1799 assert(*ceq == *ceq);
1800 assert(*geq == *geq);
1801 trace2("", *ceq, *geq);
1802 return OK;
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);
1809 assert(n);
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
1815 return OK;
1817 int CKTmkCur(CKTcircuit* ckt, CKTnode** n, IFuid i, char* c)
1818 {untested();
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.
1826 return OK;
1828 //------------------------------------------------
1829 //------------------------------------------------
1830 double* SMPmakeElt(SMPmatrix* mm, int r, int c)
1831 { // returns a pointer m[r][c] -- used by DEVsetup
1832 //trace2("", r, c);
1833 assert(mm);
1834 if (r == 0 || c == 0) {
1835 static double trash;
1836 trash = 0;
1837 return &trash;
1838 }else{
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);
1844 assert(m);
1845 assert(m[r-OFFSET]);
1846 return reinterpret_cast<double*>(&(m[r-OFFSET][c-OFFSET]));
1849 //------------------------------------------------
1850 #ifdef JSPICE3
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;}
1868 #endif
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 {
1875 COMPLEX_TEST() {
1876 COMPLEX x;
1877 COMPLEX* px = &x;
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));
1883 ~COMPLEX_TEST() {
1885 } complex_test;
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: