Xyce  6.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
N_DEV_MOSFET2.C
Go to the documentation of this file.
1 //-----------------------------------------------------------------------------
2 // Copyright Notice
3 //
4 // Copyright 2002 Sandia Corporation. Under the terms
5 // of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S.
6 // Government retains certain rights in this software.
7 //
8 // Xyce(TM) Parallel Electrical Simulator
9 // Copyright (C) 2002-2014 Sandia Corporation
10 //
11 // This program is free software: you can redistribute it and/or modify
12 // it under the terms of the GNU General Public License as published by
13 // the Free Software Foundation, either version 3 of the License, or
14 // (at your option) any later version.
15 //
16 // This program is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 // GNU General Public License for more details.
20 //
21 // You should have received a copy of the GNU General Public License
22 // along with this program. If not, see <http://www.gnu.org/licenses/>.
23 //-----------------------------------------------------------------------------
24 
25 //-------------------------------------------------------------------------
26 // Filename : $RCSfile: N_DEV_MOSFET2.C,v $
27 //
28 // Purpose : Implement the MOSFET Level 2 model
29 //
30 // Special Notes :
31 //
32 // Creator : Eric R. Keiter, SNL, Parallel Computational Sciences
33 //
34 // Creation Date : 02/28/00
35 //
36 // Revision Information:
37 // ---------------------
38 //
39 // Revision Number: $Revision: 1.76 $
40 //
41 // Revision Date : $Date: 2014/05/22 17:40:30 $
42 //
43 // Current Owner : $Author: erkeite $
44 //-------------------------------------------------------------------------
45 #include <Xyce_config.h>
46 
47 // ---------- Standard Includes ----------
48 #ifdef HAVE_CMATH
49 #include <cmath>
50 #else
51 #include <math.h>
52 #endif
53 
54 // ---------- Xyce Includes ----------
55 #include <N_DEV_Const.h>
56 #include <N_DEV_DeviceOptions.h>
57 #include <N_DEV_ExternData.h>
58 #include <N_DEV_MOSFET2.h>
59 #include <N_DEV_MatrixLoadData.h>
60 #include <N_DEV_SolverState.h>
61 #include <N_DEV_Message.h>
62 #include <N_ERH_ErrorMgr.h>
63 
64 #include <N_DEV_MOSFET1.h>
65 
66 #include <N_LAS_Matrix.h>
67 #include <N_LAS_Vector.h>
68 
69 namespace Xyce {
70 namespace Device {
71 
72 
73 namespace MOSFET2 {
74 
75 
77 {
78 // Set up double precision variables:
79  p.addPar ("TEMP", 0.0, false, ParameterType::TIME_DEP,
81  STANDARD, CAT_NONE, "Device temperature");
82 
83  p.addPar ("L", 0.0, true, ParameterType::NO_DEP,
84  &MOSFET2::Instance::l, NULL,
85  U_METER, CAT_GEOMETRY, "Channel length");
86 
87  p.addPar ("W", 0.0, true, ParameterType::NO_DEP,
88  &MOSFET2::Instance::w, NULL,
89  U_METER, CAT_GEOMETRY, "Channel width");
90 
91  p.addPar ("AD", 0.0, false, ParameterType::NO_DEP,
93  U_METER2, CAT_GEOMETRY, "Drain diffusion area");
94 
95  p.addPar ("AS", 0.0, false, ParameterType::NO_DEP,
97  U_METER2, CAT_GEOMETRY, "Source diffusion area");
98 
99  p.addPar ("NRD", 1.0, false, ParameterType::NO_DEP,
101  U_SQUARES, CAT_GEOMETRY, "Multiplier for RSH to yield parasitic resistance of drain");
102 
103  p.addPar ("NRS", 1.0, false, ParameterType::NO_DEP,
105  U_SQUARES, CAT_GEOMETRY, "Multiplier for RSH to yield parasitic resistance of source");
106 
107  p.addPar ("PD", 0.0, false, ParameterType::NO_DEP,
109  U_METER, CAT_GEOMETRY, "Drain diffusion perimeter");
110 
111  p.addPar ("PS", 0.0, false, ParameterType::NO_DEP,
113  U_METER, CAT_GEOMETRY, "Source diffusion perimeter");
114 
115  p.addPar ("M", 1.0, false, ParameterType::NO_DEP,
117  U_NONE, CAT_CONTROL, "Multiplier for M devices connected in parallel");
118 
119  // Initial conditions
120  p.addPar ("IC1", 0.0, false, NO_DEP,
123  U_VOLT, CAT_INITIAL, "Initial condition on Drain-Source voltage");
124 
125  p.addPar ("IC2", 0.0, false, NO_DEP,
128  U_VOLT, CAT_INITIAL, "Initial condition on Gate-Source voltage");
129 
130  p.addPar ("IC3", 0.0, false, NO_DEP,
133  U_VOLT, CAT_INITIAL, "Initial condition on Bulk-Source voltage");
134 
135  p.makeVector ("IC",3);
136 
137  // Set up non-double precision variables:
138  p.addPar ("OFF",false,false, ParameterType::NO_DEP,
140  NULL, U_LOGIC, CAT_VOLT,
141  "Initial condition of no voltage drops across device");
142 }
143 
145 {
146  // Set up double precision variables:
147  p.addPar ("L", 1e-4, false, ParameterType::NO_DEP,
149  U_METER, CAT_GEOMETRY, "Default channel length");
150 
151  p.addPar ("W", 1e-4, false, ParameterType::NO_DEP,
153  U_METER, CAT_GEOMETRY, "Default channel width");
154 
155  p.addPar ("VTO", 0.0, false, ParameterType::NO_DEP,
156  &MOSFET2::Model::vt0, NULL,
157  U_VOLT, CAT_VOLT, "Zero-bias threshold voltage");
158 
159  p.addPar ("KP", 2e-5, false, ParameterType::NO_DEP,
161  U_AMPVM2, CAT_PROCESS, "Transconductance coefficient");
162 
163  p.addPar ("GAMMA", 0.0, false, ParameterType::NO_DEP,
164  &MOSFET2::Model::gamma, NULL,
165  U_VOLTH, CAT_PROCESS, "Bulk threshold parameter");
166 
167  p.addPar ("PHI", 0.6, false, ParameterType::NO_DEP,
168  &MOSFET2::Model::phi, NULL,
169  U_VOLT, CAT_PROCESS, "Surface potential");
170 
171  p.addPar ("LAMBDA", 0.0, false, ParameterType::NO_DEP,
172  &MOSFET2::Model::lambda, NULL,
173  U_VOLTM1, CAT_PROCESS, "Channel-length modulation");
174 
175  p.addPar ("RD", 0.0, false, ParameterType::MIN_RES,
177  U_OHM, CAT_RES, "Drain ohmic resistance");
178 
179  p.addPar ("RS", 0.0, false, ParameterType::MIN_RES,
181  U_OHM, CAT_RES, "Source ohmic resistance");
182 
183  p.addPar ("CBD", 0.0, false, ParameterType::MIN_CAP,
186  U_FARAD, CAT_CAP, "Zero-bias bulk-drain p-n capacitance");
187 
188  p.addPar ("CBS", 0.0, false, ParameterType::MIN_CAP,
191  U_FARAD, CAT_CAP, "Zero-bias bulk-source p-n capacitance");
192 
193  p.addPar ("IS", 1e-14, false, ParameterType::NO_DEP,
195  U_AMP, CAT_CURRENT, "Bulk p-n saturation current");
196 
197  p.addPar ("PB", 0.8, false, ParameterType::NO_DEP,
199  U_VOLT, CAT_VOLT, "Bulk p-n bottom potential");
200 
201  p.addPar ("CGSO", 0.0, false, ParameterType::NO_DEP,
203  U_FARADMM1, CAT_CAP, "Gate-source overlap capacitance/channel width");
204 
205  p.addPar ("CGDO", 0.0, false, ParameterType::NO_DEP,
207  U_FARADMM1, CAT_CAP, "Gate-drain overlap capacitance/channel width");
208 
209  p.addPar ("CGBO", 0.0, false, ParameterType::NO_DEP,
211  U_FARADMM1, CAT_CAP, "Gate-bulk overlap capacitance/channel length");
212 
213  p.addPar ("RSH", 0.0, false, ParameterType::NO_DEP,
215  U_OHM, CAT_RES, "Drain, source diffusion sheet resistance");
216 
217  p.addPar ("CJ", 0.0, false, ParameterType::NO_DEP,
220  U_FARADMM2, CAT_CAP, "Bulk p-n zero-bias bottom capacitance/area");
221 
222  p.addPar ("MJ", 0.5, false, ParameterType::NO_DEP,
224  U_NONE, CAT_DOPING, "Bulk p-n bottom grading coefficient");
225 
226  p.addPar ("CJSW", 0.0, false, ParameterType::NO_DEP,
229  U_FARADMM2, CAT_CAP, "Bulk p-n zero-bias sidewall capacitance/area");
230 
231  p.addPar ("MJSW", 0.5, false, ParameterType::NO_DEP,
233  U_NONE, CAT_DOPING, "Bulk p-n sidewall grading coefficient");
234 
235  p.addPar ("JS", 0.0,false, ParameterType::NO_DEP,
237  U_AMPMM2, CAT_PROCESS, "Bulk p-n saturation current density");
238 
239  p.addPar ("TOX", 1e-7, true, ParameterType::NO_DEP,
241  U_METER, CAT_GEOMETRY, "Gate oxide thickness");
242 
243  p.addPar ("LD", 0.0, false, ParameterType::NO_DEP,
245  U_METER, CAT_DOPING, "Lateral diffusion length");
246 
247  p.addPar ("UO", 600.0, false, ParameterType::NO_DEP,
249  U_CMM2VM1SM1, ParameterCategory(CAT_PROCESS | UNDOCUMENTED), "Surface mobility");
250 
251  p.addPar ("U0", 600.0, false, ParameterType::NO_DEP,
253  U_CMM2VM1SM1, CAT_PROCESS, "Surface mobility");
254 
255  p.addPar ("FC", 0.5, false, ParameterType::NO_DEP,
257  U_NONE, CAT_CAP, "Bulk p-n forward-bias capacitance coefficient");
258 
259  p.addPar ("NSUB", 0.0, false, ParameterType::NO_DEP,
261  U_CMM3, CAT_DOPING, "Substrate doping density");
262 
263  p.addPar ("NSS", 0.0, false, ParameterType::NO_DEP,
265  U_CMM2, CAT_PROCESS, "Surface state density");
266 
267 
268 // mos2 (vs mos1) params.
269  p.addPar ("DELTA", 0.0, false, ParameterType::NO_DEP,
271  U_NONE, CAT_NONE, "Width effect on threshold");
272 
273  p.addPar ("UEXP", 0.0, false, ParameterType::NO_DEP,
275  U_NONE, CAT_NONE, "Crit. field exp for mob. deg.");
276 
277  p.addPar ("UCRIT", 1.0e4, false, ParameterType::NO_DEP,
279  U_NONE, CAT_NONE, "Crit. field for mob. degradation");
280 
281  p.addPar ("VMAX", 0.0, false, ParameterType::NO_DEP,
283  U_NONE, CAT_NONE, "Maximum carrier drift velocity");
284 
285  p.addPar ("XJ", 0.0, false, ParameterType::NO_DEP,
287  U_NONE, CAT_NONE, "Junction depth");
288 
289  p.addPar ("NEFF", 1.0, false, ParameterType::NO_DEP,
291  U_NONE, CAT_NONE, "Total channel charge coeff.");
292 
293  p.addPar ("NFS", 0.0, false, ParameterType::NO_DEP,
295  U_NONE, CAT_NONE, "Fast surface state density");
296 
297 // end of mos2 (vs mos1) params.
298 
299  p.addPar ("TNOM", 27.0, false, ParameterType::NO_DEP,
300  &MOSFET2::Model::tnom, NULL,
301  STANDARD, CAT_NONE, "");
302 
303  p.addPar ("KF", 0.0, false, ParameterType::NO_DEP,
304  &MOSFET2::Model::fNcoef, NULL,
305  U_NONE, CAT_FLICKER, "Flicker noise coefficient");
306 
307  p.addPar ("AF", 1.0, false, ParameterType::NO_DEP,
308  &MOSFET2::Model::fNexp, NULL,
309  U_NONE, CAT_FLICKER, "Flicker noise exponent");
310 
311  // Set up non-double precision variables:
312  p.addPar ("TPG", 0, false, ParameterType::NO_DEP,
314  U_NONE, CAT_MATERIAL, "Gate material type (-1 = same as substrate,"
315  " 0 = aluminum, 1 = opposite of substrate)");
316 
318 }
319 
320 
321 
322 std::vector< std::vector<int> > Instance::jacStamp_DC_SC;
323 std::vector< std::vector<int> > Instance::jacStamp_DC;
324 std::vector< std::vector<int> > Instance::jacStamp_SC;
325 std::vector< std::vector<int> > Instance::jacStamp;
326 
327 std::vector<int> Instance::jacMap_DC_SC;
328 std::vector<int> Instance::jacMap_DC;
329 std::vector<int> Instance::jacMap_SC;
330 std::vector<int> Instance::jacMap;
331 
332 std::vector< std::vector<int> > Instance::jacMap2_DC_SC;
333 std::vector< std::vector<int> > Instance::jacMap2_DC;
334 std::vector< std::vector<int> > Instance::jacMap2_SC;
335 std::vector< std::vector<int> > Instance::jacMap2;
336 
337 
338 // Class Instance
339 //-----------------------------------------------------------------------------
340 // Function : Instance::processParams
341 // Purpose :
342 // Special Notes :
343 // Scope : public
344 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
345 // Creation Date : 6/03/02
346 //-----------------------------------------------------------------------------
348 {
349 
350  // now set the temperature related stuff
352 
353  return true;
354 }
355 
356 //-----------------------------------------------------------------------------
357 // Function : Instance::Instance
358 // Purpose : instance block constructor
359 // Special Notes :
360 // Scope : public
361 // Creator : Eric Keiter
362 // Creation Date : 3/21/01
363 //-----------------------------------------------------------------------------
365  const Configuration & configuration,
366  const InstanceBlock & IB,
367  Model & Miter,
368  const FactoryBlock & factory_block)
369  : DeviceInstance(IB, configuration.getInstanceParameters(), factory_block),
370  model_(Miter),
371  dNode(0),
372  gNode(0),
373  sNode(0),
374  bNode(0),
375  dNodePrime(0),
376  sNodePrime(0),
377  l(getDeviceOptions().defl),
378  w(getDeviceOptions().defw),
379  OFF(false),
380  drainArea(getDeviceOptions().defad),
381  sourceArea(getDeviceOptions().defas),
382  drainSquares(1.0),
383  sourceSquares(1.0),
384  drainPerimeter(0.0),
385  sourcePerimeter(0.0),
386  sourceConductance(0.0),
387  drainConductance(0.0),
388  temp(getDeviceOptions().temp.getImmutableValue<double>()),
389  numberParallel(1),
390  tTransconductance(0.0),
391  tSurfMob(0.0),
392  tPhi(0.0),
393  tVto(0.0),
394  tSatCur(0.0),
395  tSatCurDens(0.0),
396  tCbd(0.0),
397  tCbs(0.0),
398  tCj(0.0),
399  tCjsw(0.0),
400  tBulkPot(0.0),
401  tDepCap(0.0),
402  tVbi(0.0),
403  icVBS(0.0),
404  icVDS(0.0),
405  icVGS(0.0),
406  von(0.0),
407  vdsat(0.0),
408  sourceVcrit(0.0),
409  drainVcrit(0.0),
410  cd(0.0),
411  cbs(0.0),
412  cbd(0.0),
413  gmbs(0.0),
414  gm(0.0),
415  gds(0.0),
416  gbd(0.0),
417  gbs(0.0),
418  capbd(0.0),
419  capbs(0.0),
420  Cbd(0.0),
421  Cbdsw(0.0),
422  Cbs(0.0),
423  Cbssw(0.0),
424  f2d(0.0),
425  f3d(0.0),
426  f4d(0.0),
427  f2s(0.0),
428  f3s(0.0),
429  f4s(0.0),
430  mode(1),
431  mode_low(0.0),
432  mode_high(0.0),
433  limitedFlag(false),
434  IC_GIVEN(false),
435  Idrain(0.0),
436  Isource(0.0),
437  //calculated quantities
438  EffectiveLength(0),
439  DrainSatCur(0),
440  SourceSatCur(0),
441  GateSourceOverlapCap(0),
442  GateDrainOverlapCap(0),
443  GateBulkOverlapCap(0),
444  OxideCap(0),
445  // solution vector:
446  // local indices
447  li_Drain(-1),
448  li_DrainPrime(-1),
449  li_Source(-1),
450  li_SourcePrime(-1),
451  li_Gate(-1),
452  li_Bulk(-1),
453  // matrix and vector pointers:
454  // jacobian:
455  // drain row
456  ADrainEquDrainNodeOffset(-1),
457  ADrainEquDrainPrimeNodeOffset(-1),
458  // gate row
459  AGateEquGateNodeOffset(-1),
460  AGateEquBulkNodeOffset(-1),
461  AGateEquDrainPrimeNodeOffset(-1),
462  AGateEquSourcePrimeNodeOffset(-1),
463  // source row
464  ASourceEquSourceNodeOffset(-1),
465  ASourceEquSourcePrimeNodeOffset(-1),
466  // bulk row
467  ABulkEquGateNodeOffset(-1),
468  ABulkEquBulkNodeOffset(-1),
469  ABulkEquDrainPrimeNodeOffset(-1),
470  ABulkEquSourcePrimeNodeOffset(-1),
471  // drain' row
472  ADrainPrimeEquDrainNodeOffset(-1),
473  ADrainPrimeEquGateNodeOffset(-1),
474  ADrainPrimeEquBulkNodeOffset(-1),
475  ADrainPrimeEquDrainPrimeNodeOffset(-1),
476  ADrainPrimeEquSourcePrimeNodeOffset(-1),
477  // source' row
478  ASourcePrimeEquGateNodeOffset(-1),
479  ASourcePrimeEquSourceNodeOffset(-1),
480  ASourcePrimeEquBulkNodeOffset(-1),
481  ASourcePrimeEquDrainPrimeNodeOffset(-1),
482  ASourcePrimeEquSourcePrimeNodeOffset(-1),
483 
485  // F-vector pointers:
486  // V_d Row:
487  f_DrainEquDrainNodePtr(0), // a
488  f_DrainEquDrainPrimeNodePtr(0), // b
489  // V_g Row:
490  f_GateEquGateNodePtr(0), // c
491  f_GateEquBulkNodePtr(0), // d
492  f_GateEquDrainPrimeNodePtr(0), // e
493  f_GateEquSourcePrimeNodePtr(0), // f
494  // V_s Row:
495  f_SourceEquSourceNodePtr(0), // g
496  f_SourceEquSourcePrimeNodePtr(0), // h
497  // V_b Row:
498  f_BulkEquGateNodePtr(0), // i
499  f_BulkEquBulkNodePtr(0), // j
500  f_BulkEquDrainPrimeNodePtr(0), // k
501  f_BulkEquSourcePrimeNodePtr(0), // l
502  // V_d' Row:
503  f_DrainPrimeEquDrainNodePtr(0), // m
504  f_DrainPrimeEquGateNodePtr(0), // n
505  f_DrainPrimeEquBulkNodePtr(0), // o
506  f_DrainPrimeEquDrainPrimeNodePtr(0), // p
507  f_DrainPrimeEquSourcePrimeNodePtr(0), // q
508  // V_s' Row:
509  f_SourcePrimeEquGateNodePtr(0), // r
510  f_SourcePrimeEquSourceNodePtr(0), // s
511  f_SourcePrimeEquBulkNodePtr(0), // t
512  f_SourcePrimeEquDrainPrimeNodePtr(0), // u
513  f_SourcePrimeEquSourcePrimeNodePtr(0), // v
514  // Q-vector pointers:
515  // V_d Row:
516  q_DrainEquDrainNodePtr(0), // a
517  q_DrainEquDrainPrimeNodePtr(0), // b
518  // V_g Row:
519  q_GateEquGateNodePtr(0), // c
520  q_GateEquBulkNodePtr(0), // d
521  q_GateEquDrainPrimeNodePtr(0), // e
522  q_GateEquSourcePrimeNodePtr(0), // f
523  // V_s Row:
524  q_SourceEquSourceNodePtr(0), // g
525  q_SourceEquSourcePrimeNodePtr(0), // h
526  // V_b Row:
527  q_BulkEquGateNodePtr(0), // i
528  q_BulkEquBulkNodePtr(0), // j
529  q_BulkEquDrainPrimeNodePtr(0), // k
530  q_BulkEquSourcePrimeNodePtr(0), // l
531  // V_d' Row:
532  q_DrainPrimeEquDrainNodePtr(0), // m
533  q_DrainPrimeEquGateNodePtr(0), // n
534  q_DrainPrimeEquBulkNodePtr(0), // o
535  q_DrainPrimeEquDrainPrimeNodePtr(0), // p
536  q_DrainPrimeEquSourcePrimeNodePtr(0), // q
537  // V_s' Row:
538  q_SourcePrimeEquGateNodePtr(0), // r
539  q_SourcePrimeEquSourceNodePtr(0), // s
540  q_SourcePrimeEquBulkNodePtr(0), // t
541  q_SourcePrimeEquDrainPrimeNodePtr(0), // u
542  q_SourcePrimeEquSourcePrimeNodePtr(0), // v
543 #endif
544 
545  vbd(0.0),
546  vbs(0.0),
547  vgs(0.0),
548  vds(0.0),
549  vbd_old(0.0),
550  vbs_old(0.0),
551  vgs_old(0.0),
552  vds_old(0.0),
553  vbd_orig(0.0),
554  vbs_orig(0.0),
555  vgs_orig(0.0),
556  vds_orig(0.0),
557  capgs(0.0),
558  qgs(0.0),
559  //cqgs(0.0),
560  capgd(0.0),
561  qgd(0.0),
562  //cqgd(0.0),
563  capgb(0.0),
564  qgb(0.0),
565  //cqgb(0.0),
566  qbd(0.0),
567  //cqbd(0.0),
568  qbs(0.0),
569  //cqbs(0.0),
570  // local indices
571  li_store_vbd(-1),
572  li_store_vbs(-1),
573  li_store_vgs(-1),
574  li_store_vds(-1),
575  li_store_von(-1),
576  li_store_dev_id(-1),
577  li_store_dev_is(-1),
578  li_store_dev_ig(-1),
579  li_store_dev_ib(-1),
580  li_state_qgs(-1),
581  li_state_qgd(-1),
582  li_state_qgb(-1),
583  li_state_capgs(-1),
584  li_state_capgd(-1),
585  li_state_capgb(-1),
586  li_state_qbd(-1),
587  li_state_qbs(-1),
588  blockHomotopyID(0),
589  randomPerturb(0.0)
590 {
591  numIntVars = 2;
592  numExtVars = 4;
593 
594  setNumStoreVars(5);
595  numLeadCurrentStoreVars = 4; // drain, gate, source & base lead currents
596  numStateVars = 8;
597 
598  devConMap.resize(4);
599  devConMap[0] = 1;
600  devConMap[1] = 2;
601  devConMap[2] = 1;
602  devConMap[3] = 3;
603 
605  devSupport.getGainScaleBlockID(getDeviceOptions().numGainScaleBlocks);
606  randomPerturb =
608 
609  if( jacStamp.empty() )
610  {
611  // stamp for RS!=0, RD!=0
612  jacStamp_DC_SC.resize(6);
613  jacStamp_DC_SC[0].resize(2); // Drain row
614  jacStamp_DC_SC[0][0]=0; // d-d
615  jacStamp_DC_SC[0][1]=4; // d-d'
616  jacStamp_DC_SC[1].resize(4); // Gate row
617  jacStamp_DC_SC[1][0]=1; // g-g
618  jacStamp_DC_SC[1][1]=3; // g-b
619  jacStamp_DC_SC[1][2]=4; // g-d'
620  jacStamp_DC_SC[1][3]=5; // g-s'
621  jacStamp_DC_SC[2].resize(2); // Source row
622  jacStamp_DC_SC[2][0]=2; // s-s
623  jacStamp_DC_SC[2][1]=5; // s-s'
624  jacStamp_DC_SC[3].resize(4); // Bulk row
625  jacStamp_DC_SC[3][0]=1; // b-g
626  jacStamp_DC_SC[3][1]=3; // b-b
627  jacStamp_DC_SC[3][2]=4; // b-d'
628  jacStamp_DC_SC[3][3]=5; // b-s'
629  jacStamp_DC_SC[4].resize(5); // Drain' row
630  jacStamp_DC_SC[4][0]=0; // d'-d
631  jacStamp_DC_SC[4][1]=1; // d'-g
632  jacStamp_DC_SC[4][2]=3; // d'-b
633  jacStamp_DC_SC[4][3]=4; // d'-d'
634  jacStamp_DC_SC[4][4]=5; // d'-s'
635  jacStamp_DC_SC[5].resize(5); // Source' row
636  jacStamp_DC_SC[5][0]=1; // s'-g
637  jacStamp_DC_SC[5][1]=2; // s'-s
638  jacStamp_DC_SC[5][2]=3; // s'-b
639  jacStamp_DC_SC[5][3]=4; // s'-d'
640  jacStamp_DC_SC[5][4]=5; // s'-s'
641 
642  jacMap_DC_SC.clear();
644  jacStamp_DC, jacMap_DC, jacMap2_DC, 5, 2, 6);
645 
647  jacStamp_SC, jacMap_SC, jacMap2_SC, 4, 0, 6);
648 
650  jacStamp, jacMap, jacMap2, 4, 0, 6);
651 
652  }
653 
654 
655  // Set params to constant default values:
656  setDefaultParams ();
657 
658  // Set params according to instance line and constant defaults from metadata:
659  setParams (IB.params);
660 
661  // Set any non-constant parameter defaults:
662  if (!given("TEMP"))
663  temp = getDeviceOptions().temp.getImmutableValue<double>();
664  if (!given("L"))
665  l =model_.model_l;
666  if (!given("W"))
667  w = model_.model_w;
668 
669  // process source/drain series resistance (from mos1temp)
670  if(model_.drainResistance != 0.0)
671  {
673  }
674  else if (model_.given("RSH"))
675  {
676  if(model_.sheetResistance != 0.0)
677  {
680  }
681  else
682  {
683  drainConductance = 0.0;
684  }
685  }
686  else
687  {
688  drainConductance = 0.0;
689  }
690  if(model_.sourceResistance != 0.0)
691  {
693  }
694  else if (model_.given("RSH"))
695  {
696  if(model_.sheetResistance != 0.0)
697  {
700  }
701  else
702  {
703  sourceConductance = 0.0;
704  }
705  }
706  else
707  {
708  sourceConductance = 0.0;
709  }
710 
711  if (!given("AD"))
713  if (!given("AS"))
715 
716  // Calculate any parameters specified as expressions:
717 
719 
720  // calculate dependent (ie computed) params and check for errors:
721 
722  if(l - 2 * model_.latDiff <=0)
723  {
724  UserError0(*this) << "Effective channel length less than zero.";
725  }
726 
732 
733  numIntVars = (((sourceConductance == 0.0)?0:1)+((drainConductance == 0.0) ? 0:1));
734 
735 #ifdef Xyce_DEBUG_DEVICE
737  {
738  Xyce::dout() << ": name = " << getName() << std::endl;
739  Xyce::dout() << ": sourceConductance = " << sourceConductance << std::endl;
740  Xyce::dout() << ": drainConductance = " << drainConductance << std::endl;
741  }
742 
743 #endif
744 
745  processParams ();
746 }
747 
748 //-----------------------------------------------------------------------------
749 // Function : Instance::~Instance
750 // Purpose : destructor
751 // Special Notes :
752 // Scope : public
753 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
754 // Creation Date : 3/16/00
755 //-----------------------------------------------------------------------------
757 {
758 }
759 
760 //-----------------------------------------------------------------------------
761 // Function : Instance::registerLIDs
762 // Purpose :
763 // Special Notes :
764 // Scope : public
765 // Creator : Robert Hoekstra, Computational Sciences
766 // Creation Date : 6/21/02
767 //-----------------------------------------------------------------------------
768 void Instance::registerLIDs( const std::vector<int> & intLIDVecRef,
769  const std::vector<int> & extLIDVecRef )
770 {
771  numIntVars = (((sourceConductance == 0.0)?0:1)+((drainConductance == 0.0) ? 0:1));
772 
773  AssertLIDs(intLIDVecRef.size() == numIntVars);
774  AssertLIDs(extLIDVecRef.size() == numExtVars);
775 
776 #ifdef Xyce_DEBUG_DEVICE
777  if (getDeviceOptions().debugLevel > 0)
778  {
779  Xyce::dout() << section_divider << std::endl;
780  Xyce::dout() << " In Instance::register LIDs\n\n";
781  Xyce::dout() << " name = " << getName() << std::endl;
782  Xyce::dout() << " number of internal variables: " << numIntVars << std::endl;
783  Xyce::dout() << " number of external variables: " << numExtVars << std::endl;
784  }
785 #endif
786 
787  // copy over the global ID lists.
788  intLIDVec = intLIDVecRef;
789  extLIDVec = extLIDVecRef;
790 
791  // now use these lists to obtain the indices into the
792  // linear algebra entities. This assumes an order.
793  // For the matrix indices, first do the rows.
794 
795  li_Drain = extLIDVec[0];
796  li_Gate = extLIDVec[1];
797  li_Source = extLIDVec[2];
798  li_Bulk = extLIDVec[3];
799 
800  int intLoc = 0;
801 
802  if( drainConductance )
803  li_DrainPrime = intLIDVec[intLoc++];
804  else
806 
807  if( sourceConductance )
808  li_SourcePrime = intLIDVec[intLoc];
809  else
811 
812 #ifdef Xyce_DEBUG_DEVICE
813  if (getDeviceOptions().debugLevel > 0)
814  {
815  Xyce::dout() << "\n variable local indices:\n";
816  Xyce::dout() << " li_Drain = " << li_Drain << std::endl;
817  Xyce::dout() << " li_DrainPrime = " << li_DrainPrime << std::endl;
818  Xyce::dout() << " li_Source = " << li_Source << std::endl;
819  Xyce::dout() << " li_SourcePrime = " << li_SourcePrime << std::endl;
820  Xyce::dout() << " li_Gate = " << li_Gate << std::endl;
821  Xyce::dout() << " li_Bulk = " << li_Bulk << std::endl;
822 
823  Xyce::dout() << section_divider << std::endl;
824  }
825 #endif
826 
827 }
828 
829 //-----------------------------------------------------------------------------
830 // Function : Instance::getIntNameMap
831 // Purpose :
832 // Special Notes :
833 // Scope : public
834 // Creator : Eric R. Keiter, SNL, Parallel Computational Sciences
835 // Creation Date : 05/13/05
836 //-----------------------------------------------------------------------------
837 std::map<int,std::string> & Instance::getIntNameMap ()
838 {
839  // set up the internal name map, if it hasn't been already.
840  if (intNameMap.empty ())
841  {
842  if ( li_DrainPrime != li_Drain )
843  {
844  intNameMap[ li_DrainPrime ] = spiceInternalName(getName(), "drainprime");
845  }
846 
847  if ( li_SourcePrime != li_Source )
848  {
849  intNameMap[ li_SourcePrime ] = spiceInternalName(getName(), "sourceprime");
850  }
851  }
852 
853  return intNameMap;
854 }
855 
856 
857 //-----------------------------------------------------------------------------
858 // Function : N_DEV_MOSFET2Instance::getStoreNameMap
859 // Purpose :
860 // Special Notes :
861 // Scope : public
862 // Creator : Richard Schiek, Electrical Systems Modeling
863 // Creation Date : 4/3/2013
864 //-----------------------------------------------------------------------------
865 std::map<int,std::string> & N_DEV_MOSFET2Instance::getStoreNameMap ()
866 {
867  // set up the internal name map, if it hasn't been already.
868  if( loadLeadCurrent && storeNameMap.empty ())
869  {
870  storeNameMap[ li_store_dev_id ] = spiceStoreName(getName(), "DEV_ID");
871  storeNameMap[ li_store_dev_is ] = spiceStoreName(getName(), "DEV_IS");
872  storeNameMap[ li_store_dev_ig ] = spiceStoreName(getName(), "DEV_IG");
873  storeNameMap[ li_store_dev_ib ] = spiceStoreName(getName(), "DEV_IB");
874  }
875 
876  return storeNameMap;
877 }
878 
879 //-----------------------------------------------------------------------------
880 // Function : Instance::registerStateLIDs
881 // Purpose :
882 // Special Notes :
883 // Scope : public
884 // Creator : Robert Hoekstra, Computational Sciences
885 // Creation Date : 6/21/02
886 //-----------------------------------------------------------------------------
887 void Instance::registerStateLIDs( const std::vector<int> & staLIDVecRef )
888 {
889  AssertLIDs(staLIDVecRef.size() == numStateVars);
890 
891 #ifdef Xyce_DEBUG_DEVICE
892  if (getDeviceOptions().debugLevel > 0)
893  {
894  Xyce::dout() << std::endl;
895  Xyce::dout() << section_divider << std::endl;
896  Xyce::dout() << " In Instance::registerStateLIDs\n\n";
897  Xyce::dout() << " name = " << getName() << std::endl;
898  Xyce::dout() << " Number of State LIDs: " << numStateVars << std::endl;
899  }
900 #endif
901 
902  // Copy over the global ID lists:
903  staLIDVec = staLIDVecRef;
904 
905  int lid=0;
906 
907  li_state_qgs = staLIDVec[lid++];
908  li_state_qgd = staLIDVec[lid++];
909  li_state_qgb = staLIDVec[lid++];
910 
911  li_state_capgs = staLIDVec[lid++];
912  li_state_capgd = staLIDVec[lid++];
913  li_state_capgb = staLIDVec[lid++];
914 
915  li_state_qbd = staLIDVec[lid++];
916  li_state_qbs = staLIDVec[lid++];
917 
918 
919 #ifdef Xyce_DEBUG_DEVICE
920  if (getDeviceOptions().debugLevel > 0)
921  {
922  Xyce::dout() << " State local indices:" << std::endl;
923  Xyce::dout() << std::endl;
924 
925  Xyce::dout() << " li_state_qgs = " << li_state_qgs ;
926  Xyce::dout() << " li_state_capgs = " << li_state_capgs;
927  Xyce::dout() << " li_state_capgd = " << li_state_capgd;
928  Xyce::dout() << " li_state_capgb = " << li_state_capgb;
929  Xyce::dout() << " li_state_qgd = " << li_state_qgd;
930  Xyce::dout() << " li_state_qgb = " << li_state_qgb;
931  Xyce::dout() << " li_state_qbs = " << li_state_qbs;
932  Xyce::dout() << " li_state_qbd = " << li_state_qbd;
933 
934  Xyce::dout() << std::endl;
935  Xyce::dout() << section_divider << std::endl;
936  }
937 #endif
938 
939 }
940 
941 //-----------------------------------------------------------------------------
942 // Function : Instance::registerStoreLIDs
943 // Purpose :
944 // Special Notes :
945 // Scope : public
946 // Creator : Eric Keiter, Computational Sciences
947 // Creation Date : 12/9/11
948 //-----------------------------------------------------------------------------
949 void Instance::registerStoreLIDs( const std::vector<int> & stoLIDVecRef )
950 {
951  AssertLIDs(stoLIDVecRef.size() == getNumStoreVars());
952 
953  // Copy over the global ID lists:
954  stoLIDVec = stoLIDVecRef;
955 
956  int lid=0;
957  li_store_vbd = stoLIDVec[lid++];
958  li_store_vbs = stoLIDVec[lid++];
959  li_store_vgs = stoLIDVec[lid++];
960  li_store_vds = stoLIDVec[lid++];
961  li_store_von = stoLIDVec[lid++];
962 
963  if( loadLeadCurrent )
964  {
965  li_store_dev_id = stoLIDVec[lid++];
966  li_store_dev_ig = stoLIDVec[lid++];
967  li_store_dev_is = stoLIDVec[lid++];
968  li_store_dev_ib = stoLIDVec[lid++];
969  }
970 }
971 
972 //-----------------------------------------------------------------------------
973 // Function : Instance::jacobianStamp
974 // Purpose :
975 // Special Notes :
976 // Scope : public
977 // Creator : Robert Hoekstra, Computational Sciences
978 // Creation Date : 9/3/02
979 //-----------------------------------------------------------------------------
980 const std::vector< std::vector<int> > & Instance::jacobianStamp() const
981 {
982  if( drainConductance != 0.0 && sourceConductance != 0.0 )
983  return jacStamp_DC_SC;
984  else if( drainConductance != 0.0 && sourceConductance == 0.0 )
985  return jacStamp_DC;
986  else if( drainConductance == 0.0 && sourceConductance != 0.0 )
987  return jacStamp_SC;
988 
989  return jacStamp;
990 }
991 
992 //-----------------------------------------------------------------------------
993 // Function : Instance::registerJacLIDs
994 // Purpose :
995 // Special Notes :
996 // Scope : public
997 // Creator : Robert Hoekstra, Computational Sciences
998 // Creation Date : 9/3/02
999 //-----------------------------------------------------------------------------
1000 void Instance::registerJacLIDs( const std::vector< std::vector<int> > & jacLIDVec )
1001 {
1002  DeviceInstance::registerJacLIDs( jacLIDVec );
1003  std::vector<int> map;
1004  std::vector< std::vector<int> > map2;
1005 
1006  if (drainConductance != 0.0)
1007  {
1008  if (sourceConductance != 0.0)
1009  {
1010  map = jacMap_DC_SC;
1011  map2 = jacMap2_DC_SC;
1012  }
1013  else
1014  {
1015  map = jacMap_DC;
1016  map2 = jacMap2_DC;
1017  }
1018  }
1019  else
1020  {
1021  if (sourceConductance != 0.0)
1022  {
1023  map = jacMap_SC;
1024  map2 = jacMap2_SC;
1025  }
1026  else
1027  {
1028  map = jacMap;
1029  map2 = jacMap2;
1030  }
1031  }
1032  ADrainEquDrainNodeOffset = jacLIDVec[map[0]][map2[0][0]];
1033  ADrainEquDrainPrimeNodeOffset = jacLIDVec[map[0]][map2[0][1]];
1034 
1035  AGateEquGateNodeOffset = jacLIDVec[map[1]][map2[1][0]];
1036  AGateEquBulkNodeOffset = jacLIDVec[map[1]][map2[1][1]];
1037  AGateEquDrainPrimeNodeOffset = jacLIDVec[map[1]][map2[1][2]];
1038  AGateEquSourcePrimeNodeOffset = jacLIDVec[map[1]][map2[1][3]];
1039 
1040  ASourceEquSourceNodeOffset = jacLIDVec[map[2]][map2[2][0]];
1041  ASourceEquSourcePrimeNodeOffset = jacLIDVec[map[2]][map2[2][1]];
1042 
1043  ABulkEquGateNodeOffset = jacLIDVec[map[3]][map2[3][0]];
1044  ABulkEquBulkNodeOffset = jacLIDVec[map[3]][map2[3][1]];
1045  ABulkEquDrainPrimeNodeOffset = jacLIDVec[map[3]][map2[3][2]];
1046  ABulkEquSourcePrimeNodeOffset = jacLIDVec[map[3]][map2[3][3]];
1047 
1048  ADrainPrimeEquDrainNodeOffset = jacLIDVec[map[4]][map2[4][0]];
1049  ADrainPrimeEquGateNodeOffset = jacLIDVec[map[4]][map2[4][1]];
1050  ADrainPrimeEquBulkNodeOffset = jacLIDVec[map[4]][map2[4][2]];
1051  ADrainPrimeEquDrainPrimeNodeOffset = jacLIDVec[map[4]][map2[4][3]];
1052  ADrainPrimeEquSourcePrimeNodeOffset = jacLIDVec[map[4]][map2[4][4]];
1053 
1054  ASourcePrimeEquGateNodeOffset = jacLIDVec[map[5]][map2[5][0]];
1055  ASourcePrimeEquSourceNodeOffset = jacLIDVec[map[5]][map2[5][1]];
1056  ASourcePrimeEquBulkNodeOffset = jacLIDVec[map[5]][map2[5][2]];
1057  ASourcePrimeEquDrainPrimeNodeOffset = jacLIDVec[map[5]][map2[5][3]];
1058  ASourcePrimeEquSourcePrimeNodeOffset = jacLIDVec[map[5]][map2[5][4]];
1059 }
1060 
1061 //-----------------------------------------------------------------------------
1062 // Function : Instance::setupPointers
1063 // Purpose :
1064 // Special Notes :
1065 // Scope : public
1066 // Creator : Eric Keiter, SNL
1067 // Creation Date : 12/06/08
1068 //-----------------------------------------------------------------------------
1070 {
1071 #ifndef Xyce_NONPOINTER_MATRIX_LOAD
1072  N_LAS_Matrix & dFdx = *(extData.dFdxMatrixPtr);
1073  N_LAS_Matrix & dQdx = *(extData.dQdxMatrixPtr);
1074 
1075  // F-pointers:
1078 
1083 
1086 
1091 
1097 
1103 
1104  // Q-pointers:
1107 
1112 
1115 
1120 
1126 
1132 #endif
1133 }
1134 
1135 //-----------------------------------------------------------------------------
1136 // Function : Instance::loadDAEQVector
1137 //
1138 // Purpose : Loads the Q-vector contributions for a single
1139 // diode instance.
1140 //
1141 // Special Notes : The "Q" vector is part of a standard DAE formalism in
1142 // which the system of equations is represented as:
1143 //
1144 // f(x) = dQ(x)/dt + F(x) - B(t) = 0
1145 //
1146 // This is similar to the loadRHS function, only this function
1147 // only loads capacitor charges, and loads them into the daeQ vector.
1148 //
1149 // Scope : public
1150 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1151 // Creation Date : 03/06/04
1152 //-----------------------------------------------------------------------------
1154 {
1155  double * qVec = extData.daeQVectorRawPtr;
1156  double coef(0.0);
1157 
1158  double Qeqbs(0.0),Qeqbd(0.0),Qeqgb(0.0), Qeqgs(0.0), Qeqgd(0.0);
1159  //double ceqbs,ceqbd,ceqgb, ceqgs, ceqgd; // 3f5 vars
1160  int Dtype=model_.dtype;
1161 
1162  // do the same Dtype corrections on the charges that
1163  // are performed on the currents in the loadRHS function.
1164 
1165  // What is cbs and cbd? They are diode currents (from exponentials),
1166  // so they are left out of this function.
1167  Qeqbs = Dtype*(qbs);
1168  Qeqbd = Dtype*(qbd);
1169  // These need "Dtype" here because we use them later *without*
1170  // Dtype, where SPICE uses it *with*
1171  Qeqgb = Dtype*(qgb);
1172  Qeqgs = Dtype*(qgs);
1173  Qeqgd = Dtype*(qgd);
1174 
1175  // 2 KCL for gate node
1176  coef = (Qeqgs+Qeqgd+Qeqgb);
1177  qVec[li_Gate] += coef*numberParallel;
1178 
1179  // 4 KCL for bulk node
1180  coef = Qeqbs + Qeqbd - Qeqgb;
1181  qVec[li_Bulk] += coef*numberParallel;
1182 
1183  // 5 KCL for drain' node
1184  coef = -(Qeqbd + Qeqgd);
1185  qVec[li_DrainPrime] += coef*numberParallel;
1186 
1187  // 6 KCL for source' node
1188  coef = -(Qeqbs + Qeqgs);
1189  qVec[li_SourcePrime] += coef*numberParallel;
1190 
1191  // Same as for the loadRHS function, but with capacitive terms:
1192  // gcgd = Capgd;
1193  // gcgs = Capgs;
1194  // gcgb = Capgb;
1195  // gcbs = capbs;
1196  // gcbd = capbd;
1197 
1198  if( loadLeadCurrent )
1199  {
1200  double * storeLeadQ = extData.storeLeadCurrQCompRawPtr;
1201  if (drainConductance == 0.0)
1202  {
1203  storeLeadQ[li_store_dev_id] = (-(Qeqbd + Qeqgd))*numberParallel;
1204  }
1205  if (sourceConductance == 0.0)
1206  {
1207  storeLeadQ[li_store_dev_is] = (-(Qeqbs + Qeqgs))*numberParallel;
1208  }
1209  storeLeadQ[li_store_dev_ig] = (Qeqgs+Qeqgd+Qeqgb)*numberParallel;
1210  storeLeadQ[li_store_dev_ib] = (Qeqbs + Qeqbd - Qeqgb)*numberParallel;
1211  }
1212 
1213  if(!origFlag)
1214  {
1215  // THe setup of gcgd, etc. is the same as in the loadDAEdQdxVector
1216  // function.
1217  double gcgd, gcgs, gcgb, gcbs, gcbd;
1219  {
1220  gcgd = Capgd;
1221  gcgs = Capgs;
1222  gcgb = Capgb;
1223  // get at the two parasitic caps the same way
1224  gcbs = capbs;
1225  gcbd = capbd;
1226  }
1227  else
1228  {
1229  gcgd = 0.0; gcgs = 0.0; gcgb = 0.0; gcbs = 0.0; gcbd = 0.0;
1230  }
1231 
1232  // KCL 2
1233  double coef_Jdxp2 = Dtype*(gcgd*(vgd-vgd_orig)+gcgs*(vgs-vgs_orig)+
1234  gcgb*(vgs-vgs_orig-vbs+vbs_orig));
1235 
1236  // 4 KCL for bulk node
1237  double coef_Jdxp4 = Dtype*(
1238  - (gcgb)*(vgs-vgs_orig-vbs+vbs_orig)
1239  + (gcgb)*(vbd-vbd_orig)
1240  + (gcbs)*(vbs-vbs_orig));
1241 
1242  // 5 KCL for drain' node
1243  double coef_Jdxp5 = Dtype*(
1244  -(gcgd)*(vgd-vgd_orig)
1245  -(gcbd)*(vbd-vbd_orig));
1246 
1247  // 6 KCL for source' node
1248  double coef_Jdxp6 = Dtype*(-gcgs*(vgs-vgs_orig)-(gcbs)*(vbs-vbs_orig));
1249 
1250  double * dQdxdVp = extData.dQdxdVpVectorRawPtr;
1251  dQdxdVp[li_Gate ] += coef_Jdxp2*numberParallel;
1252  dQdxdVp[li_Bulk ] += coef_Jdxp4*numberParallel;
1253  dQdxdVp[li_DrainPrime ] += coef_Jdxp5*numberParallel;
1254  dQdxdVp[li_SourcePrime] += coef_Jdxp6*numberParallel;
1255  }
1256 
1257  return true;
1258 }
1259 
1260 //-----------------------------------------------------------------------------
1261 // Function : Instance::loadDAEFVector
1262 //
1263 // Purpose : Loads the F-vector contributions for a single
1264 // diode instance.
1265 //
1266 // Special Notes : See the special notes for loadDAEFVector.
1267 //
1268 // Scope : public
1269 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1270 // Creation Date : 03/06/04
1271 //-----------------------------------------------------------------------------
1273 {
1274  double * fVec = extData.daeFVectorRawPtr;
1275  double coef(0.0);
1276  double ceqbs(0.0),ceqbd(0.0),ceqgb(0.0), ceqgs(0.0), ceqgd(0.0); // 3f5 vars
1277  double gmin1 = getDeviceOptions().gmin;
1278 
1279  int Dtype=model_.dtype;
1280 
1281  // The next few lines are the same as for loadRHS, except
1282  // the capcitor current terms have been set to zero here.
1283  ceqbs = Dtype*(cbs);
1284  ceqbd = Dtype*(cbd);
1285  // These need "Dtype" here because we use them later *without*
1286  // Dtype, where SPICE uses it *with*
1287  ceqgb = 0.0;
1288  ceqgs = 0.0;
1289  ceqgd = 0.0;
1290 
1291  // 1 KCL for drain node
1292  if (drainConductance != 0.0)
1293  {
1294  coef = Idrain;
1295  fVec[li_Drain] += coef*numberParallel;
1296  }
1297 
1298  // 2 KCL for gate node
1299  coef = (ceqgs+ceqgd+ceqgb);
1300  fVec[li_Gate] += coef*numberParallel;
1301 
1302  // 3 KCL for source node
1303  if (sourceConductance != 0.0)
1304  {
1305  coef = Isource;
1306  fVec[li_Source] += coef*numberParallel;
1307  }
1308 
1309  // 4 KCL for bulk node
1310  coef = ceqbs + ceqbd - ceqgb;
1311  fVec[li_Bulk] += coef*numberParallel;
1312 
1313  // 5 KCL for drain' node
1314  coef = -Idrain-(ceqbd - cdreq + ceqgd);
1315  fVec[li_DrainPrime] += coef*numberParallel;
1316 
1317  // 6 KCL for source' node
1318  coef = -Isource-(ceqbs + cdreq + ceqgs);
1319  fVec[li_SourcePrime] += coef*numberParallel;
1320 
1321  // Same as for the loadRHS function, but without capacitive terms:
1322  // gcgd = Capgd;
1323  // gcgs = Capgs;
1324  // gcgb = Capgb;
1325  // gcbs = capbs;
1326  // gcbd = capbd;
1327  if (!origFlag)
1328  {
1329  // 4 KCL for bulk node
1330  double coef_Jdxp4 = Dtype*(
1331  + ((gbd-gmin1))*(vbd-vbd_orig)
1332  + ((gbs-gmin1))*(vbs-vbs_orig));
1333 
1334  // 5 KCL for drain' node
1335  double coef_Jdxp5 = Dtype*(
1336  -((gbd-gmin1))*(vbd-vbd_orig)
1337  +gds*(vds-vds_orig)
1338  +Gm*((mode>0)?(vgs-vgs_orig):(vgd-vgd_orig))
1339  +Gmbs*((mode>0)?(vbs-vbs_orig):(vbd-vbd_orig)));
1340 
1341  // 6 KCL for source' node
1342  double coef_Jdxp6 = Dtype*(
1343  -((gbs-gmin1))*(vbs-vbs_orig)
1344  -gds*(vds-vds_orig)
1345  -Gm*((mode>0)?(vgs-vgs_orig):(vgd-vgd_orig))
1346  -Gmbs*((mode>0)?(vbs-vbs_orig):(vbd-vbd_orig)));
1347 
1348  double * dFdxdVp = extData.dFdxdVpVectorRawPtr;
1349  dFdxdVp[li_Bulk ] += coef_Jdxp4*numberParallel;
1350  dFdxdVp[li_DrainPrime ] += coef_Jdxp5*numberParallel;
1351  dFdxdVp[li_SourcePrime] += coef_Jdxp6*numberParallel;
1352  }
1353 
1354  if( loadLeadCurrent )
1355  {
1356  double * storeLeadF = extData.nextStoVectorRawPtr;
1357  if (drainConductance != 0.0)
1358  {
1359  storeLeadF[li_store_dev_id] = Idrain*numberParallel;
1360  }
1361  else
1362  {
1363  storeLeadF[li_store_dev_id] = (-Idrain-(ceqbd - cdreq + ceqgd))*numberParallel;
1364  }
1365  if (sourceConductance != 0.0)
1366  {
1367  storeLeadF[li_store_dev_is] = Isource*numberParallel;
1368  }
1369  else
1370  {
1371  storeLeadF[li_store_dev_is] = (-Isource-(ceqbs + cdreq + ceqgs))*numberParallel;
1372  }
1373  storeLeadF[li_store_dev_ig] = (ceqgs+ceqgd+ceqgb)*numberParallel;
1374  storeLeadF[li_store_dev_ib] = (ceqbs + ceqbd - ceqgb)*numberParallel;
1375  }
1376 
1377  return true;
1378 }
1379 
1380 //-----------------------------------------------------------------------------
1381 // Function : Instance::loadDAEdQdx
1382 //
1383 // Purpose : Loads the Q-vector contributions for a single
1384 // diode instance.
1385 //
1386 // Special Notes : The "Q" vector is part of a standard DAE formalism in
1387 // which the system of equations is represented as:
1388 //
1389 // f(x) = dQ(x)/dt + F(x) - B(t) = 0
1390 //
1391 // Scope : public
1392 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1393 // Creation Date : 03/06/04
1394 //-----------------------------------------------------------------------------
1396 {
1397  N_LAS_Matrix & dQdx = *(extData.dQdxMatrixPtr);
1398 
1399  double gcgd(0.0); // d(cqgd)/dVgd
1400  double gcgs(0.0); // d(cqgs)/dVgs
1401  double gcgb(0.0); // d(cqgb)/dVgb
1402  double gcbs(0.0); // d(cqbs)/dVbs
1403  double gcbd(0.0); // d(cqbd)/dVbd
1404 
1405  // get at the "conductances" for the gate capacitors with this trick
1406  // gcgd = model_.dtype*Capgd;
1407  // gcgs = model_.dtype*Capgs;
1408  // gcgb = model_.dtype*Capgb;
1409  //
1410  // In the loadRHS function, these would all be multiplied by
1411  // getSolverState().pdt. Here, for dQdx, the pdt term is left out.
1412  if (getSolverState().tranopFlag || getSolverState().acopFlag || getSolverState().transientFlag)
1413  {
1414  gcgd = Capgd;
1415  gcgs = Capgs;
1416  gcgb = Capgb;
1417  // get at the two parasitic caps the same way
1418  gcbs = capbs;
1419  gcbd = capbd;
1420  }
1421 
1423  (gcgd+gcgs+gcgb)*numberParallel;
1427 
1430  (+gcbs+gcbd+gcgb)*numberParallel;
1433  +gcbs*numberParallel;
1434 
1436  -gcgd*numberParallel;
1438  -gcbd*numberParallel;
1440  (+gcbd+gcgd)*numberParallel;
1441 
1443  gcgs*numberParallel;
1445  +gcbs*numberParallel;
1447  (+gcbs+gcgs)*numberParallel;
1448 
1449  return true;
1450 }
1451 
1452 //-----------------------------------------------------------------------------
1453 // Function : Instance::loadDAEdFdx ()
1454 //
1455 // Purpose : Loads the F-vector contributions for a single
1456 // diode instance.
1457 //
1458 // Special Notes :
1459 //
1460 // Scope : public
1461 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1462 // Creation Date : 03/06/04
1463 //-----------------------------------------------------------------------------
1465 {
1466  N_LAS_Matrix & dFdx = *(extData.dFdxMatrixPtr);
1467 
1472 
1477 
1479  (gbs+gbd)*numberParallel;
1482 
1488  (-gbd+Gmbs)*numberParallel;
1490  (drainConductance+gds+gbd+revsum)*numberParallel;
1492  (-gds-nrmsum)*numberParallel;
1493 
1499  (gbs+Gmbs)*numberParallel;
1501  (gds+revsum)*numberParallel;
1503  (sourceConductance+gds+gbs+nrmsum)*numberParallel;
1504 
1505  return true;
1506 }
1507 
1508 //-----------------------------------------------------------------------------
1509 // Function : Instance::updateIntermediateVars
1510 // Purpose :
1511 // Special Notes :
1512 // Scope : public
1513 // Creator : Eric Keiter
1514 // Creation Date : 03/01/01
1515 //-----------------------------------------------------------------------------
1517 {
1518  bool bsuccess = true;
1519 
1520  // 3f5 likes to use the same variable names in local variables and in
1521  // structures. Messes with us! Define some local versions with capitals
1522  // instead
1523  double Von;
1524  double Vdsat;
1525  double Beta;
1526  //
1527  double evbs;
1528  double evbd;
1529  double sarg;
1530  double sargsw;
1531  // double vgs1;
1532  // double vgd1;
1533  // double vgb1;
1534  double arg;
1535  int Check = 1;
1536 
1537  double capgs_old;
1538  double capgd_old;
1539  double capgb_old;
1540 
1541  // temporary storage for vgs/vgd/vds so that homotopy doesn't impact
1542  // voltage limiting "jdxp" terms
1543 
1544  double vgs_save;
1545  double vgd_save;
1546  double vds_save;
1547 
1548  // This is one of the vars that are set up at the top of mos1load that
1549  // should *not* be moved to the instance constructor! tTransconductance
1550  // is set by updateTemperature. Perhaps I should remove it from the
1551  // instance variables, too, since now it's pretty much a local thing.
1552  // same goes for the other things that depend on the t* variables!
1553 
1554  if( (tSatCurDens == 0) || (drainArea == 0) || (sourceArea == 0))
1555  {
1556  DrainSatCur = tSatCur;
1558  }
1559  else
1560  {
1563  }
1565 
1566  // we need our solution variables for any of this stuff
1573 
1574  // now we need voltage drops
1575  Vddp = Vd - Vdp;
1576  Vssp = Vs - Vsp;
1577  Vbsp = Vb - Vsp;
1578  Vbdp = Vb - Vdp;
1579  Vgsp = Vg - Vsp;
1580  Vgdp = Vg - Vdp;
1581  Vgb = Vg - Vb;
1582  Vdpsp = Vdp - Vsp;
1583 
1584  // Now the things that the 3f5 code really uses (from mos1load's
1585  // "general iteration" part at lines 276-295
1586  vbs = model_.dtype * Vbsp;
1587  vgs = model_.dtype * Vgsp;
1588  vds = model_.dtype * Vdpsp;
1589 
1590  vbd = vbs-vds;
1591  vgd = vgs-vds;
1592 
1593  origFlag = 1;
1594  limitedFlag=false;
1595  vgs_orig = vgs;
1596  vds_orig = vds;
1597  vbs_orig = vbs;
1598  vbd_orig = vbd;
1599  vgd_orig = vgd;
1600 
1602  {
1603  if (IC_GIVEN)
1604  {
1605  vds = model_.dtype*icVDS;
1606  vgs = model_.dtype*icVGS;
1607  vbs = model_.dtype*icVBS;
1608  vbd = vbs - vds;
1609  vgd = vgs - vds;
1610  origFlag = false;
1611  }
1612  else
1613  {
1615  {
1616  N_LAS_Vector * flagSolVectorPtr = extData.flagSolVectorPtr;
1617  if ((*flagSolVectorPtr)[li_Drain] == 0 || (*flagSolVectorPtr)[li_Gate] == 0 ||
1618  (*flagSolVectorPtr)[li_Source] == 0 || (*flagSolVectorPtr)[li_SourcePrime] ||
1619  (*flagSolVectorPtr)[li_DrainPrime] || (*flagSolVectorPtr)[li_Bulk] )
1620  {
1621  vbs = -1;
1622  vgs = model_.dtype*tVto;
1623  vds = 0;
1624  vbd = vbs-vds;
1625  vgd = vgs-vds;
1626  }
1627  }
1628  else
1629  {
1630  vbs = -1;
1631  vgs = model_.dtype*tVto;
1632  vds = 0;
1633  vbd = vbs-vds;
1634  vgd = vgs-vds;
1635  }
1636  }
1637  }
1638  else if ((getSolverState().initFixFlag || getSolverState().initJctFlag) && OFF)
1639  {
1640  vbs = vgs = vds = 0;
1641  vbd = vgd = 0;
1642  }
1643 
1644  if (getSolverState().newtonIter == 0)
1645  {
1646 
1648  {
1653  Von = model_.dtype *
1655  }
1656  else
1657  { // otherwise there is no history
1658  vbs_old = vbs;
1659  vbd_old = vbd;
1660  vgs_old = vgs;
1661  vds_old = vds;
1662  Von = 0.0;
1663  }
1665  }
1666  else
1667  {
1672  Von = model_.dtype *
1675  }
1676 
1677  ////////////////////////////////////////////
1678  // SPICE-type Voltage Limiting
1679  ////////////////////////////////////////////
1681  {
1682  // Do not do limiting if mode initfix and OFF:
1683  if (! (getSolverState().initFixFlag && OFF))
1684  {
1685  if (vds_old >= 0)
1686  {
1687  vgs = devSupport.fetlim( vgs, vgs_old, Von);
1688  vds = vgs - vgd;
1689  vds = devSupport.limvds( vds, vds_old);
1690  vgd = vgs - vds;
1691  }
1692  else
1693  {
1694  vgd = devSupport.fetlim( vgd, vgd_old, Von);
1695  vds = vgs - vgd;
1696  vds = -devSupport.limvds( -vds, -vds_old );
1697  vgs = vgd + vds;
1698  }
1699 
1700  if (vds >= 0.0)
1701  {
1702  vbs = devSupport.pnjlim( vbs, vbs_old, vt, sourceVcrit, &Check);
1703  vbd = vbs - vds;
1704  }
1705  else
1706  {
1707  vbd = devSupport.pnjlim( vbd, vbd_old, vt, drainVcrit, &Check);
1708  vbs = vbd + vds;
1709  }
1710 
1711  // for convergence:
1712  if (Check == 1) limitedFlag=true;
1713 
1714  }
1715  }
1716 
1717  ////
1718  // now all the preliminaries are over - we can start doing the
1719  // real work
1720  ////
1721  vbd = vbs - vds;
1722  vgd = vgs - vds;
1723  Vgb = vgs - vbs;
1724 
1725  // Now set the origFlag
1726  if (vgs_orig != vgs || vds_orig != vds ||
1727  vbs_orig != vbs || vbd_orig != vbd || vgd_orig != vgd) origFlag = 0;
1728 
1729  ////
1730  // bulk-source and bulk-drain diodes
1731  // here we just evaluate the ideal diode current and the
1732  // corresponding derivative (conductance).
1733  ////
1734  if(vbs <= 0)
1735  {
1736  gbs = SourceSatCur/vt;
1737  gbs += getDeviceOptions().gmin;
1738  cbs = gbs*vbs;
1739  }
1740  else
1741  {
1742  // erkeite note: the Xycemin failsafe is in the level-1 but not the level-2.
1743  //evbs = exp(Xycemin(CONSTMAX_EXP_ARG,vbs/vt));
1744  evbs = exp(vbs/vt);
1745  gbs = (SourceSatCur*evbs/vt + getDeviceOptions().gmin);
1746  cbs = (SourceSatCur * (evbs-1) + getDeviceOptions().gmin*vbs);
1747  }
1748  if(vbd <= 0)
1749  {
1750  gbd = DrainSatCur/vt;
1751  gbd += getDeviceOptions().gmin;
1752  cbd = gbd *vbd;
1753 
1754  }
1755  else
1756  {
1757  // erkeite note: the Xycemin failsafe is in the level-1 but not the level-2.
1758  //evbd = exp(Xycemin(CONSTMAX_EXP_ARG,vbd/vt));
1759  evbd = exp(vbd/vt);
1760  gbd = (DrainSatCur*evbd/vt + getDeviceOptions().gmin);
1761  cbd = (DrainSatCur *(evbd-1)+getDeviceOptions().gmin*vbd);
1762  }
1763 
1764  // 3f5 does this simple stuff
1765  if (vds >= 0)
1766  mode = 1;
1767  else
1768  mode = -1;
1769 
1770  {
1771  //
1772  // this block of code evaluates the drain current and its
1773  // derivatives using the shichman-hodges model and the
1774  // charges associated with the gate, channel and bulk for
1775  // mosfets
1776  //
1777  //
1778 
1779  // the following 4 variables are local to this code block until
1780  // it is obvious that they can be made global
1781  //
1782  //double arg;
1783  //double betap;
1784  //double sarg;
1785  //double vgst;
1786 
1787  // Begin block of mosfet continuation code.
1788  // This idea is based, loosely, on a paper by Jaijeet
1789  // Roychowdhury.
1790 
1791  // Save these before allowing homotopy to tweak them. It
1792  // is important to restore them before moving on to
1793  // calculate RHS, because then the Jdxp terms will attempt to force
1794  // the external circuit to make these voltage drops the real thing!
1795  vds_save=vds;
1796  vgs_save=vgs;
1797  vgd_save=vgd;
1798 
1800  {
1801  double alpha = getSolverState().gainScale[blockHomotopyID];
1802  if (getDeviceOptions().staggerGainScale)
1803  {
1804  alpha *= (0.3 * randomPerturb + 1.0);
1805  if (alpha > 1.0)
1806  {
1807  alpha = 1.0;
1808  }
1809  }
1810  double vgstConst = getDeviceOptions().vgstConst;
1811  if (getDeviceOptions().randomizeVgstConst)
1812  {
1813  vgstConst *= randomPerturb;
1814  }
1815 
1816  vds = devSupport.contVds (vds, getSolverState().nltermScale, getDeviceOptions().vdsScaleMin);
1817 
1818  if (mode==1)
1819  {
1820  vgs = devSupport.contVgst (vgs, alpha, vgstConst);
1821  }
1822  else
1823  {
1824  vgd = devSupport.contVgst (vgd, alpha, vgstConst);
1825  }
1826  }
1827  // End of block of mosfet continuation code.
1828 
1829  // erkeite: This block that follows (surrounded by curly brackets) is
1830  // the main difference between the level-1 and level-2 MOSFETs in spice3.
1831  // Otherwise they are nearly identical.
1832  //
1833  // The spice3 code was embedded in the mos2load.c function. However, it
1834  // clearly was originally its own separate function. Also, it was probably
1835  // converted from fortran-66, or something like that, as it had "goto" statements
1836  // all over the place ("else" wasn't support in early versions of fortran). I've
1837  // removed all the goto's and have attempted to replace them with modern conditional
1838  // statements. If there are any mistakes here, it is in those replacements.
1839  //
1840  //
1841 // begin level-2 block:
1842 //
1843  // this routine evaluates the drain current, its derivatives and
1844  // the charges associated with the gate, channel and bulk
1845  // for mosfets
1846  {
1847  {
1848 
1849  static double sig1[4] = {1.0, -1.0, 1.0, -1.0};
1850  static double sig2[4] = {1.0, 1.0,-1.0, -1.0};
1851 
1852  double arg(0.0);
1853  double sarg(0.0);
1854  double a4[4],b4[4],x4[8],poly4[8];
1855 
1856  double beta1(0.0);
1857  double dsrgdb(0.0);
1858  double d2sdb2(0.0);
1859  double sphi(0.0); // square root of phi
1860  double sphi3(0.0); // square root of phi cubed
1861  double barg(0.0);
1862  double d2bdb2(0.0);
1863  double factor(0.0);
1864  double dbrgdb(0.0);
1865  double eta(0.0);
1866  double vbin(0.0);
1867  double argd(0.0);
1868  double args(0.0);
1869  double argss(0.0);
1870  double argsd(0.0);
1871  double argxs(0.0);
1872  double argxd(0.0);
1873  double daddb2(0.0);
1874  double dasdb2(0.0);
1875  double dbargd(0.0);
1876  double dbargs(0.0);
1877  double dbxwd(0.0);
1878  double dbxws(0.0);
1879  double dgddb2(0.0);
1880  double dgddvb(0.0);
1881  double dgdvds(0.0);
1882  double gamasd(0.0);
1883  double xwd(0.0);
1884  double xws(0.0);
1885  double ddxwd(0.0);
1886  double gammad(0.0);
1887  double vth(0.0);
1888  double cfs(0.0);
1889  double cdonco(0.0);
1890  double xn(0.0);
1891  double argg(0.0);
1892  double vgst(0.0);
1893  double sarg3(0.0);
1894  double sbiarg(0.0);
1895  double dgdvbs(0.0);
1896  double body(0.0);
1897  double gdbdv(0.0);
1898  double dodvbs(0.0);
1899  double dodvds(0.0);
1900  double dxndvd(0.0);
1901  double dxndvb(0.0);
1902  double udenom(0.0);
1903  double dudvgs(0.0);
1904  double dudvds(0.0);
1905  double dudvbs(0.0);
1906  double gammd2(0.0);
1907  double argv(0.0);
1908  double vgsx(0.0);
1909  double ufact(0.0);
1910  double ueff(0.0);
1911  double dsdvgs(0.0);
1912  double dsdvbs(0.0);
1913  double a1(0.0);
1914  double a3(0.0);
1915  double a(0.0);
1916  double b1(0.0);
1917  double b3(0.0);
1918  double b(0.0);
1919  double c1(0.0);
1920  double c(0.0);
1921  double d1(0.0);
1922  double fi(0.0);
1923  double p0(0.0);
1924  double p2(0.0);
1925  double p3(0.0);
1926  double p4(0.0);
1927  double p(0.0);
1928  double r3(0.0);
1929  double r(0.0);
1930  double ro(0.0);
1931  double s2(0.0);
1932  double s(0.0);
1933  double v1(0.0);
1934  double v2(0.0);
1935  double xv(0.0);
1936  double y3(0.0);
1937  double delta4(0.0);
1938  double xvalid(0.0);
1939  double bsarg(0.0);
1940  double dbsrdb(0.0);
1941  double bodys(0.0);
1942  double gdbdvs(0.0);
1943  double sargv(0.0);
1944  double xlfact(0.0);
1945  double dldsat(0.0);
1946  double xdv(0.0);
1947  double xlv(0.0);
1948  double vqchan(0.0);
1949  double dqdsat(0.0);
1950  double vl(0.0);
1951  double dfundg(0.0);
1952  double dfunds(0.0);
1953  double dfundb(0.0);
1954  double xls(0.0);
1955  double dldvgs(0.0);
1956  double dldvds(0.0);
1957  double dldvbs(0.0);
1958  double dfact(0.0);
1959  double clfact(0.0);
1960  double xleff(0.0);
1961  double deltal(0.0);
1962  double xwb(0.0);
1963  double vdson(0.0);
1964  double cdson(0.0);
1965  double didvds(0.0);
1966  double gdson(0.0);
1967  double gmw(0.0);
1968  double gbson(0.0);
1969  double expg(0.0);
1970  double xld(0.0);
1971  double xlamda = model_.lambda;
1972 
1973  // 'local' variables - these switch d & s around appropriately
1974  // so that we don't have to worry about vds < 0
1975  double lvbs = mode==1?vbs:vbd;
1976  double lvds = mode*vds;
1977  double lvgs = mode==1?vgs:vgd;
1978  double phiMinVbs = tPhi - lvbs;
1979  double tmp(0.0); // a temporary variable, not used for more than
1980  // about 10 lines at a time
1981  int iknt;
1982  int jknt;
1983  int i;
1984  int j;
1985 
1986  // compute some useful quantities
1987  if (lvbs <= 0.0)
1988  {
1989  sarg = sqrt(phiMinVbs);
1990  dsrgdb = -0.5/sarg;
1991  d2sdb2 = 0.5*dsrgdb/phiMinVbs;
1992  }
1993  else
1994  {
1995  sphi = sqrt(tPhi);
1996  sphi3 = tPhi*sphi;
1997  sarg = sphi/(1.0+0.5*lvbs/tPhi);
1998  tmp = sarg/sphi3;
1999  dsrgdb = -0.5*sarg*tmp;
2000  d2sdb2 = -dsrgdb*tmp;
2001  }
2002  if ((lvds-lvbs) >= 0)
2003  {
2004  barg = sqrt(phiMinVbs+lvds);
2005  dbrgdb = -0.5/barg;
2006  d2bdb2 = 0.5*dbrgdb/(phiMinVbs+lvds);
2007  }
2008  else
2009  {
2010  barg = sphi/(1.0+0.5*(lvbs-lvds)/tPhi);
2011  tmp = barg/sphi3;
2012  dbrgdb = -0.5*barg*tmp;
2013  d2bdb2 = -dbrgdb*tmp;
2014  }
2015 
2016  // calculate threshold voltage (Von)
2017  // narrow-channel effect
2018 
2019  // XXX constant per device
2021  // XXX constant per device
2022  eta = 1.0+factor;
2023  vbin = tVbi* (model_.dtype)+factor*phiMinVbs;
2024 
2025  if ((model_.gamma > 0.0) || (model_.substrateDoping > 0.0))
2026  {
2027  xwd = model_.xd*barg;
2028  xws = model_.xd*sarg;
2029 
2030  // short-channel effect with vds .ne. 0.0
2031  argss = 0.0;
2032  argsd = 0.0;
2033  dbargs = 0.0;
2034  dbargd = 0.0;
2035  dgdvds = 0.0;
2036  dgddb2 = 0.0;
2037  if (model_.junctionDepth > 0)
2038  {
2039  tmp = 2.0/model_.junctionDepth;
2040  argxs = 1.0+xws*tmp;
2041  argxd = 1.0+xwd*tmp;
2042  args = sqrt(argxs);
2043  argd = sqrt(argxd);
2045  argss = tmp * (args-1.0);
2046  argsd = tmp * (argd-1.0);
2047  }
2048  gamasd = model_.gamma*(1.0-argss-argsd);
2049  dbxwd = model_.xd*dbrgdb;
2050  dbxws = model_.xd*dsrgdb;
2051  if (model_.junctionDepth > 0)
2052  {
2053  tmp = 0.5/EffectiveLength;
2054  dbargs = tmp*dbxws/args;
2055  dbargd = tmp*dbxwd/argd;
2056  dasdb2 = -model_.xd*( d2sdb2+dsrgdb*dsrgdb*
2057  model_.xd/(model_.junctionDepth*argxs))/
2058  (EffectiveLength*args);
2059  daddb2 = -model_.xd*( d2bdb2+dbrgdb*dbrgdb*
2060  model_.xd/(model_.junctionDepth*argxd))/
2061  (EffectiveLength*argd);
2062  dgddb2 = -0.5*model_.gamma*(dasdb2+daddb2);
2063  }
2064  dgddvb = -model_.gamma*(dbargs+dbargd);
2065  if (model_.junctionDepth > 0)
2066  {
2067  ddxwd = -dbxwd;
2068  dgdvds = -model_.gamma*0.5*ddxwd/(EffectiveLength*argd);
2069  }
2070  }
2071  else
2072  {
2073  gamasd = model_.gamma;
2074  gammad = model_.gamma;
2075  dgddvb = 0.0;
2076  dgdvds = 0.0;
2077  dgddb2 = 0.0;
2078  }
2079  Von = vbin+gamasd*sarg;
2080  vth = Von;
2081  Vdsat = 0.0;
2082 
2083  // erkeite: there were a lot of got line1050: in the original spice3
2084  // source. I think essentially it means, "don't do any more calcultions here,
2085  // and set cdrain, gm, and gmbs to zero".
2086  bool line1050bool=false;
2087  if (model_.fastSurfaceStateDensity != 0.0 && OxideCap != 0.0)
2088  {
2089  // XXX constant per model
2090  cfs = CONSTQ *model_.fastSurfaceStateDensity*1e4; //(cm**2/m**2)
2091  cdonco = -(gamasd*dsrgdb+dgddvb*sarg)+factor;
2092  xn = 1.0+cfs/OxideCap*w*EffectiveLength+cdonco;
2093  tmp = vt*xn;
2094  Von = Von+tmp;
2095  argg = 1.0/tmp;
2096  vgst = lvgs-Von;
2097  }
2098  else
2099  {
2100  vgst = lvgs-Von;
2101  if (lvgs <= Von)
2102  {
2103  // cutoff region
2104  gds = 0.0;
2105  //goto line1050;
2106  line1050bool=true;
2107  }
2108  }
2109 
2110  if (!line1050bool)
2111  {
2112  ufact = 1.0;
2113  ueff = model_.surfaceMobility * 1e-4;
2114  dudvgs = 0.0;
2115  dudvds = 0.0;
2116  dudvbs = 0.0;
2117 
2118  // compute some more useful quantities
2119  sarg3 = sarg*sarg*sarg;
2120  // XXX constant per model
2121  sbiarg = sqrt(tBulkPot);
2122  gammad = gamasd;
2123  dgdvbs = dgddvb;
2124  body = barg*barg*barg-sarg3;
2125  gdbdv = 2.0*gammad*(barg*barg*dbrgdb-sarg*sarg*dsrgdb);
2126  dodvbs = -factor+dgdvbs*sarg+gammad*dsrgdb;
2127 
2128  if (OxideCap != 0.0)
2129  {
2130  if (model_.fastSurfaceStateDensity != 0.0)
2131  {
2132  dxndvb = 2.0*dgdvbs*dsrgdb+gammad*d2sdb2+dgddb2*sarg;
2133  dodvbs = dodvbs+vt*dxndvb;
2134  dxndvd = dgdvds*dsrgdb;
2135  dodvds = dgdvds*sarg+vt*dxndvd;
2136  }
2137 
2138  // evaluate effective mobility and its derivatives
2139  // line400
2140  if (OxideCap > 0.0)
2141  {
2142  udenom = vgst;
2144 
2145  if (udenom > tmp)
2146  {
2147  ufact = exp(model_.critFieldExp*log(tmp/udenom));
2148  ueff = model_.surfaceMobility * 1e-4 *ufact;
2149  dudvgs = -ufact*model_.critFieldExp/udenom;
2150  dudvds = 0.0;
2151  dudvbs = model_.critFieldExp*ufact*dodvbs/vgst;
2152  //goto line500;
2153  }
2154  }
2155  }
2156  }
2157 
2158  if (!line1050bool)
2159  {
2160 
2161  // evaluate saturation voltage and its derivatives according to
2162  // grove-frohman equation
2163  // line500
2164  vgsx = lvgs;
2165  gammad = gamasd/eta;
2166  dgdvbs = dgddvb;
2167  if (model_.fastSurfaceStateDensity != 0 && OxideCap != 0)
2168  {
2169  vgsx = Xycemax(lvgs,Von);
2170  }
2171  if (gammad > 0)
2172  {
2173  gammd2 = gammad*gammad;
2174  argv = (vgsx-vbin)/eta+phiMinVbs;
2175  if (argv <= 0.0)
2176  {
2177  Vdsat = 0.0;
2178  dsdvgs = 0.0;
2179  dsdvbs = 0.0;
2180  }
2181  else
2182  {
2183  arg = sqrt(1.0+4.0*argv/gammd2);
2184  Vdsat = (vgsx-vbin)/eta+gammd2*(1.0-arg)/2.0;
2185  Vdsat = Xycemax(Vdsat,0.0);
2186  dsdvgs = (1.0-1.0/arg)/eta;
2187  dsdvbs = (gammad*(1.0-arg)+2.0*argv/(gammad*arg))/
2188  eta*dgdvbs+1.0/arg+factor*dsdvgs;
2189  }
2190  }
2191  else
2192  {
2193  Vdsat = (vgsx-vbin)/eta;
2194  Vdsat = Xycemax(Vdsat,0.0);
2195  dsdvgs = 1.0;
2196  dsdvbs = 0.0;
2197  }
2198  if (model_.maxDriftVel > 0)
2199  {
2200  // evaluate saturation voltage and its derivatives
2201  // according to baum's theory of scattering velocity
2202  // saturation
2203 
2204  gammd2 = gammad*gammad;
2205  v1 = (vgsx-vbin)/eta+phiMinVbs;
2206  v2 = phiMinVbs;
2207  xv = model_.maxDriftVel*EffectiveLength/ueff;
2208  a1 = gammad/0.75;
2209  b1 = -2.0*(v1+xv);
2210  c1 = -2.0*gammad*xv;
2211  d1 = 2.0*v1*(v2+xv)-v2*v2-4.0/3.0*gammad*sarg3;
2212  a = -b1;
2213  b = a1*c1-4.0*d1;
2214  c = -d1*(a1*a1-4.0*b1)-c1*c1;
2215  r = -a*a/3.0+b;
2216  s = 2.0*a*a*a/27.0-a*b/3.0+c;
2217  r3 = r*r*r;
2218  s2 = s*s;
2219  p = s2/4.0+r3/27.0;
2220  p0 = fabs(p);
2221  p2 = sqrt(p0);
2222  if (p < 0)
2223  {
2224  ro = sqrt(s2/4.0+p0);
2225  ro = log(ro)/3.0;
2226  ro = exp(ro);
2227  fi = atan(-2.0*p2/s);
2228  y3 = 2.0*ro*cos(fi/3.0)-a/3.0;
2229  }
2230  else
2231  {
2232  p3 = (-s/2.0+p2);
2233  p3 = exp(log(fabs(p3))/3.0);
2234  p4 = (-s/2.0-p2);
2235  p4 = exp(log(fabs(p4))/3.0);
2236  y3 = p3+p4-a/3.0;
2237  }
2238  iknt = 0;
2239  a3 = sqrt(a1*a1/4.0-b1+y3);
2240  b3 = sqrt(y3*y3/4.0-d1);
2241  for(i = 1;i<=4;i++)
2242  {
2243  a4[i-1] = a1/2.0+sig1[i-1]*a3;
2244  b4[i-1] = y3/2.0+sig2[i-1]*b3;
2245  delta4 = a4[i-1]*a4[i-1]/4.0-b4[i-1];
2246  if (delta4 < 0) continue;
2247  iknt = iknt+1;
2248  tmp = sqrt(delta4);
2249  x4[iknt-1] = -a4[i-1]/2.0+tmp;
2250  iknt = iknt+1;
2251  x4[iknt-1] = -a4[i-1]/2.0-tmp;
2252  }
2253  jknt = 0;
2254  for(j = 1;j<=iknt;j++)
2255  {
2256  if (x4[j-1] <= 0) continue;
2257  // XXX implement this sanely
2258  poly4[j-1] = x4[j-1]*x4[j-1]*x4[j-1]*x4[j-1]+a1*x4[j-1]*
2259  x4[j-1]*x4[j-1];
2260  poly4[j-1] = poly4[j-1]+b1*x4[j-1]*x4[j-1]+c1*x4[j-1]+d1;
2261  if (fabs(poly4[j-1]) > 1.0e-6) continue;
2262  jknt = jknt+1;
2263  if (jknt <= 1)
2264  {
2265  xvalid = x4[j-1];
2266  }
2267  if (x4[j-1] > xvalid) continue;
2268  xvalid = x4[j-1];
2269  }
2270  if (jknt > 0)
2271  {
2272  Vdsat = xvalid*xvalid-phiMinVbs;
2273  }
2274  }
2275 
2276  }
2277 
2278  // evaluate effective channel length and its derivatives
2279  bool line610bool=false;
2280  if (!line1050bool)
2281  {
2282  dldvgs = 0.0;
2283  dldvds = 0.0;
2284  dldvbs = 0.0;
2285  if (lvds != 0.0)
2286  {
2287  gammad = gamasd;
2288  if ((lvbs-Vdsat) <= 0)
2289  {
2290  bsarg = sqrt(Vdsat+phiMinVbs);
2291  dbsrdb = -0.5/bsarg;
2292  }
2293  else
2294  {
2295  bsarg = sphi/(1.0+0.5*(lvbs-Vdsat)/tPhi);
2296  dbsrdb = -0.5*bsarg*bsarg/sphi3;
2297  }
2298  bodys = bsarg*bsarg*bsarg-sarg3;
2299  gdbdvs = 2.0*gammad*(bsarg*bsarg*dbsrdb-sarg*sarg*dsrgdb);
2300  if (model_.maxDriftVel <= 0)
2301  {
2302  if (model_.substrateDoping == 0.0 || xlamda > 0.0)
2303  {
2304  line610bool=true;
2305  }
2306  else
2307  {
2308  argv = (lvds-Vdsat)/4.0;
2309  sargv = sqrt(1.0+argv*argv);
2310  arg = sqrt(argv+sargv);
2311  xlfact = model_.xd/(EffectiveLength*lvds);
2312  xlamda = xlfact*arg;
2313  dldsat = lvds*xlamda/(8.0*sargv);
2314  }
2315  }
2316  else
2317  {
2318  argv = (vgsx-vbin)/eta-Vdsat;
2319  xdv = model_.xd/sqrt(model_.channelCharge);
2320  xlv = model_.maxDriftVel*xdv/(2.0*ueff);
2321  vqchan = argv-gammad*bsarg;
2322  dqdsat = -1.0+gammad*dbsrdb;
2324  dfunds = vl*dqdsat-ueff*vqchan;
2325  dfundg = (vl-ueff*Vdsat)/eta;
2326  dfundb = -vl*(1.0+dqdsat-factor/eta)+ueff*
2327  (gdbdvs-dgdvbs*bodys/1.5)/eta;
2328  dsdvgs = -dfundg/dfunds;
2329  dsdvbs = -dfundb/dfunds;
2330 
2331  if (model_.substrateDoping == 0.0 || xlamda > 0.0)
2332  {
2333  line610bool=true;
2334  }
2335  else
2336  {
2337  argv = lvds-Vdsat;
2338  argv = Xycemax(argv,0.0);
2339  xls = sqrt(xlv*xlv+argv);
2340  dldsat = xdv/(2.0*xls);
2341  xlfact = xdv/(EffectiveLength*lvds);
2342  xlamda = xlfact*(xls-xlv);
2343  dldsat = dldsat/EffectiveLength;
2344  }
2345  }
2346 
2347  if (!line610bool)
2348  {
2349  dldvgs = dldsat*dsdvgs;
2350  dldvds = -xlamda+dldsat;
2351  dldvbs = dldsat*dsdvbs;
2352  }
2353  }
2354  }
2355 
2356  bool donevalbool=false;
2357  if (!line1050bool)
2358  {
2359  // limit channel shortening at punch-through
2360  xwb = model_.xd*sbiarg;
2361  xld = EffectiveLength-xwb;
2362  clfact = 1.0-xlamda*lvds;
2363  dldvds = -xlamda-dldvds;
2364  xleff = EffectiveLength*clfact;
2365  deltal = xlamda*lvds*EffectiveLength;
2366  if (model_.substrateDoping == 0.0) xwb = 0.25e-6;
2367  if (xleff < xwb)
2368  {
2369  xleff = xwb/(1.0+(deltal-xld)/xwb);
2370  clfact = xleff/EffectiveLength;
2371  dfact = xleff*xleff/(xwb*xwb);
2372  dldvgs = dfact*dldvgs;
2373  dldvds = dfact*dldvds;
2374  dldvbs = dfact*dldvbs;
2375  }
2376  // evaluate effective beta (effective kp)
2377  beta1 = Beta*ufact/clfact;
2378 
2379  // test for mode of operation and branch appropriately
2380  gammad = gamasd;
2381  dgdvbs = dgddvb;
2382 
2383  if (lvds <= 1.0e-10)
2384  {
2385  if (lvgs <= Von)
2386  {
2387  if ((model_.fastSurfaceStateDensity == 0.0) || (OxideCap == 0.0))
2388  {
2389  gds = 0.0;
2390  }
2391  else
2392  {
2393  gds = beta1*(Von-vbin-gammad*sarg)*exp(argg*(lvgs-Von));
2394  }
2395  }
2396  else
2397  {
2398  gds = beta1*(lvgs-vbin-gammad*sarg);
2399  }
2400  line1050bool=true;
2401  }
2402 
2403  }
2404 
2405  if (!line1050bool)
2406  {
2407  if ( !(lvgs > Von) )
2408  {
2409  // subthreshold region
2410  if (Vdsat <= 0)
2411  {
2412  gds = 0.0;
2413  if (lvgs > vth)
2414  {
2415  donevalbool=true;
2416  }
2417  else
2418  {
2419  line1050bool=true;
2420  }
2421  }
2422 
2423  if (!donevalbool && !line1050bool)
2424  {
2425  vdson = Xycemin(Vdsat,lvds);
2426  if (lvds > Vdsat)
2427  {
2428  barg = bsarg;
2429  dbrgdb = dbsrdb;
2430  body = bodys;
2431  gdbdv = gdbdvs;
2432  }
2433 
2434  cdson = beta1*((Von-vbin-eta*vdson*0.5)*vdson-gammad*body/1.5);
2435  didvds = beta1*(Von-vbin-eta*vdson-gammad*barg);
2436  gdson = -cdson*dldvds/clfact-beta1*dgdvds*body/1.5;
2437 
2438  if (lvds < Vdsat)
2439  {
2440  gdson = gdson+didvds;
2441  }
2442 
2443  gbson = -cdson*dldvbs/clfact+beta1*
2444  (dodvbs*vdson+factor*vdson-dgdvbs*body/1.5-gdbdv);
2445  if (lvds > Vdsat)
2446  {
2447  gbson = gbson+didvds*dsdvbs;
2448  }
2449  expg = exp(argg*(lvgs-Von));
2450  cdrain = cdson*expg;
2451  gmw = cdrain*argg;
2452  gm = gmw;
2453  if (lvds > Vdsat)
2454  {
2455  gm = gmw+didvds*dsdvgs*expg;
2456  }
2457  tmp = gmw*(lvgs-Von)/xn;
2458  gds = gdson*expg-gm*dodvds-tmp*dxndvd;
2459  gmbs = gbson*expg-gm*dodvbs-tmp*dxndvb;
2460  donevalbool=true;
2461  }
2462  }
2463  }
2464 
2465  if (!donevalbool && !line1050bool)
2466  {
2467  if (lvds <= Vdsat)
2468  {
2469  // linear region
2470  cdrain = beta1*((lvgs-vbin-eta*lvds/2.0)*lvds-gammad*body/1.5);
2471  arg = cdrain*(dudvgs/ufact-dldvgs/clfact);
2472  gm = arg+beta1*lvds;
2473  arg = cdrain*(dudvds/ufact-dldvds/clfact);
2474  gds = arg+beta1*(lvgs-vbin-eta*
2475  lvds-gammad*barg-dgdvds*body/1.5);
2476  arg = cdrain*(dudvbs/ufact-dldvbs/clfact);
2477  gmbs = arg-beta1*(gdbdv+dgdvbs*body/1.5-factor*lvds);
2478  }
2479  else
2480  {
2481  // saturation region
2482  cdrain = beta1*((lvgs-vbin-eta*
2483  Vdsat/2.0)*Vdsat-gammad*bodys/1.5);
2484  arg = cdrain*(dudvgs/ufact-dldvgs/clfact);
2485  gm = arg+beta1*Vdsat+beta1*(lvgs-
2486  vbin-eta*Vdsat-gammad*bsarg)*dsdvgs;
2487  gds = -cdrain*dldvds/clfact-beta1*dgdvds*bodys/1.5;
2488  arg = cdrain*(dudvbs/ufact-dldvbs/clfact);
2489  gmbs = arg-beta1*(gdbdvs+dgdvbs*bodys/1.5-factor*
2490  Vdsat)+beta1* (lvgs-vbin-eta*Vdsat-gammad*bsarg)*dsdvbs;
2491  }
2492 
2493  // compute charges for "on" region
2494  donevalbool=true;
2495  }
2496 
2497  // finish special cases.
2498  if (line1050bool)
2499  {
2500  cdrain = 0.0;
2501  gm = 0.0;
2502  gmbs = 0.0;
2503  }
2504 
2505  // finished
2506  }
2507 
2508  von = (model_.dtype) * Von;
2509  vdsat = (model_.dtype) * Vdsat;
2510  }
2511  }
2512 // end level-2 block
2513 
2514 
2515  ////
2516  // * COMPUTE EQUIVALENT DRAIN CURRENT SOURCE
2517  ////
2518 
2519  cd = mode * cdrain - cbd;
2520 
2521  // in 3f5 this is all in a block conditioned on CKTmode, but since
2522  // it's valid for MODETRAN and MODETRANOP we'll just always do it
2523 
2524  ////
2525  // * now we do the hard part of the bulk-drain and bulk-source
2526  // * diode - we evaluate the non-linear capacitance and
2527  // * charge
2528  // *
2529  // * the basic equations are not hard, but the implementation
2530  // * is somewhat long in an attempt to avoid log/exponential
2531  // * evaluations
2532  ////
2533  ////
2534  // * charge storage elements
2535  // *
2536  // *.. bulk-drain and bulk-source depletion capacitances
2537  ////
2538  // I took out all the CAPBYPASS stuff, and the
2539  // unnecessary curly braces that wind up there if you do
2540 
2541  // can't bypass the diode capacitance calculations
2542  if(Cbs != 0 || Cbssw != 0 )
2543  {
2544  if (vbs < tDepCap)
2545  {
2546  arg=1-vbs/tBulkPot;
2547  ////
2548  // * the following block looks somewhat long and messy,
2549  // * but since most users use the default grading
2550  // * coefficients of .5, and sqrt is MUCH faster than an
2551  // * exp(log()) we use this special case code to buy time.
2552  // * (as much as 10% of total job time!)
2553  ////
2555  {
2556  if(model_.bulkJctBotGradingCoeff == .5)
2557  {
2558  sarg = sargsw = 1/sqrt(arg);
2559  }
2560  else
2561  {
2562  sarg = sargsw = exp(-model_.bulkJctBotGradingCoeff*log(arg));
2563  }
2564  }
2565  else
2566  {
2567  if(model_.bulkJctBotGradingCoeff == .5)
2568  {
2569  sarg = 1/sqrt(arg);
2570  }
2571  else
2572  {
2573  sarg = exp(-model_.bulkJctBotGradingCoeff*log(arg));
2574  }
2576  {
2577  sargsw = 1/sqrt(arg);
2578  }
2579  else
2580  {
2581  sargsw =exp(-model_.bulkJctSideGradingCoeff* log(arg));
2582  }
2583  }
2584  qbs = tBulkPot*(Cbs*(1-arg*sarg)/(1-model_.bulkJctBotGradingCoeff)
2585  +Cbssw*(1-arg*sargsw)/(1-model_.bulkJctSideGradingCoeff));
2586  capbs=Cbs*sarg+ Cbssw*sargsw;
2587  }
2588  else
2589  {
2590  qbs = f4s + vbs*(f2s+vbs*(f3s/2));
2591  capbs=f2s+f3s*vbs;
2592  }
2593  }
2594  else
2595  {
2596  qbs = 0;
2597  capbs=0;
2598  }
2599 
2600  //// can't bypass the diode capacitance calculations
2601  if(Cbd != 0 || Cbdsw != 0 )
2602  {
2603 
2604  if (vbd < tDepCap)
2605  {
2606  arg=1-vbd/tBulkPot;
2607  ////
2608  // * the following block looks somewhat long and messy,
2609  // * but since most users use the default grading
2610  // * coefficients of .5, and sqrt is MUCH faster than an
2611  // * exp(log()) we use this special case code to buy time.
2612  // * (as much as 10% of total job time!)
2613  ////
2614  if(model_.bulkJctBotGradingCoeff == .5 &&
2616  {
2617  sarg = sargsw = 1/sqrt(arg);
2618  }
2619  else
2620  {
2621  if(model_.bulkJctBotGradingCoeff == .5)
2622  {
2623  sarg = 1/sqrt(arg);
2624  }
2625  else
2626  {
2627  sarg = exp(-model_.bulkJctBotGradingCoeff*log(arg));
2628  }
2630  {
2631  sargsw = 1/sqrt(arg);
2632  }
2633  else
2634  {
2635  sargsw =exp(-model_.bulkJctSideGradingCoeff*log(arg));
2636  }
2637  }
2638  qbd =
2639  tBulkPot*(Cbd*
2640  (1-arg*sarg)
2642  +Cbdsw*
2643  (1-arg*sargsw)
2645  capbd=Cbd*sarg+
2646  Cbdsw*sargsw;
2647  }
2648  else
2649  {
2650  qbd = f4d +
2651  vbd * (f2d + vbd * f3d/2);
2652  capbd=f2d + vbd * f3d;
2653  }
2654  }
2655  else
2656  {
2657  qbd = 0;
2658  capbd = 0;
2659  }
2660 
2661  // Now after a mess of convergence stuff that seems not to apply to us
2662  // 3f5 saves the vbs, vbd, etc. in the state vector (we don't, it gets
2663  // saved in updatePrimaryState)
2664 
2665  // Then 3f5 calculates meyer capacitances, capgs, capgb and capgd
2666  // Careful! They use the local von and vdsat, which haven't got dtype
2667  // multiplying them!
2668 
2669  ////
2670  // * calculate meyer's capacitors
2671  ////
2672  ////
2673  // * new cmeyer - this just evaluates at the current time,
2674  // * expects you to remember values from previous time
2675  // * returns 1/2 of non-constant portion of capacitance
2676  // * you must add in the other half from previous time
2677  // * and the constant part
2678  ////
2679 
2680  if (mode > 0)
2681  {
2682  devSupport.qmeyer (vgs,vgd,Vgb,Von,Vdsat,
2684  }
2685  else
2686  {
2687  devSupport.qmeyer (vgd,vgs,Vgb,Von,Vdsat,
2689  }
2690 
2691 
2692  // vgs1 = vgs_old;
2693  // vgd1 = vgs1 - vds_old;
2694  // vgb1 = vgs1 - vbs_old;
2695 
2696  ////
2697  // TVR: Note! Caution with Capgs vs. capgs. If I used the instance var
2698  // capgs on the left hand side, it's OK as long as we never try to implement
2699  // meyer back averaging, since capgs is going to be recalculated each
2700  // time through. But if we do the averaging, the old one will have the
2701  // constant part and old old part added in, which is not what we wanted.
2702  // So I'll continue 3f5's way of having a local Capgs that's actually used
2703  // for the charge computation, and an instance capgs that's saved as state.
2704  ////
2705 
2706  if((getSolverState().dcopFlag))
2707  {
2708  Capgs = 2 * capgs + GateSourceOverlapCap ;
2709  Capgd = 2 * capgd + GateDrainOverlapCap ;
2710  Capgb = 2 * capgb + GateBulkOverlapCap ;
2711  }
2712  else
2713  {
2714  capgs_old = (*extData.currStaVectorPtr)[li_state_capgs];
2715  capgd_old = (*extData.currStaVectorPtr)[li_state_capgd];
2716  capgb_old = (*extData.currStaVectorPtr)[li_state_capgb];
2717 
2718  Capgs = ( capgs+
2719  capgs_old +
2721  Capgd = ( capgd+
2722  capgd_old +
2724  Capgb = ( capgb+
2725  capgb_old +
2727  }
2728 
2729  // Eric does this kludge in level 1, so I'll do it to make sure capacitances
2730  // are positive
2731  Capgs *= (Capgs < 0.0)?-1.0:1.0;
2732  Capgd *= (Capgd < 0.0)?-1.0:1.0;
2733  Capgb *= (Capgb < 0.0)?-1.0:1.0;
2734 
2735 
2736  // in the sequel, I'll refer to all derivatives of currents w.r.t. voltages
2737  // as conductances, whether they really are or not.
2738 
2739  // when we get here, cdrain has the channel current
2740  // cbd and cbs have the currents through the diodes
2741  // cd has the drain current minus the diode current and seems only to be used
2742  // for 3f5 convergence stuff
2743  // qbs and qbd have the charges on the parasitic capacitors
2744  // capbs and capbd have the capacitances of the parasitics.
2745 
2746  // none of the charges for the gate capacitors have been calculated yet.
2747  // We've saved the capacitances, so we can get the charges in
2748  // updatePrimaryState later.
2749 
2750  // Conductances:
2751  // gbd: the bulk-drain' conductance without the capacitor components
2752  // We'll need to get the capacitor contribution in the actual load
2753  // using C*dt
2754  // gbs: bulk-source' without capacitor
2755  // gm = derivative of channel current w.r.t. gate-source voltage --- gotta
2756  // account for mode=normal or mode=reverse when using this!
2757  // gmbs = derivative of channel current w.r.t bulk-source voltage
2758  // gds = derivative of channel current w.r.t. drain-source voltage
2759 
2760  // the variables gcgs, gcgb, gcgd should be the conductances for the gate
2761  // capacitors, but we won't do those here (vide supra), we'll do them
2762  // in the jacobian load given the capacitances.
2763 
2764  // Now 3f5 doesn't do the resistor currents in the RHS load, because of
2765  // how they do their numerics. We do, so let's save those here.
2766 
2769 
2770  if (mode >= 0) // Normal mode
2771  {
2772  Gm = gm; // (xnrm-xrev)*gm in 3f5
2773  Gmbs = gmbs; // (xnrm-xrev)*gmbs in 3f5
2774  nrmsum = Gm+Gmbs; // xnrm*(gm+gmbs)
2775  revsum = 0; // xrev*(gm+gmbs)
2777  }
2778  else
2779  {
2780  Gm = -gm;
2781  Gmbs = -gmbs;
2782  nrmsum = 0;
2783  revsum = -(Gm+Gmbs); // because Gm and Gmbs already have - in them!
2784  cdreq = -(model_.dtype)*cdrain;
2785  }
2786 
2787  // It is now essential to restore the vds/vgs/vgd variables that might
2788  // have been tweaked by homotopy, lest they have an effect on RHS
2789  // Jdxp terms.
2790 
2791  vds=vds_save;
2792  vgs=vgs_save;
2793  vgd=vgd_save;
2794 
2795  /// CURRENTS to load into RHS:
2796 
2797  // so at this point:
2798 
2799  // current out of drain is
2800  // Idrain
2801 
2802  // current out of gate:
2803  // dtype*( (deriv of qgs) + (deriv of qgd) + (deriv of qgb))
2804 
2805  // the current *out of* the source should be simply
2806  // Isource.
2807 
2808  // current out of bulk is
2809  // dtype*(deriv of qbd) + dtype*cbd + dtype*cbs + dtype*(deriv of qbs)
2810  // - dtype*(deriv of qgb)
2811 
2812  // current out of drain' is
2813  // -Idrain - dtype*(deriv of qgd) - (deriv of qbd) - dtype*cbd +
2814  // mode*dtype*cdrain
2815 
2816  // the current out of the source' is
2817  // -Isource - dtype*(deriv of qgs) - dtype*cbs - (deriv of qbs) -
2818  // mode*dtype*cdrain
2819 
2820  //////Conductances to load into Jacobian as they relate to things here:
2821  /// all of the places where I say Cap/dt I really mean dtype*Cap/dt for
2822  // the meyer capacitors. No dtype for the parasitics, though
2823 
2824  // 3f5 handles the mode by doing:
2825  // where xnrm=1, xrev=0 if mode>=0, xnrm=0,xrev=1 if mode<0
2826 
2827  // drain-drain = a = drainConductance
2828  // drain-drain' = b = -drainConductance
2829 
2830  // gate-gate = c = "gcgd+gcgs+gcgb" = Capgd/dt+Capgs/dt+Capgb/dt
2831  // gate-bulk = d = -gcgb = -Capgb/dt
2832  // gate-drain' = e = -gcgd = -Capgd/dt
2833  // gate-source' = f = -gcgs = -Capgs/dt
2834 
2835  // source-source = g = sourceConductance
2836  // source-source' = h = -sourceConductance
2837 
2838  // bulk-gate = i = -gcgb = -Capgb/dt
2839  // bulk-bulk = j = gbs+gbd+gcgb+parasitics=gbs+gbd+Capgb/dt+capbs/dt+capbd/dt
2840  // bulk-drain' = k= -gbd-capbd/dt
2841  // bulk-source' = l= -gbs-capbs/dt
2842 
2843  // drain'-drain = m = -drainConductance
2844  // drain'-gate = n = (xnrm-xrev)*gm-Capgd/dt
2845  // drain'-bulk = o = -gbd-capbd/dt+(xnrm-xrev)*gmbs
2846  // drain'-drain' = p = drainConductance+gds+gbd+capbd/dt+
2847  // xrev*(gm+gmbs)+ Capgd/dt
2848  // drain'-source' = q = -gds-xnrm*(gm+gmbs)
2849 
2850  // source'-gate = r = -(xnrm-xrev)*gm-Capgs/dt
2851  // source'-source = s = -sourceConductance
2852  // source'-bulk = t = -gbs-capbs/dt-(xnrm-xrev)*gmbs
2853  // source'-drain' = u= -gds-xrev*(gm+gmbs)
2854  // source'-source' = v = sourceConductance+gds+gbs+capbs/dt+xnrm*(gm+gmbs)+
2855  // Capgs/dt
2856 
2857  return bsuccess;
2858 }
2859 
2860 //-----------------------------------------------------------------------------
2861 // Function : Instance::updateTemperature
2862 // Purpose :
2863 // Special Notes :
2864 // Scope : public
2865 // Creator : Eric Keiter
2866 // Creation Date : 02/27/01
2867 //-----------------------------------------------------------------------------
2868 bool Instance::updateTemperature ( const double & temp_tmp)
2869 {
2870  // mos3temp vars
2871  double czbd; // zero voltage bulk-drain capacitance
2872  double czbdsw; // zero voltage bulk-drain sidewall capacitance
2873  double czbs; // zero voltage bulk-source capacitance
2874  double czbssw; // zero voltage bulk-source sidewall capacitance
2875  double arg; // 1 - fc
2876  double sarg; // (1-fc) ^^ (-mj)
2877  double sargsw; // (1-fc) ^^ (-mjsw)
2878  double ratio,ratio4;
2879  double fact2;
2880  double kt;
2881  double egfet;
2882  double pbfact;
2883  double capfact;
2884  double phio;
2885  double pbo;
2886  double gmanew,gmaold;
2887  // end of mos3temp stuff
2888 
2889  double tnom;
2890 
2891 #ifdef Xyce_DEBUG_DEVICE
2892  if (getDeviceOptions().debugLevel > 0 && getSolverState().debugTimeFlag)
2893  {
2894  Xyce::dout() << subsection_divider << std::endl;
2895  Xyce::dout() << " Instance::Begin of updateTemperature. \n";
2896  Xyce::dout() <<" name = " << getName() << std::endl;
2897  Xyce::dout() << std::endl;
2898  }
2899 #endif
2900 
2901  // first set the instance temperature to the new temperature:
2902  if (temp_tmp != -999.0) temp = temp_tmp;
2903 
2905  {
2907  }
2908 
2909  tnom = model_.tnom;
2910  ratio = temp/tnom;
2911 
2912 #ifdef Xyce_DEBUG_DEVICE
2913  if (getDeviceOptions().debugLevel > 0 && getSolverState().debugTimeFlag)
2914  {
2915  Xyce::dout() << "Temperature = "<< temp << std::endl;
2916  Xyce::dout() << "tnom = " << tnom << std::endl;
2917  Xyce::dout() << "ratio = " << ratio << std::endl;
2918  }
2919 #endif
2920 
2921  vt = temp * CONSTKoverQ;
2922  ratio = temp/tnom;
2923  fact2 = temp/CONSTREFTEMP;
2924  kt = temp * CONSTboltz;
2925  egfet = 1.16-(7.02e-4*temp*temp)/(temp+1108);
2926  arg = -egfet/(kt+kt)+1.1150877/(CONSTboltz*(CONSTREFTEMP+CONSTREFTEMP));
2927  pbfact = -2*vt *(1.5*log(fact2)+CONSTQ*arg);
2928 
2929 #ifdef Xyce_DEBUG_DEVICE
2931  {
2932  Xyce::dout() << "vt = " << vt << std::endl;
2933  Xyce::dout() << "ratio = " << ratio << std::endl;
2934  Xyce::dout() << "fact2 = " << fact2 << std::endl;
2935  Xyce::dout() << "kt = " << kt << std::endl;
2936  Xyce::dout() << "egfet = " << egfet << std::endl;
2937  Xyce::dout() << "arg = " << arg << std::endl;
2938  Xyce::dout() << "pbfact = " << pbfact << std::endl;
2939  }
2940 #endif
2941 
2942  // in mos3temp 3f5 does a bunch of parameter defaulting (lines 155-163)
2943  // but we assume that our various parameters have been set already in
2944  // the constructors
2945 
2946  // lines 164-203 of mos3temp moved to instance block constructor
2947 
2948  // Here's the entire guts of the mos3temp instance loop, with obvious
2949  // modifications (here->MOS3 goes away, model->MOS3 turns into model_.)
2950 
2951  ratio4 = ratio * sqrt(ratio);
2953  tSurfMob = model_.surfaceMobility/ratio4;
2954  phio= (model_.phi-model_.pbfact1)/model_.fact1;
2955  tPhi = fact2 * phio + pbfact;
2956  tVbi = model_.vt0 - model_.dtype *
2957  (model_.gamma* sqrt(model_.phi))+.5*(model_.egfet1-egfet)
2958  + model_.dtype*.5* (tPhi-model_.phi);
2959  tVto = tVbi + model_.dtype * model_.gamma * sqrt(tPhi);
2963  gmaold = (model_.bulkJctPotential-pbo)/pbo;
2964  capfact = 1/(1+model_.bulkJctBotGradingCoeff*
2965  (4e-4*(model_.tnom-CONSTREFTEMP)-gmaold));
2966  tCbd = model_.capBD * capfact;
2967  tCbs = model_.capBS * capfact;
2968  tCj = model_.bulkCapFactor * capfact;
2969  capfact = 1/(1+model_.bulkJctSideGradingCoeff*
2970  (4e-4*(model_.tnom-CONSTREFTEMP)-gmaold));
2971  tCjsw = model_.sideWallCapFactor * capfact;
2972  tBulkPot = fact2 * pbo+pbfact;
2973  gmanew = (tBulkPot-pbo)/pbo;
2974  capfact = (1+model_.bulkJctBotGradingCoeff*(4e-4*(temp-CONSTREFTEMP)-gmanew));
2975  tCbd *= capfact;
2976  tCbs *= capfact;
2977  tCj *= capfact;
2978  capfact = (1+model_.bulkJctSideGradingCoeff*(4e-4*(temp-CONSTREFTEMP)-gmanew));
2979  tCjsw *= capfact;
2981 
2982  if( (model_.jctSatCurDensity == 0) || (drainArea == 0) ||
2983  (sourceArea == 0) )
2984  {
2986  vt*log(vt/(CONSTroot2*model_.jctSatCur));
2987  }
2988  else
2989  {
2990  drainVcrit = vt * log( vt / (CONSTroot2 *
2992  sourceVcrit = vt * log( vt / (CONSTroot2 *
2994  }
2995  if(model_.capBDGiven)
2996  {
2997  czbd = tCbd;
2998  }
2999  else
3000  {
3002  {
3003  czbd=tCj*drainArea;
3004  }
3005  else
3006  {
3007  czbd=0;
3008  }
3009  }
3011  {
3012  czbdsw= tCjsw * drainPerimeter;
3013  }
3014  else
3015  {
3016  czbdsw=0;
3017  }
3018  arg = 1-model_.fwdCapDepCoeff;
3019  sarg = exp( (-model_.bulkJctBotGradingCoeff) * log(arg) );
3020  sargsw = exp( (-model_.bulkJctSideGradingCoeff) * log(arg) );
3021  Cbd = czbd;
3022  Cbdsw = czbdsw;
3023  f2d = czbd*(1-model_.fwdCapDepCoeff*
3024  (1+model_.bulkJctBotGradingCoeff))* sarg/arg
3025  + czbdsw*(1-model_.fwdCapDepCoeff*
3027  sargsw/arg;
3028  f3d = czbd * model_.bulkJctBotGradingCoeff * sarg/arg/
3029  tBulkPot
3030  + czbdsw * model_.bulkJctSideGradingCoeff * sargsw/arg /
3031  tBulkPot;
3032  f4d = czbd*tBulkPot*(1-arg*sarg)/
3034  + czbdsw*tBulkPot*(1-arg*sargsw)/
3036  -f3d/2*
3037  (tDepCap*tDepCap)
3038  -tDepCap * f2d;
3039  if(model_.capBSGiven)
3040  {
3041  czbs=tCbs;
3042  }
3043  else
3044  {
3046  {
3047  czbs=tCj*sourceArea;
3048  }
3049  else
3050  {
3051  czbs=0;
3052  }
3053  }
3055  {
3056  czbssw = tCjsw * sourcePerimeter;
3057  }
3058  else
3059  {
3060  czbssw=0;
3061  }
3062  arg = 1-model_.fwdCapDepCoeff;
3063  sarg = exp( (-model_.bulkJctBotGradingCoeff) * log(arg) );
3064  sargsw = exp( (-model_.bulkJctSideGradingCoeff) * log(arg) );
3065  Cbs = czbs;
3066  Cbssw = czbssw;
3067  f2s = czbs*(1-model_.fwdCapDepCoeff*
3068  (1+model_.bulkJctBotGradingCoeff))* sarg/arg
3069  + czbssw*(1-model_.fwdCapDepCoeff*
3071  sargsw/arg;
3072  f3s = czbs * model_.bulkJctBotGradingCoeff * sarg/arg/
3073  tBulkPot
3074  + czbssw * model_.bulkJctSideGradingCoeff * sargsw/arg /
3075  tBulkPot;
3076  f4s = czbs*tBulkPot*(1-arg*sarg)/
3078  + czbssw*tBulkPot*(1-arg*sargsw)/
3080  -f3s/2*
3081  (tDepCap*tDepCap)
3082  -tDepCap * f2s;
3083 
3084  return true;
3085 }
3086 
3087 //-----------------------------------------------------------------------------
3088 // Function : Instance::updatePrimaryState
3089 // Purpose :
3090 // Special Notes :
3091 // Scope : public
3092 // Creator : Eric Keiter
3093 // Creation Date : 02/28/01
3094 //-----------------------------------------------------------------------------
3096 {
3097  bool bsuccess = true;
3098 
3099  double * staVector = extData.nextStaVectorRawPtr;
3100  double * oldstaVector = extData.currStaVectorRawPtr;
3101  double * stoVector = extData.nextStoVectorRawPtr;
3102  double * oldstoVector = extData.currStoVectorRawPtr;
3103 
3104  double vgs1, vgd1, vbs1,vgb1, vds1;
3105 
3106  bsuccess = updateIntermediateVars ();
3107 
3108  // voltage drops:
3109  stoVector[li_store_vbd] = vbd;
3110  stoVector[li_store_vbs] = vbs;
3111  stoVector[li_store_vgs] = vgs;
3112  stoVector[li_store_vds] = vds;
3113  stoVector[li_store_von] = von;
3114 
3115  // now the meyer capacitances
3116  // we didn't calculate these charges in update IntermediateVars
3117  // but we did calculate the voltage drops and capacitances.
3118  // first store the capacitances themselves:
3119  staVector[li_state_capgs] = capgs;
3120  staVector[li_state_capgd] = capgd;
3121  staVector[li_state_capgb] = capgb;
3122 
3123  // now the charges
3124  // BE CAREFUL! We can only do Q=CV for DCOP! Otherwise it's
3125  // supposed to be *INTEGRATED*:
3126  // Q = int(t0,t1)C(V)*dV --- and we approximate that by
3127  // Q(t1)-Q(t0) = CBar*(V(t1)-V(t0)) where CBar is the average.
3128  // Now with Meyer back averaging, Capxx is the average between the last
3129  // time step and this one. So we gotta do the right thing for non-DCOP
3130  // when backaverage is on.
3131 
3132  if((getSolverState().dcopFlag))
3133  {
3134  qgs = Capgs*vgs;
3135  qgd = Capgd*vgd;
3136  qgb = Capgb*Vgb;
3137  }
3138  else
3139  {
3140  // get the ones from last time step
3141  qgs = oldstaVector[li_state_qgs];
3142  qgd = oldstaVector[li_state_qgd];
3143  qgb = oldstaVector[li_state_qgb];
3144  // get the voltage drops, too
3145  vgs1 = oldstoVector[li_store_vgs];
3146  vbs1 = oldstoVector[li_store_vbs];
3147  vds1 = oldstoVector[li_store_vds];
3148 
3149  vgb1 = vgs1-vbs1;
3150  vgd1 = vgs1-vds1;
3151 
3152  // NOW we can calculate the charge update
3153  qgs += Capgs*(vgs-vgs1);
3154  qgd += Capgd*(vgd-vgd1);
3155  qgb += Capgb*((vgs-vbs)-vgb1);
3156  }
3157 
3158  staVector[li_state_qgs] = qgs;
3159  staVector[li_state_qgd] = qgd;
3160  staVector[li_state_qgb] = qgb;
3161 
3162  // and the diode parasitic capacitors
3163  // these charges were set in updateIntermediateVars
3164  staVector[li_state_qbd] = qbd;
3165  staVector[li_state_qbs] = qbs;
3166 
3167  return bsuccess;
3168 }
3169 
3170 // Additional Declarations
3171 // Class Model
3172 //-----------------------------------------------------------------------------
3173 // Function : Model::processParams
3174 // Purpose :
3175 // Special Notes :
3176 // Scope : public
3177 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
3178 // Creation Date : 6/03/02
3179 //-----------------------------------------------------------------------------
3181 {
3182  double wkfngs;
3183  double wkfng;
3184  double fermig;
3185  double fermis;
3186  double vfb;
3187  double kt1;
3188  double arg1;
3189 
3192  kt1 = CONSTboltz * tnom;
3193  egfet1 = 1.16-(7.02e-4*tnom*tnom)/(tnom+1108);
3194  arg1 = -egfet1/(kt1+kt1)+1.1150877/(CONSTboltz*(CONSTREFTEMP+CONSTREFTEMP));
3195  pbfact1 = -2*vtnom *(1.5*log(fact1)+CONSTQ*arg1);
3196 
3197  //
3198 
3199  if(!given("TOX"))
3200  {
3201  oxideThickness = 1e-7;
3202  }
3203  oxideCapFactor = 3.9 * 8.854214871e-12/oxideThickness;
3204 
3205  if(!given("UO") && !given("U0"))
3206  {
3207  surfaceMobility=600;
3208  }
3209 
3210  if (!given("KP"))
3211  {
3213  * 1e-4 * oxideCapFactor;
3214  //(m**2/cm**2)
3215  }
3216 
3217  if(given("NSUB"))
3218  {
3219  if(substrateDoping *1e6 >1.45e16)
3220  //(cm**3/m**3)
3221  {
3222  if(!given("PHI"))
3223  {
3224  phi = 2*vtnom* log(substrateDoping* 1e6 /1.45e16); // (cm**3/m**3)
3225  phi = Xycemax(.1,phi);
3226  }
3227  fermis = dtype * .5 * phi;
3228  fermis = dtype * .5 * phi;
3229  wkfng = 3.2;
3230  if(!given("TPG")) gateType=1;
3231  if(gateType != 0)
3232  {
3233  fermig = dtype * gateType*.5*egfet1;
3234  wkfng = 3.25 + .5 * egfet1 - fermig;
3235  }
3236  wkfngs = wkfng - (3.25 + .5 * egfet1 +fermis);
3237  if(!given("GAMMA"))
3238  {
3239  gamma = sqrt(2 * 11.70 * 8.854214871e-12 *
3241  // (cm**3/m**3)
3242  }
3243 
3244  if(!given("VTO"))
3245  {
3246  if(!given("NSS"))
3247  {
3249  }
3250  vfb = wkfngs - surfaceStateDensity * 1e4 * CONSTQ/oxideCapFactor;
3251  //(cm**2/m**2)
3252  vt0 = vfb + dtype * (gamma * sqrt(phi)+ phi);
3253  }
3254  else
3255  {
3256  vfb = vt0 - dtype * (gamma* sqrt(phi)+phi);
3257  }
3258  xd = sqrt((CONSTEPSSIL+CONSTEPSSIL)/
3259  (CONSTQ*substrateDoping *1e6)); //(cm**3/m**3)
3260  }
3261  else
3262  {
3263  UserError0(*this) << "Nsub < Ni";
3264 
3265  substrateDoping = 0;
3266  }
3267  }
3268 
3269  if (!given("CJ"))
3270  {
3272  substrateDoping* 1e6 /(2*bulkJctPotential));
3273  // cm**3/m**3
3274  }
3275 
3276  //
3277  return true;
3278 }
3279 
3280 //----------------------------------------------------------------------------
3281 // Function : Model::processInstanceParams
3282 // Purpose :
3283 // Special Notes :
3284 // Scope : public
3285 // Creator : Dave Shirely, PSSI
3286 // Creation Date : 03/23/06
3287 //----------------------------------------------------------------------------
3289 {
3290  std::vector<Instance*>::iterator iter;
3291  std::vector<Instance*>::iterator first = instanceContainer.begin();
3292  std::vector<Instance*>::iterator last = instanceContainer.end();
3293 
3294  for (iter=first; iter!=last; ++iter)
3295  {
3296  (*iter)->processParams();
3297  }
3298 
3299  return true;
3300 }
3301 
3302 //-----------------------------------------------------------------------------
3303 // Function : Model::Model
3304 // Purpose :
3305 // Special Notes :
3306 // Scope : public
3307 // Creator : Eric Keiter
3308 // Creation Date : 2/26/01
3309 //-----------------------------------------------------------------------------
3311  const Configuration & configuration,
3312  const ModelBlock & MB,
3313  const FactoryBlock & factory_block)
3314  : DeviceModel(MB, configuration.getModelParameters(), factory_block),
3315  dtype(CONSTNMOS),
3316  tnom(getDeviceOptions().tnom),
3317  latDiff(0.0),
3318  jctSatCurDensity(0.0),
3319  jctSatCur(0.0),
3320  drainResistance(0.0),
3321  sourceResistance(0.0),
3322  sheetResistance(0.0),
3323  transconductance(0.0),
3324  gateSourceOverlapCapFactor(0.0),
3325  gateDrainOverlapCapFactor(0.0),
3326  gateBulkOverlapCapFactor(0.0),
3327  oxideCapFactor(0.0),
3328  vt0(0.0),
3329  capBD(0.0),
3330  capBS(0.0),
3331  bulkCapFactor(0.0),
3332  sideWallCapFactor(0.0),
3333  bulkJctPotential(0.0),
3334  bulkJctBotGradingCoeff(0.0),
3335  bulkJctSideGradingCoeff(0.0),
3336  fwdCapDepCoeff(0.0),
3337  phi(0.0),
3338  gamma(0.0),
3339  lambda(0.0),
3340  substrateDoping(0.0),
3341  gateType(0),
3342  surfaceStateDensity(0.0),
3343  oxideThickness(0.0),
3344  surfaceMobility(0.0),
3345  fNcoef(0.0),
3346  fNexp(0.0),
3347  capBDGiven(0),
3348  capBSGiven(0),
3349  bulkCapFactorGiven(0),
3350  sideWallCapFactorGiven(0),
3351 
3352  fact1(0.0),
3353  vtnom(0.0),
3354  egfet1(0.0),
3355  pbfact1(0.0),
3356 
3357  xd(0.0),
3358  junctionDepth(0.0),
3359  fastSurfaceStateDensity(0.0),
3360  critField(1.0e4),
3361  critFieldExp(0.0),
3362  maxDriftVel(0.0),
3363  channelCharge(1.0),
3364  narrowFactor(0.0)
3365 
3366 {
3367  if (getType() != "")
3368  {
3369  if (getType() == "NMOS") {
3370  dtype = CONSTNMOS;
3371  }
3372  else if (getType() == "PMOS") {
3373  dtype = CONSTPMOS;
3374  }
3375  else
3376  {
3377  UserError0(*this) << "Could not recognize the type for model " << getName();
3378  }
3379  }
3380 
3381 
3382  // Set params to constant default values:
3383  setDefaultParams ();
3384 
3385  // Set params according to .model line and constant defaults from metadata:
3386  setModParams (MB.params);
3387 
3388  // Set any non-constant parameter defaults:
3389  if (!given("L"))
3391  if (!given("W"))
3393  if (!given("TNOM"))
3395  if (capBD != 0)
3396  capBDGiven = true;
3397  if (capBS != 0)
3398  capBSGiven = true;
3399 
3400  // Calculate any parameters specified as expressions:
3402 
3403  // calculate dependent (ie computed) params and check for errors:
3404  if (given("U0"))
3405  {
3406  if (given("UO"))
3407  UserError0(*this) << "Both uo and u0 have been specified and, which is not allowed";
3408  else
3409  UserWarning0(*this) << "Surface mobility has been specified as u0 instead of uo, uo is the preferred syntax";
3410 
3412  }
3413 
3414  processParams ();
3415 }
3416 
3417 //-----------------------------------------------------------------------------
3418 // Function : Model::~Model
3419 // Purpose : destructor
3420 // Special Notes :
3421 // Scope : public
3422 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
3423 // Creation Date : 3/16/00
3424 //-----------------------------------------------------------------------------
3426 {
3427  std::vector<Instance*>::iterator iter;
3428  std::vector<Instance*>::iterator first = instanceContainer.begin();
3429  std::vector<Instance*>::iterator last = instanceContainer.end();
3430 
3431  for (iter=first; iter!=last; ++iter)
3432  {
3433  delete (*iter);
3434  }
3435 
3436 }
3437 
3438 //-----------------------------------------------------------------------------
3439 // Function : Model::printOutInstances
3440 // Purpose : debugging tool.
3441 // Special Notes :
3442 // Scope : public
3443 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
3444 // Creation Date : 4/03/00
3445 //-----------------------------------------------------------------------------
3446 std::ostream &Model::printOutInstances(std::ostream &os) const
3447 {
3448  std::vector<Instance*>::const_iterator iter;
3449  std::vector<Instance*>::const_iterator first = instanceContainer.begin();
3450  std::vector<Instance*>::const_iterator last = instanceContainer.end();
3451 
3452  int i;
3453  os << std::endl;
3454  os << " name model name Parameters" << std::endl;
3455  for (i=0, iter=first; iter!=last; ++iter, ++i)
3456  {
3457  os << " " << i << ": " << (*iter)->getName() << "\t";
3458  os << getName();
3459  os << std::endl;
3460  }
3461  os << std::endl;
3462 
3463  return os;
3464 }
3465 
3466 //-----------------------------------------------------------------------------
3467 // Function : Model::forEachInstance
3468 // Purpose :
3469 // Special Notes :
3470 // Scope : public
3471 // Creator : David Baur
3472 // Creation Date : 2/4/2014
3473 //-----------------------------------------------------------------------------
3474 /// Apply a device instance "op" to all instances associated with this
3475 /// model
3476 ///
3477 /// @param[in] op Operator to apply to all instances.
3478 ///
3479 ///
3480 void Model::forEachInstance(DeviceInstanceOp &op) const /* override */
3481 {
3482  for (std::vector<Instance *>::const_iterator it = instanceContainer.begin(); it != instanceContainer.end(); ++it)
3483  op(*it);
3484 }
3485 
3486 
3487 //-----------------------------------------------------------------------------
3488 // MOSFET2 Master functions:
3489 //-----------------------------------------------------------------------------
3490 
3491 //-----------------------------------------------------------------------------
3492 // Function : Master::updateState
3493 // Purpose :
3494 // Special Notes :
3495 // Scope : public
3496 // Creator : Eric Keiter, SNL
3497 // Creation Date : 11/26/08
3498 //-----------------------------------------------------------------------------
3499 bool Master::updateState (double * solVec, double * staVec, double * stoVec)
3500 {
3501  bool bsuccess = true;
3502 
3503  for (InstanceVector::const_iterator it = getInstanceBegin(); it != getInstanceEnd(); ++it)
3504  {
3505  Instance & mi = *(*it);
3506  double * oldstaVec = mi.extData.currStaVectorRawPtr;
3507  double * stoVec = mi.extData.nextStoVectorRawPtr;
3508  double * oldstoVec = mi.extData.currStoVectorRawPtr;
3509 
3510  double vgs1(0.0), vgd1(0.0), vbs1(0.0),vgb1(0.0), vds1(0.0);
3511 
3512  bool btmp = mi.updateIntermediateVars ();
3513  bsuccess = bsuccess && btmp;
3514 
3515  // voltage drops:
3516  stoVec[mi.li_store_vbd] = mi.vbd;
3517  stoVec[mi.li_store_vbs] = mi.vbs;
3518  stoVec[mi.li_store_vgs] = mi.vgs;
3519  stoVec[mi.li_store_vds] = mi.vds;
3520  stoVec[mi.li_store_von] = mi.von;
3521 
3522  // now the meyer capacitances
3523  // we didn't calculate these charges in update IntermediateVars
3524  // but we did calculate the voltage drops and capacitances.
3525  // first store the capacitances themselves:
3526  staVec[mi.li_state_capgs] = mi.capgs;
3527  staVec[mi.li_state_capgd] = mi.capgd;
3528  staVec[mi.li_state_capgb] = mi.capgb;
3529 
3530  // now the charges
3531  // BE CAREFUL! We can only do Q=CV for DCOP! Otherwise it's
3532  // supposed to be *INTEGRATED*:
3533  // Q = int(t0,t1)C(V)*dV --- and we approximate that by
3534  // Q(t1)-Q(t0) = CBar*(V(t1)-V(t0)) where CBar is the average.
3535  // Now with Meyer back averaging, Capxx is the average between the last
3536  // time step and this one. So we gotta do the right thing for non-DCOP
3537  // when backaverage is on.
3538 
3539  if((getSolverState().dcopFlag))
3540  {
3541  mi.qgs = mi.Capgs*mi.vgs;
3542  mi.qgd = mi.Capgd*mi.vgd;
3543  mi.qgb = mi.Capgb*mi.Vgb;
3544  }
3545  else
3546  {
3547  // get the ones from last time step
3548  mi.qgs = oldstaVec[mi.li_state_qgs];
3549  mi.qgd = oldstaVec[mi.li_state_qgd];
3550  mi.qgb = oldstaVec[mi.li_state_qgb];
3551  // get the voltage drops, too
3552  vgs1 = oldstoVec[mi.li_store_vgs];
3553  vbs1 = oldstoVec[mi.li_store_vbs];
3554  vds1 = oldstoVec[mi.li_store_vds];
3555 
3556  vgb1 = vgs1-vbs1;
3557  vgd1 = vgs1-vds1;
3558 
3559  // NOW we can calculate the charge update
3560  mi.qgs += mi.Capgs*(mi.vgs-vgs1);
3561  mi.qgd += mi.Capgd*(mi.vgd-vgd1);
3562  mi.qgb += mi.Capgb*((mi.vgs-mi.vbs)-vgb1);
3563  }
3564 
3565  staVec[mi.li_state_qgs] = mi.qgs;
3566  staVec[mi.li_state_qgd] = mi.qgd;
3567  staVec[mi.li_state_qgb] = mi.qgb;
3568 
3569  // and the diode parasitic capacitors
3570  // these charges were set in updateIntermediateVars
3571  staVec[mi.li_state_qbd] = mi.qbd;
3572  staVec[mi.li_state_qbs] = mi.qbs;
3573  }
3574 
3575  return bsuccess;
3576 }
3577 
3578 //-----------------------------------------------------------------------------
3579 // Function : Master::loadDAEVectors
3580 // Purpose :
3581 // Special Notes :
3582 // Scope : public
3583 // Creator : Eric Keiter, SNL
3584 // Creation Date : 11/26/08
3585 //-----------------------------------------------------------------------------
3586 bool Master::loadDAEVectors (double * solVec, double * fVec, double *qVec, double * bVec, double * storeLeadF, double * storeLeadQ)
3587 {
3588  double gmin1 = getDeviceOptions().gmin;
3589 
3590  for (InstanceVector::const_iterator it = getInstanceBegin(); it != getInstanceEnd(); ++it)
3591  {
3592  Instance & mi = *(*it);
3593 
3594  int Dtype=mi.getModel().dtype;
3595  double ceqbs(0.0),ceqbd(0.0),ceqgb(0.0), ceqgs(0.0), ceqgd(0.0);
3596  double Qeqbs(0.0),Qeqbd(0.0),Qeqgb(0.0), Qeqgs(0.0), Qeqgd(0.0);
3597  double coef(0.0);
3598 
3599  // F-Vector:
3600  ceqbs = Dtype*(mi.cbs);
3601  ceqbd = Dtype*(mi.cbd);
3602  // These need "Dtype" here because we use them later *without*
3603  // Dtype, where SPICE uses it *with*
3604  ceqgb = 0.0;
3605  ceqgs = 0.0;
3606  ceqgd = 0.0;
3607 
3608  if (mi.drainConductance != 0.0)
3609  {
3610 
3611  fVec[mi.li_Drain] += mi.Idrain*mi.numberParallel;
3612  }
3613 
3614  coef = (ceqgs+ceqgd+ceqgb);
3615 
3616  fVec[mi.li_Gate] += coef*mi.numberParallel;
3617 
3618  if (mi.sourceConductance != 0.0)
3619  {
3620 
3621  fVec[mi.li_Source] += mi.Isource*mi.numberParallel;
3622  }
3623 
3624  coef = ceqbs + ceqbd - ceqgb;
3625 
3626  fVec[mi.li_Bulk] += coef*mi.numberParallel;
3627 
3628  coef = -mi.Idrain-(ceqbd - mi.cdreq + ceqgd);
3629 
3630  fVec[mi.li_DrainPrime] += coef*mi.numberParallel;
3631 
3632  coef = -mi.Isource-(ceqbs + mi.cdreq + ceqgs);
3633 
3634  fVec[mi.li_SourcePrime] += coef*mi.numberParallel;
3635 
3636  // Q-Vector:
3637  Qeqbs = Dtype*(mi.qbs);
3638  Qeqbd = Dtype*(mi.qbd);
3639  // These need "Dtype" here because we use them later *without*
3640  // Dtype, where SPICE uses it *with*
3641  Qeqgb = Dtype*(mi.qgb);
3642  Qeqgs = Dtype*(mi.qgs);
3643  Qeqgd = Dtype*(mi.qgd);
3644 
3645  coef = (Qeqgs+Qeqgd+Qeqgb);
3646 
3647  qVec[mi.li_Gate] += coef*mi.numberParallel;
3648 
3649  coef = Qeqbs + Qeqbd - Qeqgb;
3650 
3651  qVec[mi.li_Bulk] += coef*mi.numberParallel;
3652 
3653  coef = -(Qeqbd + Qeqgd);
3654 
3655  qVec[mi.li_DrainPrime] += coef*mi.numberParallel;
3656 
3657  coef = -(Qeqbs + Qeqgs);
3658 
3659  qVec[mi.li_SourcePrime] += coef*mi.numberParallel;
3660 
3661  // voltage limiters:
3662  if (!mi.origFlag)
3663  {
3664  // F-limiters:
3665  double coef_Jdxp4 = Dtype*(
3666  + ((mi.gbd-gmin1))*(mi.vbd-mi.vbd_orig)
3667  + ((mi.gbs-gmin1))*(mi.vbs-mi.vbs_orig));
3668 
3669  double coef_Jdxp5 = Dtype*(
3670  -((mi.gbd-gmin1))*(mi.vbd-mi.vbd_orig)
3671  +mi.gds*(mi.vds-mi.vds_orig)
3672  +mi.Gm*((mi.mode>0)?(mi.vgs-mi.vgs_orig):(mi.vgd-mi.vgd_orig))
3673  +mi.Gmbs*((mi.mode>0)?(mi.vbs-mi.vbs_orig):(mi.vbd-mi.vbd_orig)));
3674 
3675  double coef_Jdxp6 = Dtype*(
3676  -((mi.gbs-gmin1))*(mi.vbs-mi.vbs_orig)
3677  -mi.gds*(mi.vds-mi.vds_orig)
3678  -mi.Gm*((mi.mode>0)?(mi.vgs-mi.vgs_orig):(mi.vgd-mi.vgd_orig))
3679  -mi.Gmbs*((mi.mode>0)?(mi.vbs-mi.vbs_orig):(mi.vbd-mi.vbd_orig)));
3680 
3681  double * dFdxdVp = mi.extData.dFdxdVpVectorRawPtr;
3682 
3683  dFdxdVp[mi.li_Bulk ] += coef_Jdxp4*mi.numberParallel;
3684 
3685  dFdxdVp[mi.li_DrainPrime ] += coef_Jdxp5*mi.numberParallel;
3686 
3687  dFdxdVp[mi.li_SourcePrime] += coef_Jdxp6*mi.numberParallel;
3688 
3689  // Q-limiters:
3690  {
3691  double gcgd(0.0), gcgs(0.0), gcgb(0.0), gcbs(0.0), gcbd(0.0);
3692  if (getSolverState().tranopFlag || getSolverState().acopFlag || getSolverState().transientFlag)
3693  {
3694  gcgd = mi.Capgd;
3695  gcgs = mi.Capgs;
3696  gcgb = mi.Capgb;
3697  // get at the two parasitic caps the same way
3698  gcbs = mi.capbs;
3699  gcbd = mi.capbd;
3700  }
3701  else
3702  {
3703  gcgd = 0.0; gcgs = 0.0; gcgb = 0.0; gcbs = 0.0; gcbd = 0.0;
3704  }
3705 
3706  double coef_Jdxp2 =
3707  Dtype*(gcgd*(mi.vgd-mi.vgd_orig)+gcgs*(mi.vgs-mi.vgs_orig)+
3708  gcgb*(mi.vgs-mi.vgs_orig-mi.vbs+mi.vbs_orig));
3709 
3710  double coef_Jdxp4 = Dtype*(
3711  - (gcgb)*(mi.vgs-mi.vgs_orig-mi.vbs+mi.vbs_orig)
3712  + (gcgb)*(mi.vbd-mi.vbd_orig)
3713  + (gcbs)*(mi.vbs-mi.vbs_orig));
3714 
3715  double coef_Jdxp5 = Dtype*(
3716  -(gcgd)*(mi.vgd-mi.vgd_orig)
3717  -(gcbd)*(mi.vbd-mi.vbd_orig));
3718 
3719  // 6 KCL for source' node
3720  double coef_Jdxp6 = Dtype*
3721  (-gcgs*(mi.vgs-mi.vgs_orig)-(gcbs)*(mi.vbs-mi.vbs_orig));
3722 
3723  double * dQdxdVp = mi.extData.dQdxdVpVectorRawPtr;
3724  dQdxdVp[mi.li_Gate ] += coef_Jdxp2*mi.numberParallel;
3725  dQdxdVp[mi.li_Bulk ] += coef_Jdxp4*mi.numberParallel;
3726  dQdxdVp[mi.li_DrainPrime ] += coef_Jdxp5*mi.numberParallel;
3727  dQdxdVp[mi.li_SourcePrime] += coef_Jdxp6*mi.numberParallel;
3728  }
3729  }
3730 
3731  if( mi.loadLeadCurrent )
3732  {
3733  if (mi.drainConductance != 0.0)
3734  {
3735  storeLeadF[mi.li_store_dev_id] = mi.Idrain*mi.numberParallel;
3736  }
3737  else
3738  {
3739  storeLeadF[mi.li_store_dev_id] = (-mi.Idrain-(ceqbd - mi.cdreq + ceqgd))*mi.numberParallel;
3740  storeLeadQ[mi.li_store_dev_id] = (-(Qeqbd + Qeqgd))*mi.numberParallel;
3741  }
3742  if (mi.sourceConductance != 0.0)
3743  {
3744  storeLeadF[mi.li_store_dev_is] = mi.Isource*mi.numberParallel;
3745  }
3746  else
3747  {
3748  storeLeadF[mi.li_store_dev_is] = (-mi.Isource-(ceqbs + mi.cdreq + ceqgs))*mi.numberParallel;
3749  storeLeadQ[mi.li_store_dev_is] = (-(Qeqbs + Qeqgs))*mi.numberParallel;
3750  }
3751  storeLeadF[mi.li_store_dev_ig] = (ceqgs+ceqgd+ceqgb)*mi.numberParallel;
3752  storeLeadQ[mi.li_store_dev_ig] = (Qeqgs+Qeqgd+Qeqgb)*mi.numberParallel;
3753  storeLeadF[mi.li_store_dev_ib] = (ceqbs + ceqbd - ceqgb)*mi.numberParallel;
3754  storeLeadQ[mi.li_store_dev_ib] = (Qeqbs + Qeqbd - Qeqgb)*mi.numberParallel;
3755  }
3756  }
3757 
3758  return true;
3759 }
3760 
3761 
3762 #ifndef Xyce_NONPOINTER_MATRIX_LOAD
3763 //-----------------------------------------------------------------------------
3764 // Function : Master::loadDAEMatrices
3765 // Purpose :
3766 // Special Notes :
3767 // Scope : public
3768 // Creator : Eric Keiter, SNL
3769 // Creation Date : 11/26/08
3770 //-----------------------------------------------------------------------------
3771 bool Master::loadDAEMatrices (N_LAS_Matrix & dFdx, N_LAS_Matrix & dQdx)
3772 {
3773  for (InstanceVector::const_iterator it = getInstanceBegin(); it != getInstanceEnd(); ++it)
3774  {
3775  Instance & mi = *(*it);
3776 
3777  // F-matrix:
3778 
3779  *mi.f_DrainEquDrainNodePtr +=
3781 
3784 
3785 
3788 
3791 
3792 
3793  *mi.f_BulkEquBulkNodePtr +=
3794  (mi.gbs+mi.gbd)*mi.numberParallel;
3795 
3797 
3799 
3800 
3803 
3805  mi.Gm*mi.numberParallel;
3806 
3808  (-mi.gbd+mi.Gmbs)*mi.numberParallel;
3809 
3811  (mi.drainConductance+mi.gds+mi.gbd+mi.revsum)*mi.numberParallel;
3812 
3814  (-mi.gds-mi.nrmsum)*mi.numberParallel;
3815 
3816 
3818  mi.Gm*mi.numberParallel;
3819 
3822 
3824  (mi.gbs+mi.Gmbs)*mi.numberParallel;
3825 
3827  (mi.gds+mi.revsum)*mi.numberParallel;
3828 
3830  (mi.sourceConductance+mi.gds+mi.gbs+mi.nrmsum)*mi.numberParallel;
3831 
3832  // Q-matrix:
3833  double gcgd(0.0); // d(cqgd)/dVgd
3834  double gcgs(0.0); // d(cqgs)/dVgs
3835  double gcgb(0.0); // d(cqgb)/dVgb
3836  double gcbs(0.0); // d(cqbs)/dVbs
3837  double gcbd(0.0); // d(cqbd)/dVbd
3838 
3839  // get at the "conductances" for the gate capacitors with this trick
3840  // gcgd = model_.dtype*Capgd;
3841  // gcgs = model_.dtype*Capgs;
3842  // gcgb = model_.dtype*Capgb;
3843  //
3844  // In the loadRHS function, these would all be multiplied by
3845  // getSolverState().pdt. Here, for *mi.q_, the pdt term is left out.
3846  if (getSolverState().tranopFlag || getSolverState().acopFlag || getSolverState().transientFlag)
3847  {
3848  gcgd = mi.Capgd;
3849  gcgs = mi.Capgs;
3850  gcgb = mi.Capgb;
3851  // get at the two parasitic caps the same way
3852  gcbs = mi.capbs;
3853  gcbd = mi.capbd;
3854  }
3855 
3856 
3857  *mi.q_GateEquGateNodePtr +=
3858  (gcgd+gcgs+gcgb)*mi.numberParallel;
3859 
3860  *mi.q_GateEquBulkNodePtr -= gcgb*mi.numberParallel;
3861 
3863 
3865 
3866 
3867  *mi.q_BulkEquGateNodePtr -= gcgb*mi.numberParallel;
3868 
3869  *mi.q_BulkEquBulkNodePtr +=
3870  (+gcbs+gcbd+gcgb)*mi.numberParallel;
3871 
3873 
3875  +gcbs*mi.numberParallel;
3876 
3877 
3879  -gcgd*mi.numberParallel;
3880 
3882  -gcbd*mi.numberParallel;
3883 
3885  (+gcbd+gcgd)*mi.numberParallel;
3886 
3887 
3889  gcgs*mi.numberParallel;
3890 
3892  +gcbs*mi.numberParallel;
3893 
3895  (+gcbs+gcgs)*mi.numberParallel;
3896  }
3897 
3898  return true;
3899 }
3900 #else
3901 //-----------------------------------------------------------------------------
3902 // Function : Master::loadDAEMatrices
3903 // Purpose :
3904 // Special Notes :
3905 // Scope : public
3906 // Creator : Eric Keiter, SNL
3907 // Creation Date : 11/26/08
3908 //-----------------------------------------------------------------------------
3909 bool Master::loadDAEMatrices (N_LAS_Matrix & dFdx, N_LAS_Matrix & dQdx)
3910 {
3911  for (InstanceVector::const_iterator it = instanceContainer.begin(); it != instanceContainer.end(); ++it)
3912  {
3913  Instance & mi = *(*it);
3914 
3915  // F-matrix:
3916 
3917  dFdx[mi.li_Drain][mi.ADrainEquDrainNodeOffset] +=
3919 
3920  dFdx[mi.li_Drain][mi.ADrainEquDrainPrimeNodeOffset] -=
3922 
3923 
3924  dFdx[mi.li_Source][mi.ASourceEquSourceNodeOffset] +=
3926 
3929 
3930 
3931  dFdx[mi.li_Bulk][mi.ABulkEquBulkNodeOffset] +=
3932  (mi.gbs+mi.gbd)*mi.numberParallel;
3933 
3935 
3937 
3938 
3941 
3943  mi.Gm*mi.numberParallel;
3944 
3946  (-mi.gbd+mi.Gmbs)*mi.numberParallel;
3947 
3949  (mi.drainConductance+mi.gds+mi.gbd+mi.revsum)*mi.numberParallel;
3950 
3952  (-mi.gds-mi.nrmsum)*mi.numberParallel;
3953 
3954 
3956  mi.Gm*mi.numberParallel;
3957 
3960 
3962  (mi.gbs+mi.Gmbs)*mi.numberParallel;
3963 
3965  (mi.gds+mi.revsum)*mi.numberParallel;
3966 
3968  (mi.sourceConductance+mi.gds+mi.gbs+mi.nrmsum)*mi.numberParallel;
3969 
3970  // Q-matrix:
3971  double gcgd(0.0); // d(cqgd)/dVgd
3972  double gcgs(0.0); // d(cqgs)/dVgs
3973  double gcgb(0.0); // d(cqgb)/dVgb
3974  double gcbs(0.0); // d(cqbs)/dVbs
3975  double gcbd(0.0); // d(cqbd)/dVbd
3976 
3977  // get at the "conductances" for the gate capacitors with this trick
3978  // gcgd = model_.dtype*Capgd;
3979  // gcgs = model_.dtype*Capgs;
3980  // gcgb = model_.dtype*Capgb;
3981  //
3982  // In the loadRHS function, these would all be multiplied by
3983  // getSolverState().pdt. Here, for dQdx, the pdt term is left out.
3984  if (getSolverState().tranopFlag || getSolverState().acopFlag || getSolverState().transientFlag)
3985  {
3986  gcgd = mi.Capgd;
3987  gcgs = mi.Capgs;
3988  gcgb = mi.Capgb;
3989  // get at the two parasitic caps the same way
3990  gcbs = mi.capbs;
3991  gcbd = mi.capbd;
3992  }
3993 
3994 
3995  dQdx[mi.li_Gate][mi.AGateEquGateNodeOffset] +=
3996  (gcgd+gcgs+gcgb)*mi.numberParallel;
3997 
3998  dQdx[mi.li_Gate][mi.AGateEquBulkNodeOffset] -= gcgb*mi.numberParallel;
3999 
4000  dQdx[mi.li_Gate][mi.AGateEquDrainPrimeNodeOffset] -= gcgd*mi.numberParallel;
4001 
4002  dQdx[mi.li_Gate][mi.AGateEquSourcePrimeNodeOffset] -= gcgs*mi.numberParallel;
4003 
4004 
4005  dQdx[mi.li_Bulk][mi.ABulkEquGateNodeOffset] -= gcgb*mi.numberParallel;
4006 
4007  dQdx[mi.li_Bulk][mi.ABulkEquBulkNodeOffset] +=
4008  (+gcbs+gcbd+gcgb)*mi.numberParallel;
4009 
4010  dQdx[mi.li_Bulk][mi.ABulkEquDrainPrimeNodeOffset] -= +gcbd*mi.numberParallel;
4011 
4012  dQdx[mi.li_Bulk][mi.ABulkEquSourcePrimeNodeOffset] -=
4013  +gcbs*mi.numberParallel;
4014 
4015 
4017  -gcgd*mi.numberParallel;
4018 
4020  -gcbd*mi.numberParallel;
4021 
4023  (+gcbd+gcgd)*mi.numberParallel;
4024 
4025 
4027  gcgs*mi.numberParallel;
4028 
4030  +gcbs*mi.numberParallel;
4031 
4033  (+gcbs+gcgs)*mi.numberParallel;
4034  }
4035  return true;
4036 }
4037 
4038 #endif
4039 
4040 Device *Traits::factory(const Configuration &configuration, const FactoryBlock &factory_block)
4041 {
4042 
4043  return new Master(configuration, factory_block, factory_block.solverState_, factory_block.deviceOptions_);
4044 }
4045 
4047 {
4049  .registerDevice("m", 2)
4050  .registerModelType("pmos", 2)
4051  .registerModelType("nmos", 2);
4052 }
4053 
4054 } // namespace MOSFET2
4055 } // namespace Device
4056 } // namespace Xyce
4057