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.73.2.3 $
40 //
41 // Revision Date : $Date: 2014/03/06 23:33:43 $
42 //
43 // Current Owner : $Author: tvrusso $
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  // set up the internal name map:
843  std::string tmpstr;
844  if ( li_DrainPrime != li_Drain )
845  {
846  tmpstr = getName()+"_drainprime";
847  spiceInternalName (tmpstr);
848  intNameMap[ li_DrainPrime ] = tmpstr;
849  }
850 
851  if ( li_SourcePrime != li_Source )
852  {
853  tmpstr = getName()+"_sourceprime";
854  spiceInternalName (tmpstr);
855  intNameMap[ li_SourcePrime ] = tmpstr;
856  }
857  }
858 
859  return intNameMap;
860 }
861 
862 
863 //-----------------------------------------------------------------------------
864 // Function : N_DEV_MOSFET2Instance::getStoreNameMap
865 // Purpose :
866 // Special Notes :
867 // Scope : public
868 // Creator : Richard Schiek, Electrical Systems Modeling
869 // Creation Date : 4/3/2013
870 //-----------------------------------------------------------------------------
871 std::map<int,std::string> & N_DEV_MOSFET2Instance::getStoreNameMap ()
872 {
873  // set up the internal name map, if it hasn't been already.
874  if( loadLeadCurrent && storeNameMap.empty ())
875  {
876  // change subcircuitname:devicetype_deviceName to
877  // devicetype:subcircuitName:deviceName
878  std::string modName(getName());
879  spiceInternalName(modName);
880  std::string tmpstr;
881  tmpstr = modName+":DEV_ID";
882  storeNameMap[ li_store_dev_id ] = tmpstr;
883  tmpstr = modName+":DEV_IG";
884  storeNameMap[ li_store_dev_ig ] = tmpstr;
885  tmpstr = modName+":DEV_IS";
886  storeNameMap[ li_store_dev_is ] = tmpstr;
887  tmpstr = modName+":DEV_IB";
888  storeNameMap[ li_store_dev_ib ] = tmpstr;
889  }
890 
891  return storeNameMap;
892 }
893 
894 //-----------------------------------------------------------------------------
895 // Function : Instance::registerStateLIDs
896 // Purpose :
897 // Special Notes :
898 // Scope : public
899 // Creator : Robert Hoekstra, Computational Sciences
900 // Creation Date : 6/21/02
901 //-----------------------------------------------------------------------------
902 void Instance::registerStateLIDs( const std::vector<int> & staLIDVecRef )
903 {
904  AssertLIDs(staLIDVecRef.size() == numStateVars);
905 
906 #ifdef Xyce_DEBUG_DEVICE
907  if (getDeviceOptions().debugLevel > 0)
908  {
909  Xyce::dout() << std::endl;
910  Xyce::dout() << section_divider << std::endl;
911  Xyce::dout() << " In Instance::registerStateLIDs\n\n";
912  Xyce::dout() << " name = " << getName() << std::endl;
913  Xyce::dout() << " Number of State LIDs: " << numStateVars << std::endl;
914  }
915 #endif
916 
917  // Copy over the global ID lists:
918  staLIDVec = staLIDVecRef;
919 
920  int lid=0;
921 
922  li_state_qgs = staLIDVec[lid++];
923  li_state_qgd = staLIDVec[lid++];
924  li_state_qgb = staLIDVec[lid++];
925 
926  li_state_capgs = staLIDVec[lid++];
927  li_state_capgd = staLIDVec[lid++];
928  li_state_capgb = staLIDVec[lid++];
929 
930  li_state_qbd = staLIDVec[lid++];
931  li_state_qbs = staLIDVec[lid++];
932 
933 
934 #ifdef Xyce_DEBUG_DEVICE
935  if (getDeviceOptions().debugLevel > 0)
936  {
937  Xyce::dout() << " State local indices:" << std::endl;
938  Xyce::dout() << std::endl;
939 
940  Xyce::dout() << " li_state_qgs = " << li_state_qgs ;
941  Xyce::dout() << " li_state_capgs = " << li_state_capgs;
942  Xyce::dout() << " li_state_capgd = " << li_state_capgd;
943  Xyce::dout() << " li_state_capgb = " << li_state_capgb;
944  Xyce::dout() << " li_state_qgd = " << li_state_qgd;
945  Xyce::dout() << " li_state_qgb = " << li_state_qgb;
946  Xyce::dout() << " li_state_qbs = " << li_state_qbs;
947  Xyce::dout() << " li_state_qbd = " << li_state_qbd;
948 
949  Xyce::dout() << std::endl;
950  Xyce::dout() << section_divider << std::endl;
951  }
952 #endif
953 
954 }
955 
956 //-----------------------------------------------------------------------------
957 // Function : Instance::registerStoreLIDs
958 // Purpose :
959 // Special Notes :
960 // Scope : public
961 // Creator : Eric Keiter, Computational Sciences
962 // Creation Date : 12/9/11
963 //-----------------------------------------------------------------------------
964 void Instance::registerStoreLIDs( const std::vector<int> & stoLIDVecRef )
965 {
966  AssertLIDs(stoLIDVecRef.size() == getNumStoreVars());
967 
968  // Copy over the global ID lists:
969  stoLIDVec = stoLIDVecRef;
970 
971  int lid=0;
972  li_store_vbd = stoLIDVec[lid++];
973  li_store_vbs = stoLIDVec[lid++];
974  li_store_vgs = stoLIDVec[lid++];
975  li_store_vds = stoLIDVec[lid++];
976  li_store_von = stoLIDVec[lid++];
977 
978  if( loadLeadCurrent )
979  {
980  li_store_dev_id = stoLIDVec[lid++];
981  li_store_dev_ig = stoLIDVec[lid++];
982  li_store_dev_is = stoLIDVec[lid++];
983  li_store_dev_ib = stoLIDVec[lid++];
984  }
985 }
986 
987 //-----------------------------------------------------------------------------
988 // Function : Instance::jacobianStamp
989 // Purpose :
990 // Special Notes :
991 // Scope : public
992 // Creator : Robert Hoekstra, Computational Sciences
993 // Creation Date : 9/3/02
994 //-----------------------------------------------------------------------------
995 const std::vector< std::vector<int> > & Instance::jacobianStamp() const
996 {
997  if( drainConductance != 0.0 && sourceConductance != 0.0 )
998  return jacStamp_DC_SC;
999  else if( drainConductance != 0.0 && sourceConductance == 0.0 )
1000  return jacStamp_DC;
1001  else if( drainConductance == 0.0 && sourceConductance != 0.0 )
1002  return jacStamp_SC;
1003 
1004  return jacStamp;
1005 }
1006 
1007 //-----------------------------------------------------------------------------
1008 // Function : Instance::registerJacLIDs
1009 // Purpose :
1010 // Special Notes :
1011 // Scope : public
1012 // Creator : Robert Hoekstra, Computational Sciences
1013 // Creation Date : 9/3/02
1014 //-----------------------------------------------------------------------------
1015 void Instance::registerJacLIDs( const std::vector< std::vector<int> > & jacLIDVec )
1016 {
1017  DeviceInstance::registerJacLIDs( jacLIDVec );
1018  std::vector<int> map;
1019  std::vector< std::vector<int> > map2;
1020 
1021  if (drainConductance != 0.0)
1022  {
1023  if (sourceConductance != 0.0)
1024  {
1025  map = jacMap_DC_SC;
1026  map2 = jacMap2_DC_SC;
1027  }
1028  else
1029  {
1030  map = jacMap_DC;
1031  map2 = jacMap2_DC;
1032  }
1033  }
1034  else
1035  {
1036  if (sourceConductance != 0.0)
1037  {
1038  map = jacMap_SC;
1039  map2 = jacMap2_SC;
1040  }
1041  else
1042  {
1043  map = jacMap;
1044  map2 = jacMap2;
1045  }
1046  }
1047  ADrainEquDrainNodeOffset = jacLIDVec[map[0]][map2[0][0]];
1048  ADrainEquDrainPrimeNodeOffset = jacLIDVec[map[0]][map2[0][1]];
1049 
1050  AGateEquGateNodeOffset = jacLIDVec[map[1]][map2[1][0]];
1051  AGateEquBulkNodeOffset = jacLIDVec[map[1]][map2[1][1]];
1052  AGateEquDrainPrimeNodeOffset = jacLIDVec[map[1]][map2[1][2]];
1053  AGateEquSourcePrimeNodeOffset = jacLIDVec[map[1]][map2[1][3]];
1054 
1055  ASourceEquSourceNodeOffset = jacLIDVec[map[2]][map2[2][0]];
1056  ASourceEquSourcePrimeNodeOffset = jacLIDVec[map[2]][map2[2][1]];
1057 
1058  ABulkEquGateNodeOffset = jacLIDVec[map[3]][map2[3][0]];
1059  ABulkEquBulkNodeOffset = jacLIDVec[map[3]][map2[3][1]];
1060  ABulkEquDrainPrimeNodeOffset = jacLIDVec[map[3]][map2[3][2]];
1061  ABulkEquSourcePrimeNodeOffset = jacLIDVec[map[3]][map2[3][3]];
1062 
1063  ADrainPrimeEquDrainNodeOffset = jacLIDVec[map[4]][map2[4][0]];
1064  ADrainPrimeEquGateNodeOffset = jacLIDVec[map[4]][map2[4][1]];
1065  ADrainPrimeEquBulkNodeOffset = jacLIDVec[map[4]][map2[4][2]];
1066  ADrainPrimeEquDrainPrimeNodeOffset = jacLIDVec[map[4]][map2[4][3]];
1067  ADrainPrimeEquSourcePrimeNodeOffset = jacLIDVec[map[4]][map2[4][4]];
1068 
1069  ASourcePrimeEquGateNodeOffset = jacLIDVec[map[5]][map2[5][0]];
1070  ASourcePrimeEquSourceNodeOffset = jacLIDVec[map[5]][map2[5][1]];
1071  ASourcePrimeEquBulkNodeOffset = jacLIDVec[map[5]][map2[5][2]];
1072  ASourcePrimeEquDrainPrimeNodeOffset = jacLIDVec[map[5]][map2[5][3]];
1073  ASourcePrimeEquSourcePrimeNodeOffset = jacLIDVec[map[5]][map2[5][4]];
1074 }
1075 
1076 //-----------------------------------------------------------------------------
1077 // Function : Instance::setupPointers
1078 // Purpose :
1079 // Special Notes :
1080 // Scope : public
1081 // Creator : Eric Keiter, SNL
1082 // Creation Date : 12/06/08
1083 //-----------------------------------------------------------------------------
1085 {
1086 #ifndef Xyce_NONPOINTER_MATRIX_LOAD
1087  N_LAS_Matrix & dFdx = *(extData.dFdxMatrixPtr);
1088  N_LAS_Matrix & dQdx = *(extData.dQdxMatrixPtr);
1089 
1090  // F-pointers:
1093 
1098 
1101 
1106 
1112 
1118 
1119  // Q-pointers:
1122 
1127 
1130 
1135 
1141 
1147 #endif
1148 }
1149 
1150 //-----------------------------------------------------------------------------
1151 // Function : Instance::loadDAEQVector
1152 //
1153 // Purpose : Loads the Q-vector contributions for a single
1154 // diode instance.
1155 //
1156 // Special Notes : The "Q" vector is part of a standard DAE formalism in
1157 // which the system of equations is represented as:
1158 //
1159 // f(x) = dQ(x)/dt + F(x) - B(t) = 0
1160 //
1161 // This is similar to the loadRHS function, only this function
1162 // only loads capacitor charges, and loads them into the daeQ vector.
1163 //
1164 // Scope : public
1165 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1166 // Creation Date : 03/06/04
1167 //-----------------------------------------------------------------------------
1169 {
1170  double * qVec = extData.daeQVectorRawPtr;
1171  double coef(0.0);
1172 
1173  double Qeqbs(0.0),Qeqbd(0.0),Qeqgb(0.0), Qeqgs(0.0), Qeqgd(0.0);
1174  //double ceqbs,ceqbd,ceqgb, ceqgs, ceqgd; // 3f5 vars
1175  int Dtype=model_.dtype;
1176 
1177  // do the same Dtype corrections on the charges that
1178  // are performed on the currents in the loadRHS function.
1179 
1180  // What is cbs and cbd? They are diode currents (from exponentials),
1181  // so they are left out of this function.
1182  Qeqbs = Dtype*(qbs);
1183  Qeqbd = Dtype*(qbd);
1184  // These need "Dtype" here because we use them later *without*
1185  // Dtype, where SPICE uses it *with*
1186  Qeqgb = Dtype*(qgb);
1187  Qeqgs = Dtype*(qgs);
1188  Qeqgd = Dtype*(qgd);
1189 
1190  // 2 KCL for gate node
1191  coef = (Qeqgs+Qeqgd+Qeqgb);
1192  qVec[li_Gate] += coef*numberParallel;
1193 
1194  // 4 KCL for bulk node
1195  coef = Qeqbs + Qeqbd - Qeqgb;
1196  qVec[li_Bulk] += coef*numberParallel;
1197 
1198  // 5 KCL for drain' node
1199  coef = -(Qeqbd + Qeqgd);
1200  qVec[li_DrainPrime] += coef*numberParallel;
1201 
1202  // 6 KCL for source' node
1203  coef = -(Qeqbs + Qeqgs);
1204  qVec[li_SourcePrime] += coef*numberParallel;
1205 
1206  // Same as for the loadRHS function, but with capacitive terms:
1207  // gcgd = Capgd;
1208  // gcgs = Capgs;
1209  // gcgb = Capgb;
1210  // gcbs = capbs;
1211  // gcbd = capbd;
1212 
1213  if( loadLeadCurrent )
1214  {
1215  double * storeLeadQ = extData.storeLeadCurrQCompRawPtr;
1216  if (drainConductance == 0.0)
1217  {
1218  storeLeadQ[li_store_dev_id] = (-(Qeqbd + Qeqgd))*numberParallel;
1219  }
1220  if (sourceConductance == 0.0)
1221  {
1222  storeLeadQ[li_store_dev_is] = (-(Qeqbs + Qeqgs))*numberParallel;
1223  }
1224  storeLeadQ[li_store_dev_ig] = (Qeqgs+Qeqgd+Qeqgb)*numberParallel;
1225  storeLeadQ[li_store_dev_ib] = (Qeqbs + Qeqbd - Qeqgb)*numberParallel;
1226  }
1227 
1228  if(!origFlag)
1229  {
1230  // THe setup of gcgd, etc. is the same as in the loadDAEdQdxVector
1231  // function.
1232  double gcgd, gcgs, gcgb, gcbs, gcbd;
1234  {
1235  gcgd = Capgd;
1236  gcgs = Capgs;
1237  gcgb = Capgb;
1238  // get at the two parasitic caps the same way
1239  gcbs = capbs;
1240  gcbd = capbd;
1241  }
1242  else
1243  {
1244  gcgd = 0.0; gcgs = 0.0; gcgb = 0.0; gcbs = 0.0; gcbd = 0.0;
1245  }
1246 
1247  // KCL 2
1248  double coef_Jdxp2 = Dtype*(gcgd*(vgd-vgd_orig)+gcgs*(vgs-vgs_orig)+
1249  gcgb*(vgs-vgs_orig-vbs+vbs_orig));
1250 
1251  // 4 KCL for bulk node
1252  double coef_Jdxp4 = Dtype*(
1253  - (gcgb)*(vgs-vgs_orig-vbs+vbs_orig)
1254  + (gcgb)*(vbd-vbd_orig)
1255  + (gcbs)*(vbs-vbs_orig));
1256 
1257  // 5 KCL for drain' node
1258  double coef_Jdxp5 = Dtype*(
1259  -(gcgd)*(vgd-vgd_orig)
1260  -(gcbd)*(vbd-vbd_orig));
1261 
1262  // 6 KCL for source' node
1263  double coef_Jdxp6 = Dtype*(-gcgs*(vgs-vgs_orig)-(gcbs)*(vbs-vbs_orig));
1264 
1265  double * dQdxdVp = extData.dQdxdVpVectorRawPtr;
1266  dQdxdVp[li_Gate ] += coef_Jdxp2*numberParallel;
1267  dQdxdVp[li_Bulk ] += coef_Jdxp4*numberParallel;
1268  dQdxdVp[li_DrainPrime ] += coef_Jdxp5*numberParallel;
1269  dQdxdVp[li_SourcePrime] += coef_Jdxp6*numberParallel;
1270  }
1271 
1272  return true;
1273 }
1274 
1275 //-----------------------------------------------------------------------------
1276 // Function : Instance::loadDAEFVector
1277 //
1278 // Purpose : Loads the F-vector contributions for a single
1279 // diode instance.
1280 //
1281 // Special Notes : See the special notes for loadDAEFVector.
1282 //
1283 // Scope : public
1284 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1285 // Creation Date : 03/06/04
1286 //-----------------------------------------------------------------------------
1288 {
1289  double * fVec = extData.daeFVectorRawPtr;
1290  double coef(0.0);
1291  double ceqbs(0.0),ceqbd(0.0),ceqgb(0.0), ceqgs(0.0), ceqgd(0.0); // 3f5 vars
1292  double gmin1 = getDeviceOptions().gmin;
1293 
1294  int Dtype=model_.dtype;
1295 
1296  // The next few lines are the same as for loadRHS, except
1297  // the capcitor current terms have been set to zero here.
1298  ceqbs = Dtype*(cbs);
1299  ceqbd = Dtype*(cbd);
1300  // These need "Dtype" here because we use them later *without*
1301  // Dtype, where SPICE uses it *with*
1302  ceqgb = 0.0;
1303  ceqgs = 0.0;
1304  ceqgd = 0.0;
1305 
1306  // 1 KCL for drain node
1307  if (drainConductance != 0.0)
1308  {
1309  coef = Idrain;
1310  fVec[li_Drain] += coef*numberParallel;
1311  }
1312 
1313  // 2 KCL for gate node
1314  coef = (ceqgs+ceqgd+ceqgb);
1315  fVec[li_Gate] += coef*numberParallel;
1316 
1317  // 3 KCL for source node
1318  if (sourceConductance != 0.0)
1319  {
1320  coef = Isource;
1321  fVec[li_Source] += coef*numberParallel;
1322  }
1323 
1324  // 4 KCL for bulk node
1325  coef = ceqbs + ceqbd - ceqgb;
1326  fVec[li_Bulk] += coef*numberParallel;
1327 
1328  // 5 KCL for drain' node
1329  coef = -Idrain-(ceqbd - cdreq + ceqgd);
1330  fVec[li_DrainPrime] += coef*numberParallel;
1331 
1332  // 6 KCL for source' node
1333  coef = -Isource-(ceqbs + cdreq + ceqgs);
1334  fVec[li_SourcePrime] += coef*numberParallel;
1335 
1336  // Same as for the loadRHS function, but without capacitive terms:
1337  // gcgd = Capgd;
1338  // gcgs = Capgs;
1339  // gcgb = Capgb;
1340  // gcbs = capbs;
1341  // gcbd = capbd;
1342  if (!origFlag)
1343  {
1344  // 4 KCL for bulk node
1345  double coef_Jdxp4 = Dtype*(
1346  + ((gbd-gmin1))*(vbd-vbd_orig)
1347  + ((gbs-gmin1))*(vbs-vbs_orig));
1348 
1349  // 5 KCL for drain' node
1350  double coef_Jdxp5 = Dtype*(
1351  -((gbd-gmin1))*(vbd-vbd_orig)
1352  +gds*(vds-vds_orig)
1353  +Gm*((mode>0)?(vgs-vgs_orig):(vgd-vgd_orig))
1354  +Gmbs*((mode>0)?(vbs-vbs_orig):(vbd-vbd_orig)));
1355 
1356  // 6 KCL for source' node
1357  double coef_Jdxp6 = Dtype*(
1358  -((gbs-gmin1))*(vbs-vbs_orig)
1359  -gds*(vds-vds_orig)
1360  -Gm*((mode>0)?(vgs-vgs_orig):(vgd-vgd_orig))
1361  -Gmbs*((mode>0)?(vbs-vbs_orig):(vbd-vbd_orig)));
1362 
1363  double * dFdxdVp = extData.dFdxdVpVectorRawPtr;
1364  dFdxdVp[li_Bulk ] += coef_Jdxp4*numberParallel;
1365  dFdxdVp[li_DrainPrime ] += coef_Jdxp5*numberParallel;
1366  dFdxdVp[li_SourcePrime] += coef_Jdxp6*numberParallel;
1367  }
1368 
1369  if( loadLeadCurrent )
1370  {
1371  double * storeLeadF = extData.nextStoVectorRawPtr;
1372  if (drainConductance != 0.0)
1373  {
1374  storeLeadF[li_store_dev_id] = Idrain*numberParallel;
1375  }
1376  else
1377  {
1378  storeLeadF[li_store_dev_id] = (-Idrain-(ceqbd - cdreq + ceqgd))*numberParallel;
1379  }
1380  if (sourceConductance != 0.0)
1381  {
1382  storeLeadF[li_store_dev_is] = Isource*numberParallel;
1383  }
1384  else
1385  {
1386  storeLeadF[li_store_dev_is] = (-Isource-(ceqbs + cdreq + ceqgs))*numberParallel;
1387  }
1388  storeLeadF[li_store_dev_ig] = (ceqgs+ceqgd+ceqgb)*numberParallel;
1389  storeLeadF[li_store_dev_ib] = (ceqbs + ceqbd - ceqgb)*numberParallel;
1390  }
1391 
1392  return true;
1393 }
1394 
1395 //-----------------------------------------------------------------------------
1396 // Function : Instance::loadDAEdQdx
1397 //
1398 // Purpose : Loads the Q-vector contributions for a single
1399 // diode instance.
1400 //
1401 // Special Notes : The "Q" vector is part of a standard DAE formalism in
1402 // which the system of equations is represented as:
1403 //
1404 // f(x) = dQ(x)/dt + F(x) - B(t) = 0
1405 //
1406 // Scope : public
1407 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1408 // Creation Date : 03/06/04
1409 //-----------------------------------------------------------------------------
1411 {
1412  N_LAS_Matrix & dQdx = *(extData.dQdxMatrixPtr);
1413 
1414  double gcgd(0.0); // d(cqgd)/dVgd
1415  double gcgs(0.0); // d(cqgs)/dVgs
1416  double gcgb(0.0); // d(cqgb)/dVgb
1417  double gcbs(0.0); // d(cqbs)/dVbs
1418  double gcbd(0.0); // d(cqbd)/dVbd
1419 
1420  // get at the "conductances" for the gate capacitors with this trick
1421  // gcgd = model_.dtype*Capgd;
1422  // gcgs = model_.dtype*Capgs;
1423  // gcgb = model_.dtype*Capgb;
1424  //
1425  // In the loadRHS function, these would all be multiplied by
1426  // getSolverState().pdt. Here, for dQdx, the pdt term is left out.
1427  if (getSolverState().tranopFlag || getSolverState().acopFlag || getSolverState().transientFlag)
1428  {
1429  gcgd = Capgd;
1430  gcgs = Capgs;
1431  gcgb = Capgb;
1432  // get at the two parasitic caps the same way
1433  gcbs = capbs;
1434  gcbd = capbd;
1435  }
1436 
1438  (gcgd+gcgs+gcgb)*numberParallel;
1442 
1445  (+gcbs+gcbd+gcgb)*numberParallel;
1448  +gcbs*numberParallel;
1449 
1451  -gcgd*numberParallel;
1453  -gcbd*numberParallel;
1455  (+gcbd+gcgd)*numberParallel;
1456 
1458  gcgs*numberParallel;
1460  +gcbs*numberParallel;
1462  (+gcbs+gcgs)*numberParallel;
1463 
1464  return true;
1465 }
1466 
1467 //-----------------------------------------------------------------------------
1468 // Function : Instance::loadDAEdFdx ()
1469 //
1470 // Purpose : Loads the F-vector contributions for a single
1471 // diode instance.
1472 //
1473 // Special Notes :
1474 //
1475 // Scope : public
1476 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1477 // Creation Date : 03/06/04
1478 //-----------------------------------------------------------------------------
1480 {
1481  N_LAS_Matrix & dFdx = *(extData.dFdxMatrixPtr);
1482 
1487 
1492 
1494  (gbs+gbd)*numberParallel;
1497 
1503  (-gbd+Gmbs)*numberParallel;
1505  (drainConductance+gds+gbd+revsum)*numberParallel;
1507  (-gds-nrmsum)*numberParallel;
1508 
1514  (gbs+Gmbs)*numberParallel;
1516  (gds+revsum)*numberParallel;
1518  (sourceConductance+gds+gbs+nrmsum)*numberParallel;
1519 
1520  return true;
1521 }
1522 
1523 //-----------------------------------------------------------------------------
1524 // Function : Instance::updateIntermediateVars
1525 // Purpose :
1526 // Special Notes :
1527 // Scope : public
1528 // Creator : Eric Keiter
1529 // Creation Date : 03/01/01
1530 //-----------------------------------------------------------------------------
1532 {
1533  bool bsuccess = true;
1534 
1535  // 3f5 likes to use the same variable names in local variables and in
1536  // structures. Messes with us! Define some local versions with capitals
1537  // instead
1538  double Von;
1539  double Vdsat;
1540  double Beta;
1541  //
1542  double evbs;
1543  double evbd;
1544  double sarg;
1545  double sargsw;
1546  // double vgs1;
1547  // double vgd1;
1548  // double vgb1;
1549  double arg;
1550  int Check = 1;
1551 
1552  double capgs_old;
1553  double capgd_old;
1554  double capgb_old;
1555 
1556  // temporary storage for vgs/vgd/vds so that homotopy doesn't impact
1557  // voltage limiting "jdxp" terms
1558 
1559  double vgs_save;
1560  double vgd_save;
1561  double vds_save;
1562 
1563  // This is one of the vars that are set up at the top of mos1load that
1564  // should *not* be moved to the instance constructor! tTransconductance
1565  // is set by updateTemperature. Perhaps I should remove it from the
1566  // instance variables, too, since now it's pretty much a local thing.
1567  // same goes for the other things that depend on the t* variables!
1568 
1569  if( (tSatCurDens == 0) || (drainArea == 0) || (sourceArea == 0))
1570  {
1571  DrainSatCur = tSatCur;
1573  }
1574  else
1575  {
1578  }
1580 
1581  // we need our solution variables for any of this stuff
1588 
1589  // now we need voltage drops
1590  Vddp = Vd - Vdp;
1591  Vssp = Vs - Vsp;
1592  Vbsp = Vb - Vsp;
1593  Vbdp = Vb - Vdp;
1594  Vgsp = Vg - Vsp;
1595  Vgdp = Vg - Vdp;
1596  Vgb = Vg - Vb;
1597  Vdpsp = Vdp - Vsp;
1598 
1599  // Now the things that the 3f5 code really uses (from mos1load's
1600  // "general iteration" part at lines 276-295
1601  vbs = model_.dtype * Vbsp;
1602  vgs = model_.dtype * Vgsp;
1603  vds = model_.dtype * Vdpsp;
1604 
1605  vbd = vbs-vds;
1606  vgd = vgs-vds;
1607 
1608  origFlag = 1;
1609  limitedFlag=false;
1610  vgs_orig = vgs;
1611  vds_orig = vds;
1612  vbs_orig = vbs;
1613  vbd_orig = vbd;
1614  vgd_orig = vgd;
1615 
1617  {
1618  if (IC_GIVEN)
1619  {
1620  vds = model_.dtype*icVDS;
1621  vgs = model_.dtype*icVGS;
1622  vbs = model_.dtype*icVBS;
1623  vbd = vbs - vds;
1624  vgd = vgs - vds;
1625  origFlag = false;
1626  }
1627  else
1628  {
1630  {
1631  N_LAS_Vector * flagSolVectorPtr = extData.flagSolVectorPtr;
1632  if ((*flagSolVectorPtr)[li_Drain] == 0 || (*flagSolVectorPtr)[li_Gate] == 0 ||
1633  (*flagSolVectorPtr)[li_Source] == 0 || (*flagSolVectorPtr)[li_SourcePrime] ||
1634  (*flagSolVectorPtr)[li_DrainPrime] || (*flagSolVectorPtr)[li_Bulk] )
1635  {
1636  vbs = -1;
1637  vgs = model_.dtype*tVto;
1638  vds = 0;
1639  vbd = vbs-vds;
1640  vgd = vgs-vds;
1641  }
1642  }
1643  else
1644  {
1645  vbs = -1;
1646  vgs = model_.dtype*tVto;
1647  vds = 0;
1648  vbd = vbs-vds;
1649  vgd = vgs-vds;
1650  }
1651  }
1652  }
1653  else if ((getSolverState().initFixFlag || getSolverState().initJctFlag) && OFF)
1654  {
1655  vbs = vgs = vds = 0;
1656  vbd = vgd = 0;
1657  }
1658 
1659  if (getSolverState().newtonIter == 0)
1660  {
1661 
1663  {
1668  Von = model_.dtype *
1670  }
1671  else
1672  { // otherwise there is no history
1673  vbs_old = vbs;
1674  vbd_old = vbd;
1675  vgs_old = vgs;
1676  vds_old = vds;
1677  Von = 0.0;
1678  }
1680  }
1681  else
1682  {
1687  Von = model_.dtype *
1690  }
1691 
1692  ////////////////////////////////////////////
1693  // SPICE-type Voltage Limiting
1694  ////////////////////////////////////////////
1696  {
1697  // Do not do limiting if mode initfix and OFF:
1698  if (! (getSolverState().initFixFlag && OFF))
1699  {
1700  if (vds_old >= 0)
1701  {
1702  vgs = devSupport.fetlim( vgs, vgs_old, Von);
1703  vds = vgs - vgd;
1704  vds = devSupport.limvds( vds, vds_old);
1705  vgd = vgs - vds;
1706  }
1707  else
1708  {
1709  vgd = devSupport.fetlim( vgd, vgd_old, Von);
1710  vds = vgs - vgd;
1711  vds = -devSupport.limvds( -vds, -vds_old );
1712  vgs = vgd + vds;
1713  }
1714 
1715  if (vds >= 0.0)
1716  {
1717  vbs = devSupport.pnjlim( vbs, vbs_old, vt, sourceVcrit, &Check);
1718  vbd = vbs - vds;
1719  }
1720  else
1721  {
1722  vbd = devSupport.pnjlim( vbd, vbd_old, vt, drainVcrit, &Check);
1723  vbs = vbd + vds;
1724  }
1725 
1726  // for convergence:
1727  if (Check == 1) limitedFlag=true;
1728 
1729  }
1730  }
1731 
1732  ////
1733  // now all the preliminaries are over - we can start doing the
1734  // real work
1735  ////
1736  vbd = vbs - vds;
1737  vgd = vgs - vds;
1738  Vgb = vgs - vbs;
1739 
1740  // Now set the origFlag
1741  if (vgs_orig != vgs || vds_orig != vds ||
1742  vbs_orig != vbs || vbd_orig != vbd || vgd_orig != vgd) origFlag = 0;
1743 
1744  ////
1745  // bulk-source and bulk-drain diodes
1746  // here we just evaluate the ideal diode current and the
1747  // corresponding derivative (conductance).
1748  ////
1749  if(vbs <= 0)
1750  {
1751  gbs = SourceSatCur/vt;
1752  gbs += getDeviceOptions().gmin;
1753  cbs = gbs*vbs;
1754  }
1755  else
1756  {
1757  // erkeite note: the Xycemin failsafe is in the level-1 but not the level-2.
1758  //evbs = exp(Xycemin(CONSTMAX_EXP_ARG,vbs/vt));
1759  evbs = exp(vbs/vt);
1760  gbs = (SourceSatCur*evbs/vt + getDeviceOptions().gmin);
1761  cbs = (SourceSatCur * (evbs-1) + getDeviceOptions().gmin*vbs);
1762  }
1763  if(vbd <= 0)
1764  {
1765  gbd = DrainSatCur/vt;
1766  gbd += getDeviceOptions().gmin;
1767  cbd = gbd *vbd;
1768 
1769  }
1770  else
1771  {
1772  // erkeite note: the Xycemin failsafe is in the level-1 but not the level-2.
1773  //evbd = exp(Xycemin(CONSTMAX_EXP_ARG,vbd/vt));
1774  evbd = exp(vbd/vt);
1775  gbd = (DrainSatCur*evbd/vt + getDeviceOptions().gmin);
1776  cbd = (DrainSatCur *(evbd-1)+getDeviceOptions().gmin*vbd);
1777  }
1778 
1779  // 3f5 does this simple stuff
1780  if (vds >= 0)
1781  mode = 1;
1782  else
1783  mode = -1;
1784 
1785  {
1786  //
1787  // this block of code evaluates the drain current and its
1788  // derivatives using the shichman-hodges model and the
1789  // charges associated with the gate, channel and bulk for
1790  // mosfets
1791  //
1792  //
1793 
1794  // the following 4 variables are local to this code block until
1795  // it is obvious that they can be made global
1796  //
1797  //double arg;
1798  //double betap;
1799  //double sarg;
1800  //double vgst;
1801 
1802  // Begin block of mosfet continuation code.
1803  // This idea is based, loosely, on a paper by Jaijeet
1804  // Roychowdhury.
1805 
1806  // Save these before allowing homotopy to tweak them. It
1807  // is important to restore them before moving on to
1808  // calculate RHS, because then the Jdxp terms will attempt to force
1809  // the external circuit to make these voltage drops the real thing!
1810  vds_save=vds;
1811  vgs_save=vgs;
1812  vgd_save=vgd;
1813 
1815  {
1816  double alpha = getSolverState().gainScale[blockHomotopyID];
1817  if (getDeviceOptions().staggerGainScale)
1818  {
1819  alpha *= (0.3 * randomPerturb + 1.0);
1820  if (alpha > 1.0)
1821  {
1822  alpha = 1.0;
1823  }
1824  }
1825  double vgstConst = getDeviceOptions().vgstConst;
1826  if (getDeviceOptions().randomizeVgstConst)
1827  {
1828  vgstConst *= randomPerturb;
1829  }
1830 
1831  vds = devSupport.contVds (vds, getSolverState().nltermScale, getDeviceOptions().vdsScaleMin);
1832 
1833  if (mode==1)
1834  {
1835  vgs = devSupport.contVgst (vgs, alpha, vgstConst);
1836  }
1837  else
1838  {
1839  vgd = devSupport.contVgst (vgd, alpha, vgstConst);
1840  }
1841  }
1842  // End of block of mosfet continuation code.
1843 
1844  // erkeite: This block that follows (surrounded by curly brackets) is
1845  // the main difference between the level-1 and level-2 MOSFETs in spice3.
1846  // Otherwise they are nearly identical.
1847  //
1848  // The spice3 code was embedded in the mos2load.c function. However, it
1849  // clearly was originally its own separate function. Also, it was probably
1850  // converted from fortran-66, or something like that, as it had "goto" statements
1851  // all over the place ("else" wasn't support in early versions of fortran). I've
1852  // removed all the goto's and have attempted to replace them with modern conditional
1853  // statements. If there are any mistakes here, it is in those replacements.
1854  //
1855  //
1856 // begin level-2 block:
1857 //
1858  // this routine evaluates the drain current, its derivatives and
1859  // the charges associated with the gate, channel and bulk
1860  // for mosfets
1861  {
1862  {
1863 
1864  static double sig1[4] = {1.0, -1.0, 1.0, -1.0};
1865  static double sig2[4] = {1.0, 1.0,-1.0, -1.0};
1866 
1867  double arg(0.0);
1868  double sarg(0.0);
1869  double a4[4],b4[4],x4[8],poly4[8];
1870 
1871  double beta1(0.0);
1872  double dsrgdb(0.0);
1873  double d2sdb2(0.0);
1874  double sphi(0.0); // square root of phi
1875  double sphi3(0.0); // square root of phi cubed
1876  double barg(0.0);
1877  double d2bdb2(0.0);
1878  double factor(0.0);
1879  double dbrgdb(0.0);
1880  double eta(0.0);
1881  double vbin(0.0);
1882  double argd(0.0);
1883  double args(0.0);
1884  double argss(0.0);
1885  double argsd(0.0);
1886  double argxs(0.0);
1887  double argxd(0.0);
1888  double daddb2(0.0);
1889  double dasdb2(0.0);
1890  double dbargd(0.0);
1891  double dbargs(0.0);
1892  double dbxwd(0.0);
1893  double dbxws(0.0);
1894  double dgddb2(0.0);
1895  double dgddvb(0.0);
1896  double dgdvds(0.0);
1897  double gamasd(0.0);
1898  double xwd(0.0);
1899  double xws(0.0);
1900  double ddxwd(0.0);
1901  double gammad(0.0);
1902  double vth(0.0);
1903  double cfs(0.0);
1904  double cdonco(0.0);
1905  double xn(0.0);
1906  double argg(0.0);
1907  double vgst(0.0);
1908  double sarg3(0.0);
1909  double sbiarg(0.0);
1910  double dgdvbs(0.0);
1911  double body(0.0);
1912  double gdbdv(0.0);
1913  double dodvbs(0.0);
1914  double dodvds(0.0);
1915  double dxndvd(0.0);
1916  double dxndvb(0.0);
1917  double udenom(0.0);
1918  double dudvgs(0.0);
1919  double dudvds(0.0);
1920  double dudvbs(0.0);
1921  double gammd2(0.0);
1922  double argv(0.0);
1923  double vgsx(0.0);
1924  double ufact(0.0);
1925  double ueff(0.0);
1926  double dsdvgs(0.0);
1927  double dsdvbs(0.0);
1928  double a1(0.0);
1929  double a3(0.0);
1930  double a(0.0);
1931  double b1(0.0);
1932  double b3(0.0);
1933  double b(0.0);
1934  double c1(0.0);
1935  double c(0.0);
1936  double d1(0.0);
1937  double fi(0.0);
1938  double p0(0.0);
1939  double p2(0.0);
1940  double p3(0.0);
1941  double p4(0.0);
1942  double p(0.0);
1943  double r3(0.0);
1944  double r(0.0);
1945  double ro(0.0);
1946  double s2(0.0);
1947  double s(0.0);
1948  double v1(0.0);
1949  double v2(0.0);
1950  double xv(0.0);
1951  double y3(0.0);
1952  double delta4(0.0);
1953  double xvalid(0.0);
1954  double bsarg(0.0);
1955  double dbsrdb(0.0);
1956  double bodys(0.0);
1957  double gdbdvs(0.0);
1958  double sargv(0.0);
1959  double xlfact(0.0);
1960  double dldsat(0.0);
1961  double xdv(0.0);
1962  double xlv(0.0);
1963  double vqchan(0.0);
1964  double dqdsat(0.0);
1965  double vl(0.0);
1966  double dfundg(0.0);
1967  double dfunds(0.0);
1968  double dfundb(0.0);
1969  double xls(0.0);
1970  double dldvgs(0.0);
1971  double dldvds(0.0);
1972  double dldvbs(0.0);
1973  double dfact(0.0);
1974  double clfact(0.0);
1975  double xleff(0.0);
1976  double deltal(0.0);
1977  double xwb(0.0);
1978  double vdson(0.0);
1979  double cdson(0.0);
1980  double didvds(0.0);
1981  double gdson(0.0);
1982  double gmw(0.0);
1983  double gbson(0.0);
1984  double expg(0.0);
1985  double xld(0.0);
1986  double xlamda = model_.lambda;
1987 
1988  // 'local' variables - these switch d & s around appropriately
1989  // so that we don't have to worry about vds < 0
1990  double lvbs = mode==1?vbs:vbd;
1991  double lvds = mode*vds;
1992  double lvgs = mode==1?vgs:vgd;
1993  double phiMinVbs = tPhi - lvbs;
1994  double tmp(0.0); // a temporary variable, not used for more than
1995  // about 10 lines at a time
1996  int iknt;
1997  int jknt;
1998  int i;
1999  int j;
2000 
2001  // compute some useful quantities
2002  if (lvbs <= 0.0)
2003  {
2004  sarg = sqrt(phiMinVbs);
2005  dsrgdb = -0.5/sarg;
2006  d2sdb2 = 0.5*dsrgdb/phiMinVbs;
2007  }
2008  else
2009  {
2010  sphi = sqrt(tPhi);
2011  sphi3 = tPhi*sphi;
2012  sarg = sphi/(1.0+0.5*lvbs/tPhi);
2013  tmp = sarg/sphi3;
2014  dsrgdb = -0.5*sarg*tmp;
2015  d2sdb2 = -dsrgdb*tmp;
2016  }
2017  if ((lvds-lvbs) >= 0)
2018  {
2019  barg = sqrt(phiMinVbs+lvds);
2020  dbrgdb = -0.5/barg;
2021  d2bdb2 = 0.5*dbrgdb/(phiMinVbs+lvds);
2022  }
2023  else
2024  {
2025  barg = sphi/(1.0+0.5*(lvbs-lvds)/tPhi);
2026  tmp = barg/sphi3;
2027  dbrgdb = -0.5*barg*tmp;
2028  d2bdb2 = -dbrgdb*tmp;
2029  }
2030 
2031  // calculate threshold voltage (Von)
2032  // narrow-channel effect
2033 
2034  // XXX constant per device
2036  // XXX constant per device
2037  eta = 1.0+factor;
2038  vbin = tVbi* (model_.dtype)+factor*phiMinVbs;
2039 
2040  if ((model_.gamma > 0.0) || (model_.substrateDoping > 0.0))
2041  {
2042  xwd = model_.xd*barg;
2043  xws = model_.xd*sarg;
2044 
2045  // short-channel effect with vds .ne. 0.0
2046  argss = 0.0;
2047  argsd = 0.0;
2048  dbargs = 0.0;
2049  dbargd = 0.0;
2050  dgdvds = 0.0;
2051  dgddb2 = 0.0;
2052  if (model_.junctionDepth > 0)
2053  {
2054  tmp = 2.0/model_.junctionDepth;
2055  argxs = 1.0+xws*tmp;
2056  argxd = 1.0+xwd*tmp;
2057  args = sqrt(argxs);
2058  argd = sqrt(argxd);
2060  argss = tmp * (args-1.0);
2061  argsd = tmp * (argd-1.0);
2062  }
2063  gamasd = model_.gamma*(1.0-argss-argsd);
2064  dbxwd = model_.xd*dbrgdb;
2065  dbxws = model_.xd*dsrgdb;
2066  if (model_.junctionDepth > 0)
2067  {
2068  tmp = 0.5/EffectiveLength;
2069  dbargs = tmp*dbxws/args;
2070  dbargd = tmp*dbxwd/argd;
2071  dasdb2 = -model_.xd*( d2sdb2+dsrgdb*dsrgdb*
2072  model_.xd/(model_.junctionDepth*argxs))/
2073  (EffectiveLength*args);
2074  daddb2 = -model_.xd*( d2bdb2+dbrgdb*dbrgdb*
2075  model_.xd/(model_.junctionDepth*argxd))/
2076  (EffectiveLength*argd);
2077  dgddb2 = -0.5*model_.gamma*(dasdb2+daddb2);
2078  }
2079  dgddvb = -model_.gamma*(dbargs+dbargd);
2080  if (model_.junctionDepth > 0)
2081  {
2082  ddxwd = -dbxwd;
2083  dgdvds = -model_.gamma*0.5*ddxwd/(EffectiveLength*argd);
2084  }
2085  }
2086  else
2087  {
2088  gamasd = model_.gamma;
2089  gammad = model_.gamma;
2090  dgddvb = 0.0;
2091  dgdvds = 0.0;
2092  dgddb2 = 0.0;
2093  }
2094  Von = vbin+gamasd*sarg;
2095  vth = Von;
2096  Vdsat = 0.0;
2097 
2098  // erkeite: there were a lot of got line1050: in the original spice3
2099  // source. I think essentially it means, "don't do any more calcultions here,
2100  // and set cdrain, gm, and gmbs to zero".
2101  bool line1050bool=false;
2102  if (model_.fastSurfaceStateDensity != 0.0 && OxideCap != 0.0)
2103  {
2104  // XXX constant per model
2105  cfs = CONSTQ *model_.fastSurfaceStateDensity*1e4; //(cm**2/m**2)
2106  cdonco = -(gamasd*dsrgdb+dgddvb*sarg)+factor;
2107  xn = 1.0+cfs/OxideCap*w*EffectiveLength+cdonco;
2108  tmp = vt*xn;
2109  Von = Von+tmp;
2110  argg = 1.0/tmp;
2111  vgst = lvgs-Von;
2112  }
2113  else
2114  {
2115  vgst = lvgs-Von;
2116  if (lvgs <= Von)
2117  {
2118  // cutoff region
2119  gds = 0.0;
2120  //goto line1050;
2121  line1050bool=true;
2122  }
2123  }
2124 
2125  if (!line1050bool)
2126  {
2127  ufact = 1.0;
2128  ueff = model_.surfaceMobility * 1e-4;
2129  dudvgs = 0.0;
2130  dudvds = 0.0;
2131  dudvbs = 0.0;
2132 
2133  // compute some more useful quantities
2134  sarg3 = sarg*sarg*sarg;
2135  // XXX constant per model
2136  sbiarg = sqrt(tBulkPot);
2137  gammad = gamasd;
2138  dgdvbs = dgddvb;
2139  body = barg*barg*barg-sarg3;
2140  gdbdv = 2.0*gammad*(barg*barg*dbrgdb-sarg*sarg*dsrgdb);
2141  dodvbs = -factor+dgdvbs*sarg+gammad*dsrgdb;
2142 
2143  if (OxideCap != 0.0)
2144  {
2145  if (model_.fastSurfaceStateDensity != 0.0)
2146  {
2147  dxndvb = 2.0*dgdvbs*dsrgdb+gammad*d2sdb2+dgddb2*sarg;
2148  dodvbs = dodvbs+vt*dxndvb;
2149  dxndvd = dgdvds*dsrgdb;
2150  dodvds = dgdvds*sarg+vt*dxndvd;
2151  }
2152 
2153  // evaluate effective mobility and its derivatives
2154  // line400
2155  if (OxideCap > 0.0)
2156  {
2157  udenom = vgst;
2159 
2160  if (udenom > tmp)
2161  {
2162  ufact = exp(model_.critFieldExp*log(tmp/udenom));
2163  ueff = model_.surfaceMobility * 1e-4 *ufact;
2164  dudvgs = -ufact*model_.critFieldExp/udenom;
2165  dudvds = 0.0;
2166  dudvbs = model_.critFieldExp*ufact*dodvbs/vgst;
2167  //goto line500;
2168  }
2169  }
2170  }
2171  }
2172 
2173  if (!line1050bool)
2174  {
2175 
2176  // evaluate saturation voltage and its derivatives according to
2177  // grove-frohman equation
2178  // line500
2179  vgsx = lvgs;
2180  gammad = gamasd/eta;
2181  dgdvbs = dgddvb;
2182  if (model_.fastSurfaceStateDensity != 0 && OxideCap != 0)
2183  {
2184  vgsx = Xycemax(lvgs,Von);
2185  }
2186  if (gammad > 0)
2187  {
2188  gammd2 = gammad*gammad;
2189  argv = (vgsx-vbin)/eta+phiMinVbs;
2190  if (argv <= 0.0)
2191  {
2192  Vdsat = 0.0;
2193  dsdvgs = 0.0;
2194  dsdvbs = 0.0;
2195  }
2196  else
2197  {
2198  arg = sqrt(1.0+4.0*argv/gammd2);
2199  Vdsat = (vgsx-vbin)/eta+gammd2*(1.0-arg)/2.0;
2200  Vdsat = Xycemax(Vdsat,0.0);
2201  dsdvgs = (1.0-1.0/arg)/eta;
2202  dsdvbs = (gammad*(1.0-arg)+2.0*argv/(gammad*arg))/
2203  eta*dgdvbs+1.0/arg+factor*dsdvgs;
2204  }
2205  }
2206  else
2207  {
2208  Vdsat = (vgsx-vbin)/eta;
2209  Vdsat = Xycemax(Vdsat,0.0);
2210  dsdvgs = 1.0;
2211  dsdvbs = 0.0;
2212  }
2213  if (model_.maxDriftVel > 0)
2214  {
2215  // evaluate saturation voltage and its derivatives
2216  // according to baum's theory of scattering velocity
2217  // saturation
2218 
2219  gammd2 = gammad*gammad;
2220  v1 = (vgsx-vbin)/eta+phiMinVbs;
2221  v2 = phiMinVbs;
2222  xv = model_.maxDriftVel*EffectiveLength/ueff;
2223  a1 = gammad/0.75;
2224  b1 = -2.0*(v1+xv);
2225  c1 = -2.0*gammad*xv;
2226  d1 = 2.0*v1*(v2+xv)-v2*v2-4.0/3.0*gammad*sarg3;
2227  a = -b1;
2228  b = a1*c1-4.0*d1;
2229  c = -d1*(a1*a1-4.0*b1)-c1*c1;
2230  r = -a*a/3.0+b;
2231  s = 2.0*a*a*a/27.0-a*b/3.0+c;
2232  r3 = r*r*r;
2233  s2 = s*s;
2234  p = s2/4.0+r3/27.0;
2235  p0 = fabs(p);
2236  p2 = sqrt(p0);
2237  if (p < 0)
2238  {
2239  ro = sqrt(s2/4.0+p0);
2240  ro = log(ro)/3.0;
2241  ro = exp(ro);
2242  fi = atan(-2.0*p2/s);
2243  y3 = 2.0*ro*cos(fi/3.0)-a/3.0;
2244  }
2245  else
2246  {
2247  p3 = (-s/2.0+p2);
2248  p3 = exp(log(fabs(p3))/3.0);
2249  p4 = (-s/2.0-p2);
2250  p4 = exp(log(fabs(p4))/3.0);
2251  y3 = p3+p4-a/3.0;
2252  }
2253  iknt = 0;
2254  a3 = sqrt(a1*a1/4.0-b1+y3);
2255  b3 = sqrt(y3*y3/4.0-d1);
2256  for(i = 1;i<=4;i++)
2257  {
2258  a4[i-1] = a1/2.0+sig1[i-1]*a3;
2259  b4[i-1] = y3/2.0+sig2[i-1]*b3;
2260  delta4 = a4[i-1]*a4[i-1]/4.0-b4[i-1];
2261  if (delta4 < 0) continue;
2262  iknt = iknt+1;
2263  tmp = sqrt(delta4);
2264  x4[iknt-1] = -a4[i-1]/2.0+tmp;
2265  iknt = iknt+1;
2266  x4[iknt-1] = -a4[i-1]/2.0-tmp;
2267  }
2268  jknt = 0;
2269  for(j = 1;j<=iknt;j++)
2270  {
2271  if (x4[j-1] <= 0) continue;
2272  // XXX implement this sanely
2273  poly4[j-1] = x4[j-1]*x4[j-1]*x4[j-1]*x4[j-1]+a1*x4[j-1]*
2274  x4[j-1]*x4[j-1];
2275  poly4[j-1] = poly4[j-1]+b1*x4[j-1]*x4[j-1]+c1*x4[j-1]+d1;
2276  if (fabs(poly4[j-1]) > 1.0e-6) continue;
2277  jknt = jknt+1;
2278  if (jknt <= 1)
2279  {
2280  xvalid = x4[j-1];
2281  }
2282  if (x4[j-1] > xvalid) continue;
2283  xvalid = x4[j-1];
2284  }
2285  if (jknt > 0)
2286  {
2287  Vdsat = xvalid*xvalid-phiMinVbs;
2288  }
2289  }
2290 
2291  }
2292 
2293  // evaluate effective channel length and its derivatives
2294  bool line610bool=false;
2295  if (!line1050bool)
2296  {
2297  dldvgs = 0.0;
2298  dldvds = 0.0;
2299  dldvbs = 0.0;
2300  if (lvds != 0.0)
2301  {
2302  gammad = gamasd;
2303  if ((lvbs-Vdsat) <= 0)
2304  {
2305  bsarg = sqrt(Vdsat+phiMinVbs);
2306  dbsrdb = -0.5/bsarg;
2307  }
2308  else
2309  {
2310  bsarg = sphi/(1.0+0.5*(lvbs-Vdsat)/tPhi);
2311  dbsrdb = -0.5*bsarg*bsarg/sphi3;
2312  }
2313  bodys = bsarg*bsarg*bsarg-sarg3;
2314  gdbdvs = 2.0*gammad*(bsarg*bsarg*dbsrdb-sarg*sarg*dsrgdb);
2315  if (model_.maxDriftVel <= 0)
2316  {
2317  if (model_.substrateDoping == 0.0 || xlamda > 0.0)
2318  {
2319  line610bool=true;
2320  }
2321  else
2322  {
2323  argv = (lvds-Vdsat)/4.0;
2324  sargv = sqrt(1.0+argv*argv);
2325  arg = sqrt(argv+sargv);
2326  xlfact = model_.xd/(EffectiveLength*lvds);
2327  xlamda = xlfact*arg;
2328  dldsat = lvds*xlamda/(8.0*sargv);
2329  }
2330  }
2331  else
2332  {
2333  argv = (vgsx-vbin)/eta-Vdsat;
2334  xdv = model_.xd/sqrt(model_.channelCharge);
2335  xlv = model_.maxDriftVel*xdv/(2.0*ueff);
2336  vqchan = argv-gammad*bsarg;
2337  dqdsat = -1.0+gammad*dbsrdb;
2339  dfunds = vl*dqdsat-ueff*vqchan;
2340  dfundg = (vl-ueff*Vdsat)/eta;
2341  dfundb = -vl*(1.0+dqdsat-factor/eta)+ueff*
2342  (gdbdvs-dgdvbs*bodys/1.5)/eta;
2343  dsdvgs = -dfundg/dfunds;
2344  dsdvbs = -dfundb/dfunds;
2345 
2346  if (model_.substrateDoping == 0.0 || xlamda > 0.0)
2347  {
2348  line610bool=true;
2349  }
2350  else
2351  {
2352  argv = lvds-Vdsat;
2353  argv = Xycemax(argv,0.0);
2354  xls = sqrt(xlv*xlv+argv);
2355  dldsat = xdv/(2.0*xls);
2356  xlfact = xdv/(EffectiveLength*lvds);
2357  xlamda = xlfact*(xls-xlv);
2358  dldsat = dldsat/EffectiveLength;
2359  }
2360  }
2361 
2362  if (!line610bool)
2363  {
2364  dldvgs = dldsat*dsdvgs;
2365  dldvds = -xlamda+dldsat;
2366  dldvbs = dldsat*dsdvbs;
2367  }
2368  }
2369  }
2370 
2371  bool donevalbool=false;
2372  if (!line1050bool)
2373  {
2374  // limit channel shortening at punch-through
2375  xwb = model_.xd*sbiarg;
2376  xld = EffectiveLength-xwb;
2377  clfact = 1.0-xlamda*lvds;
2378  dldvds = -xlamda-dldvds;
2379  xleff = EffectiveLength*clfact;
2380  deltal = xlamda*lvds*EffectiveLength;
2381  if (model_.substrateDoping == 0.0) xwb = 0.25e-6;
2382  if (xleff < xwb)
2383  {
2384  xleff = xwb/(1.0+(deltal-xld)/xwb);
2385  clfact = xleff/EffectiveLength;
2386  dfact = xleff*xleff/(xwb*xwb);
2387  dldvgs = dfact*dldvgs;
2388  dldvds = dfact*dldvds;
2389  dldvbs = dfact*dldvbs;
2390  }
2391  // evaluate effective beta (effective kp)
2392  beta1 = Beta*ufact/clfact;
2393 
2394  // test for mode of operation and branch appropriately
2395  gammad = gamasd;
2396  dgdvbs = dgddvb;
2397 
2398  if (lvds <= 1.0e-10)
2399  {
2400  if (lvgs <= Von)
2401  {
2402  if ((model_.fastSurfaceStateDensity == 0.0) || (OxideCap == 0.0))
2403  {
2404  gds = 0.0;
2405  }
2406  else
2407  {
2408  gds = beta1*(Von-vbin-gammad*sarg)*exp(argg*(lvgs-Von));
2409  }
2410  }
2411  else
2412  {
2413  gds = beta1*(lvgs-vbin-gammad*sarg);
2414  }
2415  line1050bool=true;
2416  }
2417 
2418  }
2419 
2420  if (!line1050bool)
2421  {
2422  if ( !(lvgs > Von) )
2423  {
2424  // subthreshold region
2425  if (Vdsat <= 0)
2426  {
2427  gds = 0.0;
2428  if (lvgs > vth)
2429  {
2430  donevalbool=true;
2431  }
2432  else
2433  {
2434  line1050bool=true;
2435  }
2436  }
2437 
2438  if (!donevalbool && !line1050bool)
2439  {
2440  vdson = Xycemin(Vdsat,lvds);
2441  if (lvds > Vdsat)
2442  {
2443  barg = bsarg;
2444  dbrgdb = dbsrdb;
2445  body = bodys;
2446  gdbdv = gdbdvs;
2447  }
2448 
2449  cdson = beta1*((Von-vbin-eta*vdson*0.5)*vdson-gammad*body/1.5);
2450  didvds = beta1*(Von-vbin-eta*vdson-gammad*barg);
2451  gdson = -cdson*dldvds/clfact-beta1*dgdvds*body/1.5;
2452 
2453  if (lvds < Vdsat)
2454  {
2455  gdson = gdson+didvds;
2456  }
2457 
2458  gbson = -cdson*dldvbs/clfact+beta1*
2459  (dodvbs*vdson+factor*vdson-dgdvbs*body/1.5-gdbdv);
2460  if (lvds > Vdsat)
2461  {
2462  gbson = gbson+didvds*dsdvbs;
2463  }
2464  expg = exp(argg*(lvgs-Von));
2465  cdrain = cdson*expg;
2466  gmw = cdrain*argg;
2467  gm = gmw;
2468  if (lvds > Vdsat)
2469  {
2470  gm = gmw+didvds*dsdvgs*expg;
2471  }
2472  tmp = gmw*(lvgs-Von)/xn;
2473  gds = gdson*expg-gm*dodvds-tmp*dxndvd;
2474  gmbs = gbson*expg-gm*dodvbs-tmp*dxndvb;
2475  donevalbool=true;
2476  }
2477  }
2478  }
2479 
2480  if (!donevalbool && !line1050bool)
2481  {
2482  if (lvds <= Vdsat)
2483  {
2484  // linear region
2485  cdrain = beta1*((lvgs-vbin-eta*lvds/2.0)*lvds-gammad*body/1.5);
2486  arg = cdrain*(dudvgs/ufact-dldvgs/clfact);
2487  gm = arg+beta1*lvds;
2488  arg = cdrain*(dudvds/ufact-dldvds/clfact);
2489  gds = arg+beta1*(lvgs-vbin-eta*
2490  lvds-gammad*barg-dgdvds*body/1.5);
2491  arg = cdrain*(dudvbs/ufact-dldvbs/clfact);
2492  gmbs = arg-beta1*(gdbdv+dgdvbs*body/1.5-factor*lvds);
2493  }
2494  else
2495  {
2496  // saturation region
2497  cdrain = beta1*((lvgs-vbin-eta*
2498  Vdsat/2.0)*Vdsat-gammad*bodys/1.5);
2499  arg = cdrain*(dudvgs/ufact-dldvgs/clfact);
2500  gm = arg+beta1*Vdsat+beta1*(lvgs-
2501  vbin-eta*Vdsat-gammad*bsarg)*dsdvgs;
2502  gds = -cdrain*dldvds/clfact-beta1*dgdvds*bodys/1.5;
2503  arg = cdrain*(dudvbs/ufact-dldvbs/clfact);
2504  gmbs = arg-beta1*(gdbdvs+dgdvbs*bodys/1.5-factor*
2505  Vdsat)+beta1* (lvgs-vbin-eta*Vdsat-gammad*bsarg)*dsdvbs;
2506  }
2507 
2508  // compute charges for "on" region
2509  donevalbool=true;
2510  }
2511 
2512  // finish special cases.
2513  if (line1050bool)
2514  {
2515  cdrain = 0.0;
2516  gm = 0.0;
2517  gmbs = 0.0;
2518  }
2519 
2520  // finished
2521  }
2522 
2523  von = (model_.dtype) * Von;
2524  vdsat = (model_.dtype) * Vdsat;
2525  }
2526  }
2527 // end level-2 block
2528 
2529 
2530  ////
2531  // * COMPUTE EQUIVALENT DRAIN CURRENT SOURCE
2532  ////
2533 
2534  cd = mode * cdrain - cbd;
2535 
2536  // in 3f5 this is all in a block conditioned on CKTmode, but since
2537  // it's valid for MODETRAN and MODETRANOP we'll just always do it
2538 
2539  ////
2540  // * now we do the hard part of the bulk-drain and bulk-source
2541  // * diode - we evaluate the non-linear capacitance and
2542  // * charge
2543  // *
2544  // * the basic equations are not hard, but the implementation
2545  // * is somewhat long in an attempt to avoid log/exponential
2546  // * evaluations
2547  ////
2548  ////
2549  // * charge storage elements
2550  // *
2551  // *.. bulk-drain and bulk-source depletion capacitances
2552  ////
2553  // I took out all the CAPBYPASS stuff, and the
2554  // unnecessary curly braces that wind up there if you do
2555 
2556  // can't bypass the diode capacitance calculations
2557  if(Cbs != 0 || Cbssw != 0 )
2558  {
2559  if (vbs < tDepCap)
2560  {
2561  arg=1-vbs/tBulkPot;
2562  ////
2563  // * the following block looks somewhat long and messy,
2564  // * but since most users use the default grading
2565  // * coefficients of .5, and sqrt is MUCH faster than an
2566  // * exp(log()) we use this special case code to buy time.
2567  // * (as much as 10% of total job time!)
2568  ////
2570  {
2571  if(model_.bulkJctBotGradingCoeff == .5)
2572  {
2573  sarg = sargsw = 1/sqrt(arg);
2574  }
2575  else
2576  {
2577  sarg = sargsw = exp(-model_.bulkJctBotGradingCoeff*log(arg));
2578  }
2579  }
2580  else
2581  {
2582  if(model_.bulkJctBotGradingCoeff == .5)
2583  {
2584  sarg = 1/sqrt(arg);
2585  }
2586  else
2587  {
2588  sarg = exp(-model_.bulkJctBotGradingCoeff*log(arg));
2589  }
2591  {
2592  sargsw = 1/sqrt(arg);
2593  }
2594  else
2595  {
2596  sargsw =exp(-model_.bulkJctSideGradingCoeff* log(arg));
2597  }
2598  }
2599  qbs = tBulkPot*(Cbs*(1-arg*sarg)/(1-model_.bulkJctBotGradingCoeff)
2600  +Cbssw*(1-arg*sargsw)/(1-model_.bulkJctSideGradingCoeff));
2601  capbs=Cbs*sarg+ Cbssw*sargsw;
2602  }
2603  else
2604  {
2605  qbs = f4s + vbs*(f2s+vbs*(f3s/2));
2606  capbs=f2s+f3s*vbs;
2607  }
2608  }
2609  else
2610  {
2611  qbs = 0;
2612  capbs=0;
2613  }
2614 
2615  //// can't bypass the diode capacitance calculations
2616  if(Cbd != 0 || Cbdsw != 0 )
2617  {
2618 
2619  if (vbd < tDepCap)
2620  {
2621  arg=1-vbd/tBulkPot;
2622  ////
2623  // * the following block looks somewhat long and messy,
2624  // * but since most users use the default grading
2625  // * coefficients of .5, and sqrt is MUCH faster than an
2626  // * exp(log()) we use this special case code to buy time.
2627  // * (as much as 10% of total job time!)
2628  ////
2629  if(model_.bulkJctBotGradingCoeff == .5 &&
2631  {
2632  sarg = sargsw = 1/sqrt(arg);
2633  }
2634  else
2635  {
2636  if(model_.bulkJctBotGradingCoeff == .5)
2637  {
2638  sarg = 1/sqrt(arg);
2639  }
2640  else
2641  {
2642  sarg = exp(-model_.bulkJctBotGradingCoeff*log(arg));
2643  }
2645  {
2646  sargsw = 1/sqrt(arg);
2647  }
2648  else
2649  {
2650  sargsw =exp(-model_.bulkJctSideGradingCoeff*log(arg));
2651  }
2652  }
2653  qbd =
2654  tBulkPot*(Cbd*
2655  (1-arg*sarg)
2657  +Cbdsw*
2658  (1-arg*sargsw)
2660  capbd=Cbd*sarg+
2661  Cbdsw*sargsw;
2662  }
2663  else
2664  {
2665  qbd = f4d +
2666  vbd * (f2d + vbd * f3d/2);
2667  capbd=f2d + vbd * f3d;
2668  }
2669  }
2670  else
2671  {
2672  qbd = 0;
2673  capbd = 0;
2674  }
2675 
2676  // Now after a mess of convergence stuff that seems not to apply to us
2677  // 3f5 saves the vbs, vbd, etc. in the state vector (we don't, it gets
2678  // saved in updatePrimaryState)
2679 
2680  // Then 3f5 calculates meyer capacitances, capgs, capgb and capgd
2681  // Careful! They use the local von and vdsat, which haven't got dtype
2682  // multiplying them!
2683 
2684  ////
2685  // * calculate meyer's capacitors
2686  ////
2687  ////
2688  // * new cmeyer - this just evaluates at the current time,
2689  // * expects you to remember values from previous time
2690  // * returns 1/2 of non-constant portion of capacitance
2691  // * you must add in the other half from previous time
2692  // * and the constant part
2693  ////
2694 
2695  if (mode > 0)
2696  {
2697  devSupport.qmeyer (vgs,vgd,Vgb,Von,Vdsat,
2699  }
2700  else
2701  {
2702  devSupport.qmeyer (vgd,vgs,Vgb,Von,Vdsat,
2704  }
2705 
2706 
2707  // vgs1 = vgs_old;
2708  // vgd1 = vgs1 - vds_old;
2709  // vgb1 = vgs1 - vbs_old;
2710 
2711  ////
2712  // TVR: Note! Caution with Capgs vs. capgs. If I used the instance var
2713  // capgs on the left hand side, it's OK as long as we never try to implement
2714  // meyer back averaging, since capgs is going to be recalculated each
2715  // time through. But if we do the averaging, the old one will have the
2716  // constant part and old old part added in, which is not what we wanted.
2717  // So I'll continue 3f5's way of having a local Capgs that's actually used
2718  // for the charge computation, and an instance capgs that's saved as state.
2719  ////
2720 
2721  if((getSolverState().dcopFlag))
2722  {
2723  Capgs = 2 * capgs + GateSourceOverlapCap ;
2724  Capgd = 2 * capgd + GateDrainOverlapCap ;
2725  Capgb = 2 * capgb + GateBulkOverlapCap ;
2726  }
2727  else
2728  {
2729  capgs_old = (*extData.currStaVectorPtr)[li_state_capgs];
2730  capgd_old = (*extData.currStaVectorPtr)[li_state_capgd];
2731  capgb_old = (*extData.currStaVectorPtr)[li_state_capgb];
2732 
2733  Capgs = ( capgs+
2734  capgs_old +
2736  Capgd = ( capgd+
2737  capgd_old +
2739  Capgb = ( capgb+
2740  capgb_old +
2742  }
2743 
2744  // Eric does this kludge in level 1, so I'll do it to make sure capacitances
2745  // are positive
2746  Capgs *= (Capgs < 0.0)?-1.0:1.0;
2747  Capgd *= (Capgd < 0.0)?-1.0:1.0;
2748  Capgb *= (Capgb < 0.0)?-1.0:1.0;
2749 
2750 
2751  // in the sequel, I'll refer to all derivatives of currents w.r.t. voltages
2752  // as conductances, whether they really are or not.
2753 
2754  // when we get here, cdrain has the channel current
2755  // cbd and cbs have the currents through the diodes
2756  // cd has the drain current minus the diode current and seems only to be used
2757  // for 3f5 convergence stuff
2758  // qbs and qbd have the charges on the parasitic capacitors
2759  // capbs and capbd have the capacitances of the parasitics.
2760 
2761  // none of the charges for the gate capacitors have been calculated yet.
2762  // We've saved the capacitances, so we can get the charges in
2763  // updatePrimaryState later.
2764 
2765  // Conductances:
2766  // gbd: the bulk-drain' conductance without the capacitor components
2767  // We'll need to get the capacitor contribution in the actual load
2768  // using C*dt
2769  // gbs: bulk-source' without capacitor
2770  // gm = derivative of channel current w.r.t. gate-source voltage --- gotta
2771  // account for mode=normal or mode=reverse when using this!
2772  // gmbs = derivative of channel current w.r.t bulk-source voltage
2773  // gds = derivative of channel current w.r.t. drain-source voltage
2774 
2775  // the variables gcgs, gcgb, gcgd should be the conductances for the gate
2776  // capacitors, but we won't do those here (vide supra), we'll do them
2777  // in the jacobian load given the capacitances.
2778 
2779  // Now 3f5 doesn't do the resistor currents in the RHS load, because of
2780  // how they do their numerics. We do, so let's save those here.
2781 
2784 
2785  if (mode >= 0) // Normal mode
2786  {
2787  Gm = gm; // (xnrm-xrev)*gm in 3f5
2788  Gmbs = gmbs; // (xnrm-xrev)*gmbs in 3f5
2789  nrmsum = Gm+Gmbs; // xnrm*(gm+gmbs)
2790  revsum = 0; // xrev*(gm+gmbs)
2792  }
2793  else
2794  {
2795  Gm = -gm;
2796  Gmbs = -gmbs;
2797  nrmsum = 0;
2798  revsum = -(Gm+Gmbs); // because Gm and Gmbs already have - in them!
2799  cdreq = -(model_.dtype)*cdrain;
2800  }
2801 
2802  // It is now essential to restore the vds/vgs/vgd variables that might
2803  // have been tweaked by homotopy, lest they have an effect on RHS
2804  // Jdxp terms.
2805 
2806  vds=vds_save;
2807  vgs=vgs_save;
2808  vgd=vgd_save;
2809 
2810  /// CURRENTS to load into RHS:
2811 
2812  // so at this point:
2813 
2814  // current out of drain is
2815  // Idrain
2816 
2817  // current out of gate:
2818  // dtype*( (deriv of qgs) + (deriv of qgd) + (deriv of qgb))
2819 
2820  // the current *out of* the source should be simply
2821  // Isource.
2822 
2823  // current out of bulk is
2824  // dtype*(deriv of qbd) + dtype*cbd + dtype*cbs + dtype*(deriv of qbs)
2825  // - dtype*(deriv of qgb)
2826 
2827  // current out of drain' is
2828  // -Idrain - dtype*(deriv of qgd) - (deriv of qbd) - dtype*cbd +
2829  // mode*dtype*cdrain
2830 
2831  // the current out of the source' is
2832  // -Isource - dtype*(deriv of qgs) - dtype*cbs - (deriv of qbs) -
2833  // mode*dtype*cdrain
2834 
2835  //////Conductances to load into Jacobian as they relate to things here:
2836  /// all of the places where I say Cap/dt I really mean dtype*Cap/dt for
2837  // the meyer capacitors. No dtype for the parasitics, though
2838 
2839  // 3f5 handles the mode by doing:
2840  // where xnrm=1, xrev=0 if mode>=0, xnrm=0,xrev=1 if mode<0
2841 
2842  // drain-drain = a = drainConductance
2843  // drain-drain' = b = -drainConductance
2844 
2845  // gate-gate = c = "gcgd+gcgs+gcgb" = Capgd/dt+Capgs/dt+Capgb/dt
2846  // gate-bulk = d = -gcgb = -Capgb/dt
2847  // gate-drain' = e = -gcgd = -Capgd/dt
2848  // gate-source' = f = -gcgs = -Capgs/dt
2849 
2850  // source-source = g = sourceConductance
2851  // source-source' = h = -sourceConductance
2852 
2853  // bulk-gate = i = -gcgb = -Capgb/dt
2854  // bulk-bulk = j = gbs+gbd+gcgb+parasitics=gbs+gbd+Capgb/dt+capbs/dt+capbd/dt
2855  // bulk-drain' = k= -gbd-capbd/dt
2856  // bulk-source' = l= -gbs-capbs/dt
2857 
2858  // drain'-drain = m = -drainConductance
2859  // drain'-gate = n = (xnrm-xrev)*gm-Capgd/dt
2860  // drain'-bulk = o = -gbd-capbd/dt+(xnrm-xrev)*gmbs
2861  // drain'-drain' = p = drainConductance+gds+gbd+capbd/dt+
2862  // xrev*(gm+gmbs)+ Capgd/dt
2863  // drain'-source' = q = -gds-xnrm*(gm+gmbs)
2864 
2865  // source'-gate = r = -(xnrm-xrev)*gm-Capgs/dt
2866  // source'-source = s = -sourceConductance
2867  // source'-bulk = t = -gbs-capbs/dt-(xnrm-xrev)*gmbs
2868  // source'-drain' = u= -gds-xrev*(gm+gmbs)
2869  // source'-source' = v = sourceConductance+gds+gbs+capbs/dt+xnrm*(gm+gmbs)+
2870  // Capgs/dt
2871 
2872  return bsuccess;
2873 }
2874 
2875 //-----------------------------------------------------------------------------
2876 // Function : Instance::updateTemperature
2877 // Purpose :
2878 // Special Notes :
2879 // Scope : public
2880 // Creator : Eric Keiter
2881 // Creation Date : 02/27/01
2882 //-----------------------------------------------------------------------------
2883 bool Instance::updateTemperature ( const double & temp_tmp)
2884 {
2885  // mos3temp vars
2886  double czbd; // zero voltage bulk-drain capacitance
2887  double czbdsw; // zero voltage bulk-drain sidewall capacitance
2888  double czbs; // zero voltage bulk-source capacitance
2889  double czbssw; // zero voltage bulk-source sidewall capacitance
2890  double arg; // 1 - fc
2891  double sarg; // (1-fc) ^^ (-mj)
2892  double sargsw; // (1-fc) ^^ (-mjsw)
2893  double ratio,ratio4;
2894  double fact2;
2895  double kt;
2896  double egfet;
2897  double pbfact;
2898  double capfact;
2899  double phio;
2900  double pbo;
2901  double gmanew,gmaold;
2902  // end of mos3temp stuff
2903 
2904  double tnom;
2905 
2906 #ifdef Xyce_DEBUG_DEVICE
2907  if (getDeviceOptions().debugLevel > 0 && getSolverState().debugTimeFlag)
2908  {
2909  Xyce::dout() << subsection_divider << std::endl;
2910  Xyce::dout() << " Instance::Begin of updateTemperature. \n";
2911  Xyce::dout() <<" name = " << getName() << std::endl;
2912  Xyce::dout() << std::endl;
2913  }
2914 #endif
2915 
2916  // first set the instance temperature to the new temperature:
2917  if (temp_tmp != -999.0) temp = temp_tmp;
2918 
2920  {
2922  }
2923 
2924  tnom = model_.tnom;
2925  ratio = temp/tnom;
2926 
2927 #ifdef Xyce_DEBUG_DEVICE
2928  if (getDeviceOptions().debugLevel > 0 && getSolverState().debugTimeFlag)
2929  {
2930  Xyce::dout() << "Temperature = "<< temp << std::endl;
2931  Xyce::dout() << "tnom = " << tnom << std::endl;
2932  Xyce::dout() << "ratio = " << ratio << std::endl;
2933  }
2934 #endif
2935 
2936  vt = temp * CONSTKoverQ;
2937  ratio = temp/tnom;
2938  fact2 = temp/CONSTREFTEMP;
2939  kt = temp * CONSTboltz;
2940  egfet = 1.16-(7.02e-4*temp*temp)/(temp+1108);
2941  arg = -egfet/(kt+kt)+1.1150877/(CONSTboltz*(CONSTREFTEMP+CONSTREFTEMP));
2942  pbfact = -2*vt *(1.5*log(fact2)+CONSTQ*arg);
2943 
2944 #ifdef Xyce_DEBUG_DEVICE
2946  {
2947  Xyce::dout() << "vt = " << vt << std::endl;
2948  Xyce::dout() << "ratio = " << ratio << std::endl;
2949  Xyce::dout() << "fact2 = " << fact2 << std::endl;
2950  Xyce::dout() << "kt = " << kt << std::endl;
2951  Xyce::dout() << "egfet = " << egfet << std::endl;
2952  Xyce::dout() << "arg = " << arg << std::endl;
2953  Xyce::dout() << "pbfact = " << pbfact << std::endl;
2954  }
2955 #endif
2956 
2957  // in mos3temp 3f5 does a bunch of parameter defaulting (lines 155-163)
2958  // but we assume that our various parameters have been set already in
2959  // the constructors
2960 
2961  // lines 164-203 of mos3temp moved to instance block constructor
2962 
2963  // Here's the entire guts of the mos3temp instance loop, with obvious
2964  // modifications (here->MOS3 goes away, model->MOS3 turns into model_.)
2965 
2966  ratio4 = ratio * sqrt(ratio);
2968  tSurfMob = model_.surfaceMobility/ratio4;
2969  phio= (model_.phi-model_.pbfact1)/model_.fact1;
2970  tPhi = fact2 * phio + pbfact;
2971  tVbi = model_.vt0 - model_.dtype *
2972  (model_.gamma* sqrt(model_.phi))+.5*(model_.egfet1-egfet)
2973  + model_.dtype*.5* (tPhi-model_.phi);
2974  tVto = tVbi + model_.dtype * model_.gamma * sqrt(tPhi);
2978  gmaold = (model_.bulkJctPotential-pbo)/pbo;
2979  capfact = 1/(1+model_.bulkJctBotGradingCoeff*
2980  (4e-4*(model_.tnom-CONSTREFTEMP)-gmaold));
2981  tCbd = model_.capBD * capfact;
2982  tCbs = model_.capBS * capfact;
2983  tCj = model_.bulkCapFactor * capfact;
2984  capfact = 1/(1+model_.bulkJctSideGradingCoeff*
2985  (4e-4*(model_.tnom-CONSTREFTEMP)-gmaold));
2986  tCjsw = model_.sideWallCapFactor * capfact;
2987  tBulkPot = fact2 * pbo+pbfact;
2988  gmanew = (tBulkPot-pbo)/pbo;
2989  capfact = (1+model_.bulkJctBotGradingCoeff*(4e-4*(temp-CONSTREFTEMP)-gmanew));
2990  tCbd *= capfact;
2991  tCbs *= capfact;
2992  tCj *= capfact;
2993  capfact = (1+model_.bulkJctSideGradingCoeff*(4e-4*(temp-CONSTREFTEMP)-gmanew));
2994  tCjsw *= capfact;
2996 
2997  if( (model_.jctSatCurDensity == 0) || (drainArea == 0) ||
2998  (sourceArea == 0) )
2999  {
3001  vt*log(vt/(CONSTroot2*model_.jctSatCur));
3002  }
3003  else
3004  {
3005  drainVcrit = vt * log( vt / (CONSTroot2 *
3007  sourceVcrit = vt * log( vt / (CONSTroot2 *
3009  }
3010  if(model_.capBDGiven)
3011  {
3012  czbd = tCbd;
3013  }
3014  else
3015  {
3017  {
3018  czbd=tCj*drainArea;
3019  }
3020  else
3021  {
3022  czbd=0;
3023  }
3024  }
3026  {
3027  czbdsw= tCjsw * drainPerimeter;
3028  }
3029  else
3030  {
3031  czbdsw=0;
3032  }
3033  arg = 1-model_.fwdCapDepCoeff;
3034  sarg = exp( (-model_.bulkJctBotGradingCoeff) * log(arg) );
3035  sargsw = exp( (-model_.bulkJctSideGradingCoeff) * log(arg) );
3036  Cbd = czbd;
3037  Cbdsw = czbdsw;
3038  f2d = czbd*(1-model_.fwdCapDepCoeff*
3039  (1+model_.bulkJctBotGradingCoeff))* sarg/arg
3040  + czbdsw*(1-model_.fwdCapDepCoeff*
3042  sargsw/arg;
3043  f3d = czbd * model_.bulkJctBotGradingCoeff * sarg/arg/
3044  tBulkPot
3045  + czbdsw * model_.bulkJctSideGradingCoeff * sargsw/arg /
3046  tBulkPot;
3047  f4d = czbd*tBulkPot*(1-arg*sarg)/
3049  + czbdsw*tBulkPot*(1-arg*sargsw)/
3051  -f3d/2*
3052  (tDepCap*tDepCap)
3053  -tDepCap * f2d;
3054  if(model_.capBSGiven)
3055  {
3056  czbs=tCbs;
3057  }
3058  else
3059  {
3061  {
3062  czbs=tCj*sourceArea;
3063  }
3064  else
3065  {
3066  czbs=0;
3067  }
3068  }
3070  {
3071  czbssw = tCjsw * sourcePerimeter;
3072  }
3073  else
3074  {
3075  czbssw=0;
3076  }
3077  arg = 1-model_.fwdCapDepCoeff;
3078  sarg = exp( (-model_.bulkJctBotGradingCoeff) * log(arg) );
3079  sargsw = exp( (-model_.bulkJctSideGradingCoeff) * log(arg) );
3080  Cbs = czbs;
3081  Cbssw = czbssw;
3082  f2s = czbs*(1-model_.fwdCapDepCoeff*
3083  (1+model_.bulkJctBotGradingCoeff))* sarg/arg
3084  + czbssw*(1-model_.fwdCapDepCoeff*
3086  sargsw/arg;
3087  f3s = czbs * model_.bulkJctBotGradingCoeff * sarg/arg/
3088  tBulkPot
3089  + czbssw * model_.bulkJctSideGradingCoeff * sargsw/arg /
3090  tBulkPot;
3091  f4s = czbs*tBulkPot*(1-arg*sarg)/
3093  + czbssw*tBulkPot*(1-arg*sargsw)/
3095  -f3s/2*
3096  (tDepCap*tDepCap)
3097  -tDepCap * f2s;
3098 
3099  return true;
3100 }
3101 
3102 //-----------------------------------------------------------------------------
3103 // Function : Instance::updatePrimaryState
3104 // Purpose :
3105 // Special Notes :
3106 // Scope : public
3107 // Creator : Eric Keiter
3108 // Creation Date : 02/28/01
3109 //-----------------------------------------------------------------------------
3111 {
3112  bool bsuccess = true;
3113 
3114  double * staVector = extData.nextStaVectorRawPtr;
3115  double * oldstaVector = extData.currStaVectorRawPtr;
3116  double * stoVector = extData.nextStoVectorRawPtr;
3117  double * oldstoVector = extData.currStoVectorRawPtr;
3118 
3119  double vgs1, vgd1, vbs1,vgb1, vds1;
3120 
3121  bsuccess = updateIntermediateVars ();
3122 
3123  // voltage drops:
3124  stoVector[li_store_vbd] = vbd;
3125  stoVector[li_store_vbs] = vbs;
3126  stoVector[li_store_vgs] = vgs;
3127  stoVector[li_store_vds] = vds;
3128  stoVector[li_store_von] = von;
3129 
3130  // now the meyer capacitances
3131  // we didn't calculate these charges in update IntermediateVars
3132  // but we did calculate the voltage drops and capacitances.
3133  // first store the capacitances themselves:
3134  staVector[li_state_capgs] = capgs;
3135  staVector[li_state_capgd] = capgd;
3136  staVector[li_state_capgb] = capgb;
3137 
3138  // now the charges
3139  // BE CAREFUL! We can only do Q=CV for DCOP! Otherwise it's
3140  // supposed to be *INTEGRATED*:
3141  // Q = int(t0,t1)C(V)*dV --- and we approximate that by
3142  // Q(t1)-Q(t0) = CBar*(V(t1)-V(t0)) where CBar is the average.
3143  // Now with Meyer back averaging, Capxx is the average between the last
3144  // time step and this one. So we gotta do the right thing for non-DCOP
3145  // when backaverage is on.
3146 
3147  if((getSolverState().dcopFlag))
3148  {
3149  qgs = Capgs*vgs;
3150  qgd = Capgd*vgd;
3151  qgb = Capgb*Vgb;
3152  }
3153  else
3154  {
3155  // get the ones from last time step
3156  qgs = oldstaVector[li_state_qgs];
3157  qgd = oldstaVector[li_state_qgd];
3158  qgb = oldstaVector[li_state_qgb];
3159  // get the voltage drops, too
3160  vgs1 = oldstoVector[li_store_vgs];
3161  vbs1 = oldstoVector[li_store_vbs];
3162  vds1 = oldstoVector[li_store_vds];
3163 
3164  vgb1 = vgs1-vbs1;
3165  vgd1 = vgs1-vds1;
3166 
3167  // NOW we can calculate the charge update
3168  qgs += Capgs*(vgs-vgs1);
3169  qgd += Capgd*(vgd-vgd1);
3170  qgb += Capgb*((vgs-vbs)-vgb1);
3171  }
3172 
3173  staVector[li_state_qgs] = qgs;
3174  staVector[li_state_qgd] = qgd;
3175  staVector[li_state_qgb] = qgb;
3176 
3177  // and the diode parasitic capacitors
3178  // these charges were set in updateIntermediateVars
3179  staVector[li_state_qbd] = qbd;
3180  staVector[li_state_qbs] = qbs;
3181 
3182  return bsuccess;
3183 }
3184 
3185 // Additional Declarations
3186 // Class Model
3187 //-----------------------------------------------------------------------------
3188 // Function : Model::processParams
3189 // Purpose :
3190 // Special Notes :
3191 // Scope : public
3192 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
3193 // Creation Date : 6/03/02
3194 //-----------------------------------------------------------------------------
3196 {
3197  double wkfngs;
3198  double wkfng;
3199  double fermig;
3200  double fermis;
3201  double vfb;
3202  double kt1;
3203  double arg1;
3204 
3207  kt1 = CONSTboltz * tnom;
3208  egfet1 = 1.16-(7.02e-4*tnom*tnom)/(tnom+1108);
3209  arg1 = -egfet1/(kt1+kt1)+1.1150877/(CONSTboltz*(CONSTREFTEMP+CONSTREFTEMP));
3210  pbfact1 = -2*vtnom *(1.5*log(fact1)+CONSTQ*arg1);
3211 
3212  //
3213 
3214  if(!given("TOX"))
3215  {
3216  oxideThickness = 1e-7;
3217  }
3218  oxideCapFactor = 3.9 * 8.854214871e-12/oxideThickness;
3219 
3220  if(!given("UO") && !given("U0"))
3221  {
3222  surfaceMobility=600;
3223  }
3224 
3225  if (!given("KP"))
3226  {
3228  * 1e-4 * oxideCapFactor;
3229  //(m**2/cm**2)
3230  }
3231 
3232  if(given("NSUB"))
3233  {
3234  if(substrateDoping *1e6 >1.45e16)
3235  //(cm**3/m**3)
3236  {
3237  if(!given("PHI"))
3238  {
3239  phi = 2*vtnom* log(substrateDoping* 1e6 /1.45e16); // (cm**3/m**3)
3240  phi = Xycemax(.1,phi);
3241  }
3242  fermis = dtype * .5 * phi;
3243  fermis = dtype * .5 * phi;
3244  wkfng = 3.2;
3245  if(!given("TPG")) gateType=1;
3246  if(gateType != 0)
3247  {
3248  fermig = dtype * gateType*.5*egfet1;
3249  wkfng = 3.25 + .5 * egfet1 - fermig;
3250  }
3251  wkfngs = wkfng - (3.25 + .5 * egfet1 +fermis);
3252  if(!given("GAMMA"))
3253  {
3254  gamma = sqrt(2 * 11.70 * 8.854214871e-12 *
3256  // (cm**3/m**3)
3257  }
3258 
3259  if(!given("VTO"))
3260  {
3261  if(!given("NSS"))
3262  {
3264  }
3265  vfb = wkfngs - surfaceStateDensity * 1e4 * CONSTQ/oxideCapFactor;
3266  //(cm**2/m**2)
3267  vt0 = vfb + dtype * (gamma * sqrt(phi)+ phi);
3268  }
3269  else
3270  {
3271  vfb = vt0 - dtype * (gamma* sqrt(phi)+phi);
3272  }
3273  xd = sqrt((CONSTEPSSIL+CONSTEPSSIL)/
3274  (CONSTQ*substrateDoping *1e6)); //(cm**3/m**3)
3275  }
3276  else
3277  {
3278  UserError0(*this) << "Nsub < Ni";
3279 
3280  substrateDoping = 0;
3281  }
3282  }
3283 
3284  if (!given("CJ"))
3285  {
3287  substrateDoping* 1e6 /(2*bulkJctPotential));
3288  // cm**3/m**3
3289  }
3290 
3291  //
3292 #if 0
3293  if(!given("TOX") || oxideThickness == 0)
3294  {
3295  oxideCapFactor = 0;
3296  }
3297  else
3298  {
3299  oxideCapFactor = 3.9 * 8.854214871e-12/oxideThickness;
3300  if(!given("KP"))
3301  {
3302  if(!given("UO") && !given("U0")) surfaceMobility=600;
3304  oxideCapFactor * 1e-4;
3305  }
3306  if(given("NSUB"))
3307  {
3308  if(substrateDoping*1e6 >1.45e16)
3309  {
3310  if(!given("PHI"))
3311  {
3312  phi = 2*vtnom*
3313  log(substrateDoping*1e6/1.45e16);
3314  phi = Xycemax(0.1,phi);
3315  }
3316  fermis = dtype * .5 * phi;
3317  wkfng = 3.2;
3318  if(!given("TPG")) gateType=1;
3319  if(gateType != 0)
3320  {
3321  fermig = dtype *gateType*.5*egfet1;
3322  wkfng = 3.25 + .5 * egfet1 - fermig;
3323  }
3324  wkfngs = wkfng - (3.25 + .5 * egfet1 +fermis);
3325  if(!given("GAMMA"))
3326  {
3327  gamma = sqrt(2 * 11.70 * 8.854214871e-12 *
3328  CONSTQ * substrateDoping*1e6)/
3330  }
3331  if(!given("VTO"))
3332  {
3333  if(!given("NSS"))
3335  vfb = wkfngs - surfaceStateDensity*1e4*CONSTQ/oxideCapFactor;
3336  vt0 = vfb + dtype * (gamma * sqrt(phi)+ phi);
3337  }
3338  }
3339  else
3340  {
3341  UserError0(*this) << "Nsub < Ni";
3342 
3343  substrateDoping = 0;
3344  }
3345  }
3346  }
3347 #endif
3348 
3349  return true;
3350 }
3351 
3352 //----------------------------------------------------------------------------
3353 // Function : Model::processInstanceParams
3354 // Purpose :
3355 // Special Notes :
3356 // Scope : public
3357 // Creator : Dave Shirely, PSSI
3358 // Creation Date : 03/23/06
3359 //----------------------------------------------------------------------------
3361 {
3362  std::vector<Instance*>::iterator iter;
3363  std::vector<Instance*>::iterator first = instanceContainer.begin();
3364  std::vector<Instance*>::iterator last = instanceContainer.end();
3365 
3366  for (iter=first; iter!=last; ++iter)
3367  {
3368  (*iter)->processParams();
3369  }
3370 
3371  return true;
3372 }
3373 
3374 //-----------------------------------------------------------------------------
3375 // Function : Model::Model
3376 // Purpose :
3377 // Special Notes :
3378 // Scope : public
3379 // Creator : Eric Keiter
3380 // Creation Date : 2/26/01
3381 //-----------------------------------------------------------------------------
3383  const Configuration & configuration,
3384  const ModelBlock & MB,
3385  const FactoryBlock & factory_block)
3386  : DeviceModel(MB, configuration.getModelParameters(), factory_block),
3387  dtype(CONSTNMOS),
3388  tnom(getDeviceOptions().tnom),
3389  latDiff(0.0),
3390  jctSatCurDensity(0.0),
3391  jctSatCur(0.0),
3392  drainResistance(0.0),
3393  sourceResistance(0.0),
3394  sheetResistance(0.0),
3395  transconductance(0.0),
3396  gateSourceOverlapCapFactor(0.0),
3397  gateDrainOverlapCapFactor(0.0),
3398  gateBulkOverlapCapFactor(0.0),
3399  oxideCapFactor(0.0),
3400  vt0(0.0),
3401  capBD(0.0),
3402  capBS(0.0),
3403  bulkCapFactor(0.0),
3404  sideWallCapFactor(0.0),
3405  bulkJctPotential(0.0),
3406  bulkJctBotGradingCoeff(0.0),
3407  bulkJctSideGradingCoeff(0.0),
3408  fwdCapDepCoeff(0.0),
3409  phi(0.0),
3410  gamma(0.0),
3411  lambda(0.0),
3412  substrateDoping(0.0),
3413  gateType(0),
3414  surfaceStateDensity(0.0),
3415  oxideThickness(0.0),
3416  surfaceMobility(0.0),
3417  fNcoef(0.0),
3418  fNexp(0.0),
3419  capBDGiven(0),
3420  capBSGiven(0),
3421  bulkCapFactorGiven(0),
3422  sideWallCapFactorGiven(0),
3423 
3424  fact1(0.0),
3425  vtnom(0.0),
3426  egfet1(0.0),
3427  pbfact1(0.0),
3428 
3429  xd(0.0),
3430  junctionDepth(0.0),
3431  fastSurfaceStateDensity(0.0),
3432  critField(1.0e4),
3433  critFieldExp(0.0),
3434  maxDriftVel(0.0),
3435  channelCharge(1.0),
3436  narrowFactor(0.0)
3437 
3438 {
3439  if (getType() != "")
3440  {
3441  if (getType() == "NMOS") {
3442  dtype = CONSTNMOS;
3443  }
3444  else if (getType() == "PMOS") {
3445  dtype = CONSTPMOS;
3446  }
3447  else
3448  {
3449  UserError0(*this) << "Could not recognize the type for model " << getName();
3450  }
3451  }
3452 
3453 
3454  // Set params to constant default values:
3455  setDefaultParams ();
3456 
3457  // Set params according to .model line and constant defaults from metadata:
3458  setModParams (MB.params);
3459 
3460  // Set any non-constant parameter defaults:
3461  if (!given("L"))
3463  if (!given("W"))
3465  if (!given("TNOM"))
3467  if (capBD != 0)
3468  capBDGiven = true;
3469  if (capBS != 0)
3470  capBSGiven = true;
3471 
3472  // Calculate any parameters specified as expressions:
3474 
3475  // calculate dependent (ie computed) params and check for errors:
3476  if (given("U0"))
3477  {
3478  if (given("UO"))
3479  UserError0(*this) << "You have specified both uo and u0, which is not allowed.";
3480 
3481  UserWarning0(*this) << "You have specified the surface mobility as u0 instead of uo. This is supported, but ill-advised.";
3482 
3484  }
3485 
3486  processParams ();
3487 }
3488 
3489 //-----------------------------------------------------------------------------
3490 // Function : Model::~Model
3491 // Purpose : destructor
3492 // Special Notes :
3493 // Scope : public
3494 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
3495 // Creation Date : 3/16/00
3496 //-----------------------------------------------------------------------------
3498 {
3499  std::vector<Instance*>::iterator iter;
3500  std::vector<Instance*>::iterator first = instanceContainer.begin();
3501  std::vector<Instance*>::iterator last = instanceContainer.end();
3502 
3503  for (iter=first; iter!=last; ++iter)
3504  {
3505  delete (*iter);
3506  }
3507 
3508 }
3509 
3510 //-----------------------------------------------------------------------------
3511 // Function : Model::printOutInstances
3512 // Purpose : debugging tool.
3513 // Special Notes :
3514 // Scope : public
3515 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
3516 // Creation Date : 4/03/00
3517 //-----------------------------------------------------------------------------
3518 std::ostream &Model::printOutInstances(std::ostream &os) const
3519 {
3520  std::vector<Instance*>::const_iterator iter;
3521  std::vector<Instance*>::const_iterator first = instanceContainer.begin();
3522  std::vector<Instance*>::const_iterator last = instanceContainer.end();
3523 
3524  int i;
3525  os << std::endl;
3526  os << " name model name Parameters" << std::endl;
3527  for (i=0, iter=first; iter!=last; ++iter, ++i)
3528  {
3529  os << " " << i << ": " << (*iter)->getName() << "\t";
3530  os << getName();
3531  os << std::endl;
3532  }
3533  os << std::endl;
3534 
3535  return os;
3536 }
3537 
3538 //-----------------------------------------------------------------------------
3539 // Function : Model::forEachInstance
3540 // Purpose :
3541 // Special Notes :
3542 // Scope : public
3543 // Creator : David Baur
3544 // Creation Date : 2/4/2014
3545 //-----------------------------------------------------------------------------
3546 /// Apply a device instance "op" to all instances associated with this
3547 /// model
3548 ///
3549 /// @param[in] op Operator to apply to all instances.
3550 ///
3551 ///
3552 void Model::forEachInstance(DeviceInstanceOp &op) const /* override */
3553 {
3554  for (std::vector<Instance *>::const_iterator it = instanceContainer.begin(); it != instanceContainer.end(); ++it)
3555  op(*it);
3556 }
3557 
3558 
3559 //-----------------------------------------------------------------------------
3560 // MOSFET2 Master functions:
3561 //-----------------------------------------------------------------------------
3562 
3563 //-----------------------------------------------------------------------------
3564 // Function : Master::updateState
3565 // Purpose :
3566 // Special Notes :
3567 // Scope : public
3568 // Creator : Eric Keiter, SNL
3569 // Creation Date : 11/26/08
3570 //-----------------------------------------------------------------------------
3571 bool Master::updateState (double * solVec, double * staVec, double * stoVec)
3572 {
3573  bool bsuccess = true;
3574 
3575  for (InstanceVector::const_iterator it = getInstanceBegin(); it != getInstanceEnd(); ++it)
3576  {
3577  Instance & mi = *(*it);
3578  double * oldstaVec = mi.extData.currStaVectorRawPtr;
3579  double * stoVec = mi.extData.nextStoVectorRawPtr;
3580  double * oldstoVec = mi.extData.currStoVectorRawPtr;
3581 
3582  double vgs1(0.0), vgd1(0.0), vbs1(0.0),vgb1(0.0), vds1(0.0);
3583 
3584  bool btmp = mi.updateIntermediateVars ();
3585  bsuccess = bsuccess && btmp;
3586 
3587  // voltage drops:
3588  stoVec[mi.li_store_vbd] = mi.vbd;
3589  stoVec[mi.li_store_vbs] = mi.vbs;
3590  stoVec[mi.li_store_vgs] = mi.vgs;
3591  stoVec[mi.li_store_vds] = mi.vds;
3592  stoVec[mi.li_store_von] = mi.von;
3593 
3594  // now the meyer capacitances
3595  // we didn't calculate these charges in update IntermediateVars
3596  // but we did calculate the voltage drops and capacitances.
3597  // first store the capacitances themselves:
3598  staVec[mi.li_state_capgs] = mi.capgs;
3599  staVec[mi.li_state_capgd] = mi.capgd;
3600  staVec[mi.li_state_capgb] = mi.capgb;
3601 
3602  // now the charges
3603  // BE CAREFUL! We can only do Q=CV for DCOP! Otherwise it's
3604  // supposed to be *INTEGRATED*:
3605  // Q = int(t0,t1)C(V)*dV --- and we approximate that by
3606  // Q(t1)-Q(t0) = CBar*(V(t1)-V(t0)) where CBar is the average.
3607  // Now with Meyer back averaging, Capxx is the average between the last
3608  // time step and this one. So we gotta do the right thing for non-DCOP
3609  // when backaverage is on.
3610 
3611  if((getSolverState().dcopFlag))
3612  {
3613  mi.qgs = mi.Capgs*mi.vgs;
3614  mi.qgd = mi.Capgd*mi.vgd;
3615  mi.qgb = mi.Capgb*mi.Vgb;
3616  }
3617  else
3618  {
3619  // get the ones from last time step
3620  mi.qgs = oldstaVec[mi.li_state_qgs];
3621  mi.qgd = oldstaVec[mi.li_state_qgd];
3622  mi.qgb = oldstaVec[mi.li_state_qgb];
3623  // get the voltage drops, too
3624  vgs1 = oldstoVec[mi.li_store_vgs];
3625  vbs1 = oldstoVec[mi.li_store_vbs];
3626  vds1 = oldstoVec[mi.li_store_vds];
3627 
3628  vgb1 = vgs1-vbs1;
3629  vgd1 = vgs1-vds1;
3630 
3631  // NOW we can calculate the charge update
3632  mi.qgs += mi.Capgs*(mi.vgs-vgs1);
3633  mi.qgd += mi.Capgd*(mi.vgd-vgd1);
3634  mi.qgb += mi.Capgb*((mi.vgs-mi.vbs)-vgb1);
3635  }
3636 
3637  staVec[mi.li_state_qgs] = mi.qgs;
3638  staVec[mi.li_state_qgd] = mi.qgd;
3639  staVec[mi.li_state_qgb] = mi.qgb;
3640 
3641  // and the diode parasitic capacitors
3642  // these charges were set in updateIntermediateVars
3643  staVec[mi.li_state_qbd] = mi.qbd;
3644  staVec[mi.li_state_qbs] = mi.qbs;
3645  }
3646 
3647  return bsuccess;
3648 }
3649 
3650 //-----------------------------------------------------------------------------
3651 // Function : Master::loadDAEVectors
3652 // Purpose :
3653 // Special Notes :
3654 // Scope : public
3655 // Creator : Eric Keiter, SNL
3656 // Creation Date : 11/26/08
3657 //-----------------------------------------------------------------------------
3658 bool Master::loadDAEVectors (double * solVec, double * fVec, double *qVec, double * storeLeadF, double * storeLeadQ)
3659 {
3660  double gmin1 = getDeviceOptions().gmin;
3661 
3662  for (InstanceVector::const_iterator it = getInstanceBegin(); it != getInstanceEnd(); ++it)
3663  {
3664  Instance & mi = *(*it);
3665 
3666  int Dtype=mi.getModel().dtype;
3667  double ceqbs(0.0),ceqbd(0.0),ceqgb(0.0), ceqgs(0.0), ceqgd(0.0);
3668  double Qeqbs(0.0),Qeqbd(0.0),Qeqgb(0.0), Qeqgs(0.0), Qeqgd(0.0);
3669  double coef(0.0);
3670 
3671  // F-Vector:
3672  ceqbs = Dtype*(mi.cbs);
3673  ceqbd = Dtype*(mi.cbd);
3674  // These need "Dtype" here because we use them later *without*
3675  // Dtype, where SPICE uses it *with*
3676  ceqgb = 0.0;
3677  ceqgs = 0.0;
3678  ceqgd = 0.0;
3679 
3680  if (mi.drainConductance != 0.0)
3681  {
3682 
3683  fVec[mi.li_Drain] += mi.Idrain*mi.numberParallel;
3684  }
3685 
3686  coef = (ceqgs+ceqgd+ceqgb);
3687 
3688  fVec[mi.li_Gate] += coef*mi.numberParallel;
3689 
3690  if (mi.sourceConductance != 0.0)
3691  {
3692 
3693  fVec[mi.li_Source] += mi.Isource*mi.numberParallel;
3694  }
3695 
3696  coef = ceqbs + ceqbd - ceqgb;
3697 
3698  fVec[mi.li_Bulk] += coef*mi.numberParallel;
3699 
3700  coef = -mi.Idrain-(ceqbd - mi.cdreq + ceqgd);
3701 
3702  fVec[mi.li_DrainPrime] += coef*mi.numberParallel;
3703 
3704  coef = -mi.Isource-(ceqbs + mi.cdreq + ceqgs);
3705 
3706  fVec[mi.li_SourcePrime] += coef*mi.numberParallel;
3707 
3708  // Q-Vector:
3709  Qeqbs = Dtype*(mi.qbs);
3710  Qeqbd = Dtype*(mi.qbd);
3711  // These need "Dtype" here because we use them later *without*
3712  // Dtype, where SPICE uses it *with*
3713  Qeqgb = Dtype*(mi.qgb);
3714  Qeqgs = Dtype*(mi.qgs);
3715  Qeqgd = Dtype*(mi.qgd);
3716 
3717  coef = (Qeqgs+Qeqgd+Qeqgb);
3718 
3719  qVec[mi.li_Gate] += coef*mi.numberParallel;
3720 
3721  coef = Qeqbs + Qeqbd - Qeqgb;
3722 
3723  qVec[mi.li_Bulk] += coef*mi.numberParallel;
3724 
3725  coef = -(Qeqbd + Qeqgd);
3726 
3727  qVec[mi.li_DrainPrime] += coef*mi.numberParallel;
3728 
3729  coef = -(Qeqbs + Qeqgs);
3730 
3731  qVec[mi.li_SourcePrime] += coef*mi.numberParallel;
3732 
3733  // voltage limiters:
3734  if (!mi.origFlag)
3735  {
3736  // F-limiters:
3737  double coef_Jdxp4 = Dtype*(
3738  + ((mi.gbd-gmin1))*(mi.vbd-mi.vbd_orig)
3739  + ((mi.gbs-gmin1))*(mi.vbs-mi.vbs_orig));
3740 
3741  double coef_Jdxp5 = Dtype*(
3742  -((mi.gbd-gmin1))*(mi.vbd-mi.vbd_orig)
3743  +mi.gds*(mi.vds-mi.vds_orig)
3744  +mi.Gm*((mi.mode>0)?(mi.vgs-mi.vgs_orig):(mi.vgd-mi.vgd_orig))
3745  +mi.Gmbs*((mi.mode>0)?(mi.vbs-mi.vbs_orig):(mi.vbd-mi.vbd_orig)));
3746 
3747  double coef_Jdxp6 = Dtype*(
3748  -((mi.gbs-gmin1))*(mi.vbs-mi.vbs_orig)
3749  -mi.gds*(mi.vds-mi.vds_orig)
3750  -mi.Gm*((mi.mode>0)?(mi.vgs-mi.vgs_orig):(mi.vgd-mi.vgd_orig))
3751  -mi.Gmbs*((mi.mode>0)?(mi.vbs-mi.vbs_orig):(mi.vbd-mi.vbd_orig)));
3752 
3753  double * dFdxdVp = mi.extData.dFdxdVpVectorRawPtr;
3754 
3755  dFdxdVp[mi.li_Bulk ] += coef_Jdxp4*mi.numberParallel;
3756 
3757  dFdxdVp[mi.li_DrainPrime ] += coef_Jdxp5*mi.numberParallel;
3758 
3759  dFdxdVp[mi.li_SourcePrime] += coef_Jdxp6*mi.numberParallel;
3760 
3761  // Q-limiters:
3762  {
3763  double gcgd(0.0), gcgs(0.0), gcgb(0.0), gcbs(0.0), gcbd(0.0);
3764  if (getSolverState().tranopFlag || getSolverState().acopFlag || getSolverState().transientFlag)
3765  {
3766  gcgd = mi.Capgd;
3767  gcgs = mi.Capgs;
3768  gcgb = mi.Capgb;
3769  // get at the two parasitic caps the same way
3770  gcbs = mi.capbs;
3771  gcbd = mi.capbd;
3772  }
3773  else
3774  {
3775  gcgd = 0.0; gcgs = 0.0; gcgb = 0.0; gcbs = 0.0; gcbd = 0.0;
3776  }
3777 
3778  double coef_Jdxp2 =
3779  Dtype*(gcgd*(mi.vgd-mi.vgd_orig)+gcgs*(mi.vgs-mi.vgs_orig)+
3780  gcgb*(mi.vgs-mi.vgs_orig-mi.vbs+mi.vbs_orig));
3781 
3782  double coef_Jdxp4 = Dtype*(
3783  - (gcgb)*(mi.vgs-mi.vgs_orig-mi.vbs+mi.vbs_orig)
3784  + (gcgb)*(mi.vbd-mi.vbd_orig)
3785  + (gcbs)*(mi.vbs-mi.vbs_orig));
3786 
3787  double coef_Jdxp5 = Dtype*(
3788  -(gcgd)*(mi.vgd-mi.vgd_orig)
3789  -(gcbd)*(mi.vbd-mi.vbd_orig));
3790 
3791  // 6 KCL for source' node
3792  double coef_Jdxp6 = Dtype*
3793  (-gcgs*(mi.vgs-mi.vgs_orig)-(gcbs)*(mi.vbs-mi.vbs_orig));
3794 
3795  double * dQdxdVp = mi.extData.dQdxdVpVectorRawPtr;
3796  dQdxdVp[mi.li_Gate ] += coef_Jdxp2*mi.numberParallel;
3797  dQdxdVp[mi.li_Bulk ] += coef_Jdxp4*mi.numberParallel;
3798  dQdxdVp[mi.li_DrainPrime ] += coef_Jdxp5*mi.numberParallel;
3799  dQdxdVp[mi.li_SourcePrime] += coef_Jdxp6*mi.numberParallel;
3800  }
3801  }
3802 
3803  if( mi.loadLeadCurrent )
3804  {
3805  if (mi.drainConductance != 0.0)
3806  {
3807  storeLeadF[mi.li_store_dev_id] = mi.Idrain*mi.numberParallel;
3808  }
3809  else
3810  {
3811  storeLeadF[mi.li_store_dev_id] = (-mi.Idrain-(ceqbd - mi.cdreq + ceqgd))*mi.numberParallel;
3812  storeLeadQ[mi.li_store_dev_id] = (-(Qeqbd + Qeqgd))*mi.numberParallel;
3813  }
3814  if (mi.sourceConductance != 0.0)
3815  {
3816  storeLeadF[mi.li_store_dev_is] = mi.Isource*mi.numberParallel;
3817  }
3818  else
3819  {
3820  storeLeadF[mi.li_store_dev_is] = (-mi.Isource-(ceqbs + mi.cdreq + ceqgs))*mi.numberParallel;
3821  storeLeadQ[mi.li_store_dev_is] = (-(Qeqbs + Qeqgs))*mi.numberParallel;
3822  }
3823  storeLeadF[mi.li_store_dev_ig] = (ceqgs+ceqgd+ceqgb)*mi.numberParallel;
3824  storeLeadQ[mi.li_store_dev_ig] = (Qeqgs+Qeqgd+Qeqgb)*mi.numberParallel;
3825  storeLeadF[mi.li_store_dev_ib] = (ceqbs + ceqbd - ceqgb)*mi.numberParallel;
3826  storeLeadQ[mi.li_store_dev_ib] = (Qeqbs + Qeqbd - Qeqgb)*mi.numberParallel;
3827  }
3828  }
3829 
3830  return true;
3831 }
3832 
3833 
3834 #ifndef Xyce_NONPOINTER_MATRIX_LOAD
3835 //-----------------------------------------------------------------------------
3836 // Function : Master::loadDAEMatrices
3837 // Purpose :
3838 // Special Notes :
3839 // Scope : public
3840 // Creator : Eric Keiter, SNL
3841 // Creation Date : 11/26/08
3842 //-----------------------------------------------------------------------------
3843 bool Master::loadDAEMatrices (N_LAS_Matrix & dFdx, N_LAS_Matrix & dQdx)
3844 {
3845  for (InstanceVector::const_iterator it = getInstanceBegin(); it != getInstanceEnd(); ++it)
3846  {
3847  Instance & mi = *(*it);
3848 
3849  // F-matrix:
3850 
3851  *mi.f_DrainEquDrainNodePtr +=
3853 
3856 
3857 
3860 
3863 
3864 
3865  *mi.f_BulkEquBulkNodePtr +=
3866  (mi.gbs+mi.gbd)*mi.numberParallel;
3867 
3869 
3871 
3872 
3875 
3877  mi.Gm*mi.numberParallel;
3878 
3880  (-mi.gbd+mi.Gmbs)*mi.numberParallel;
3881 
3883  (mi.drainConductance+mi.gds+mi.gbd+mi.revsum)*mi.numberParallel;
3884 
3886  (-mi.gds-mi.nrmsum)*mi.numberParallel;
3887 
3888 
3890  mi.Gm*mi.numberParallel;
3891 
3894 
3896  (mi.gbs+mi.Gmbs)*mi.numberParallel;
3897 
3899  (mi.gds+mi.revsum)*mi.numberParallel;
3900 
3902  (mi.sourceConductance+mi.gds+mi.gbs+mi.nrmsum)*mi.numberParallel;
3903 
3904  // Q-matrix:
3905  double gcgd(0.0); // d(cqgd)/dVgd
3906  double gcgs(0.0); // d(cqgs)/dVgs
3907  double gcgb(0.0); // d(cqgb)/dVgb
3908  double gcbs(0.0); // d(cqbs)/dVbs
3909  double gcbd(0.0); // d(cqbd)/dVbd
3910 
3911  // get at the "conductances" for the gate capacitors with this trick
3912  // gcgd = model_.dtype*Capgd;
3913  // gcgs = model_.dtype*Capgs;
3914  // gcgb = model_.dtype*Capgb;
3915  //
3916  // In the loadRHS function, these would all be multiplied by
3917  // getSolverState().pdt. Here, for *mi.q_, the pdt term is left out.
3918  if (getSolverState().tranopFlag || getSolverState().acopFlag || getSolverState().transientFlag)
3919  {
3920  gcgd = mi.Capgd;
3921  gcgs = mi.Capgs;
3922  gcgb = mi.Capgb;
3923  // get at the two parasitic caps the same way
3924  gcbs = mi.capbs;
3925  gcbd = mi.capbd;
3926  }
3927 
3928 
3929  *mi.q_GateEquGateNodePtr +=
3930  (gcgd+gcgs+gcgb)*mi.numberParallel;
3931 
3932  *mi.q_GateEquBulkNodePtr -= gcgb*mi.numberParallel;
3933 
3935 
3937 
3938 
3939  *mi.q_BulkEquGateNodePtr -= gcgb*mi.numberParallel;
3940 
3941  *mi.q_BulkEquBulkNodePtr +=
3942  (+gcbs+gcbd+gcgb)*mi.numberParallel;
3943 
3945 
3947  +gcbs*mi.numberParallel;
3948 
3949 
3951  -gcgd*mi.numberParallel;
3952 
3954  -gcbd*mi.numberParallel;
3955 
3957  (+gcbd+gcgd)*mi.numberParallel;
3958 
3959 
3961  gcgs*mi.numberParallel;
3962 
3964  +gcbs*mi.numberParallel;
3965 
3967  (+gcbs+gcgs)*mi.numberParallel;
3968  }
3969 
3970  return true;
3971 }
3972 #else
3973 //-----------------------------------------------------------------------------
3974 // Function : Master::loadDAEMatrices
3975 // Purpose :
3976 // Special Notes :
3977 // Scope : public
3978 // Creator : Eric Keiter, SNL
3979 // Creation Date : 11/26/08
3980 //-----------------------------------------------------------------------------
3981 bool Master::loadDAEMatrices (N_LAS_Matrix & dFdx, N_LAS_Matrix & dQdx)
3982 {
3983  for (InstanceVector::const_iterator it = instanceContainer.begin(); it != instanceContainer.end(); ++it)
3984  {
3985  Instance & mi = *(*it);
3986 
3987  // F-matrix:
3988 
3989  dFdx[mi.li_Drain][mi.ADrainEquDrainNodeOffset] +=
3991 
3992  dFdx[mi.li_Drain][mi.ADrainEquDrainPrimeNodeOffset] -=
3994 
3995 
3996  dFdx[mi.li_Source][mi.ASourceEquSourceNodeOffset] +=
3998 
4001 
4002 
4003  dFdx[mi.li_Bulk][mi.ABulkEquBulkNodeOffset] +=
4004  (mi.gbs+mi.gbd)*mi.numberParallel;
4005 
4007 
4009 
4010 
4013 
4015  mi.Gm*mi.numberParallel;
4016 
4018  (-mi.gbd+mi.Gmbs)*mi.numberParallel;
4019 
4021  (mi.drainConductance+mi.gds+mi.gbd+mi.revsum)*mi.numberParallel;
4022 
4024  (-mi.gds-mi.nrmsum)*mi.numberParallel;
4025 
4026 
4028  mi.Gm*mi.numberParallel;
4029 
4032 
4034  (mi.gbs+mi.Gmbs)*mi.numberParallel;
4035 
4037  (mi.gds+mi.revsum)*mi.numberParallel;
4038 
4040  (mi.sourceConductance+mi.gds+mi.gbs+mi.nrmsum)*mi.numberParallel;
4041 
4042  // Q-matrix:
4043  double gcgd(0.0); // d(cqgd)/dVgd
4044  double gcgs(0.0); // d(cqgs)/dVgs
4045  double gcgb(0.0); // d(cqgb)/dVgb
4046  double gcbs(0.0); // d(cqbs)/dVbs
4047  double gcbd(0.0); // d(cqbd)/dVbd
4048 
4049  // get at the "conductances" for the gate capacitors with this trick
4050  // gcgd = model_.dtype*Capgd;
4051  // gcgs = model_.dtype*Capgs;
4052  // gcgb = model_.dtype*Capgb;
4053  //
4054  // In the loadRHS function, these would all be multiplied by
4055  // getSolverState().pdt. Here, for dQdx, the pdt term is left out.
4056  if (getSolverState().tranopFlag || getSolverState().acopFlag || getSolverState().transientFlag)
4057  {
4058  gcgd = mi.Capgd;
4059  gcgs = mi.Capgs;
4060  gcgb = mi.Capgb;
4061  // get at the two parasitic caps the same way
4062  gcbs = mi.capbs;
4063  gcbd = mi.capbd;
4064  }
4065 
4066 
4067  dQdx[mi.li_Gate][mi.AGateEquGateNodeOffset] +=
4068  (gcgd+gcgs+gcgb)*mi.numberParallel;
4069 
4070  dQdx[mi.li_Gate][mi.AGateEquBulkNodeOffset] -= gcgb*mi.numberParallel;
4071 
4072  dQdx[mi.li_Gate][mi.AGateEquDrainPrimeNodeOffset] -= gcgd*mi.numberParallel;
4073 
4074  dQdx[mi.li_Gate][mi.AGateEquSourcePrimeNodeOffset] -= gcgs*mi.numberParallel;
4075 
4076 
4077  dQdx[mi.li_Bulk][mi.ABulkEquGateNodeOffset] -= gcgb*mi.numberParallel;
4078 
4079  dQdx[mi.li_Bulk][mi.ABulkEquBulkNodeOffset] +=
4080  (+gcbs+gcbd+gcgb)*mi.numberParallel;
4081 
4082  dQdx[mi.li_Bulk][mi.ABulkEquDrainPrimeNodeOffset] -= +gcbd*mi.numberParallel;
4083 
4084  dQdx[mi.li_Bulk][mi.ABulkEquSourcePrimeNodeOffset] -=
4085  +gcbs*mi.numberParallel;
4086 
4087 
4089  -gcgd*mi.numberParallel;
4090 
4092  -gcbd*mi.numberParallel;
4093 
4095  (+gcbd+gcgd)*mi.numberParallel;
4096 
4097 
4099  gcgs*mi.numberParallel;
4100 
4102  +gcbs*mi.numberParallel;
4103 
4105  (+gcbs+gcgs)*mi.numberParallel;
4106  }
4107  return true;
4108 }
4109 
4110 #endif
4111 
4112 Device *Traits::factory(const Configuration &configuration, const FactoryBlock &factory_block)
4113 {
4114 
4115  return new Master(configuration, factory_block, factory_block.solverState_, factory_block.deviceOptions_);
4116 }
4117 
4119 {
4121  .registerDevice("m", 2)
4122  .registerModelType("pmos", 2)
4123  .registerModelType("nmos", 2);
4124 }
4125 
4126 } // namespace MOSFET2
4127 } // namespace Device
4128 } // namespace Xyce
4129