Xyce  6.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
N_DEV_MOSFET3.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_MOSFET3.C,v $
27 //
28 // Purpose : Implement the MOSFET Level 3 static model
29 //
30 // Special Notes : BADMOS3 option not supported.
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.245 $
40 //
41 // Revision Date : $Date: 2014/05/22 17:40:30 $
42 //
43 // Current Owner : $Author: erkeite $
44 //-------------------------------------------------------------------------
45 
46 #include <Xyce_config.h>
47 
48 
49 // ---------- Standard Includes ----------
50 
51 #ifdef HAVE_CMATH
52 #include <cmath>
53 #else
54 #include <math.h>
55 #endif
56 
57 // ---------- Xyce Includes ----------
58 #include <N_DEV_Const.h>
59 #include <N_DEV_DeviceOptions.h>
60 #include <N_DEV_ExternData.h>
61 #include <N_DEV_MOSFET3.h>
62 #include <N_DEV_MatrixLoadData.h>
63 #include <N_DEV_SolverState.h>
64 #include <N_DEV_Message.h>
65 #include <N_DEV_Message.h>
66 #include <N_DEV_Message.h>
67 #include <N_ERH_ErrorMgr.h>
68 
69 #include <N_DEV_MOSFET1.h>
70 
71 #include <N_LAS_Matrix.h>
72 #include <N_LAS_Vector.h>
73 
74 namespace Xyce {
75 namespace Device {
76 
77 
78 namespace MOSFET3 {
79 
80 
82 {
83  // Set up configuration constants:
84 // Set up double precision variables:
85  p.addPar ("TEMP", 0.0, false, ParameterType::TIME_DEP,
87  STANDARD, CAT_NONE, "Device temperature"),
88 
89  p.addPar ("L", 0.0, true, ParameterType::NO_DEP,
90  &MOSFET3::Instance::l, NULL,
91  U_METER, CAT_GEOMETRY, "Channel length"),
92 
93  p.addPar ("W", 0.0, true, ParameterType::NO_DEP,
94  &MOSFET3::Instance::w, NULL,
95  U_METER, CAT_GEOMETRY, "Channel width"),
96 
97  p.addPar ("AD", 0.0, false, ParameterType::NO_DEP,
99  U_METER2, CAT_GEOMETRY, "Drain diffusion area"),
100 
101  p.addPar ("AS", 0.0, false, ParameterType::NO_DEP,
103  U_METER2, CAT_GEOMETRY, "Source diffusion area"),
104 
105  p.addPar ("NRD", 1.0, false, ParameterType::NO_DEP,
107  U_SQUARES, CAT_GEOMETRY, "Multiplier for RSH to yield parasitic resistance of drain"),
108 
109  p.addPar ("NRS", 1.0, false, ParameterType::NO_DEP,
111  U_SQUARES, CAT_GEOMETRY, "Multiplier for RSH to yield parasitic resistance of source"),
112 
113  p.addPar ("PD", 0.0, false, ParameterType::NO_DEP,
115  U_METER, CAT_GEOMETRY, "Drain diffusion perimeter"),
116 
117  p.addPar ("PS", 0.0, false, ParameterType::NO_DEP,
119  U_METER, CAT_GEOMETRY, "Source diffusion perimeter"),
120 
121  p.addPar ("M", 1.0, false, ParameterType::NO_DEP,
123  U_NONE, CAT_CONTROL, "Multiplier for M devices connected in parallel"),
124 
125  // Initial conditions
126  p.addPar ("IC1", 0.0, false, NO_DEP,
129  U_VOLT, CAT_INITIAL, "Initial condition on Drain-Source voltage");
130 
131  p.addPar ("IC2", 0.0, false, NO_DEP,
134  U_VOLT, CAT_INITIAL, "Initial condition on Gate-Source voltage");
135 
136  p.addPar ("IC3", 0.0, false, NO_DEP,
139  U_VOLT, CAT_INITIAL, "Initial condition on Bulk-Source voltage");
140 
141  p.makeVector ("IC",3);
142 
143  // Set up non-double precision variables:
144  p.addPar ("OFF",false,false, ParameterType::NO_DEP,
146  NULL, U_LOGIC, CAT_VOLT,
147  "Initial condition of no voltage drops across device");
148 }
149 
151 {
152  // Set up double precision variables:
153  p.addPar ("L", 1e-4, false, ParameterType::NO_DEP,
155  U_METER, CAT_GEOMETRY, "Default channel length"),
156 
157  p.addPar ("W", 1e-4, false, ParameterType::NO_DEP,
159  U_METER, CAT_GEOMETRY, "Default channel width"),
160 
161  p.addPar ("VTO", 0.0, false, ParameterType::NO_DEP,
162  &MOSFET3::Model::vt0, NULL,
163  U_VOLT, CAT_VOLT, "Zero-bias threshold voltage"),
164 
165  p.addPar ("KP", 2e-5, false, ParameterType::NO_DEP,
167  U_AMPVM2, CAT_PROCESS, "Transconductance coefficient"),
168 
169  p.addPar ("GAMMA", 0.0, false, ParameterType::NO_DEP,
170  &MOSFET3::Model::gamma, NULL,
171  U_VOLTH, CAT_PROCESS, "Bulk threshold parameter"),
172 
173  p.addPar ("PHI", 0.6, false, ParameterType::NO_DEP,
174  &MOSFET3::Model::phi, NULL,
175  U_VOLT, CAT_PROCESS, "Surface potential"),
176 
177  p.addPar ("RD", 0.0, false, ParameterType::MIN_RES,
179  U_OHM, CAT_RES, "Drain ohmic resistance"),
180 
181  p.addPar ("RS", 0.0, false, ParameterType::MIN_RES,
183  U_OHM, CAT_RES, "Source ohmic resistance"),
184 
185  p.addPar ("CBD", 0.0, false, ParameterType::MIN_CAP,
188  U_FARAD, CAT_CAP, "Zero-bias bulk-drain p-n capacitance"),
189 
190  p.addPar ("CBS", 0.0, false, ParameterType::MIN_CAP,
193  U_FARAD, CAT_CAP, "Zero-bias bulk-source p-n capacitance"),
194 
195  p.addPar ("IS", 1e-14, false, ParameterType::NO_DEP,
197  U_AMP, CAT_CURRENT, "Bulk p-n saturation current"),
198 
199  p.addPar ("PB", 0.8, false, ParameterType::NO_DEP,
201  U_VOLT, CAT_VOLT, "Bulk p-n bottom potential"),
202 
203  p.addPar ("CGSO", 0.0, false, ParameterType::NO_DEP,
205  U_FARADMM1, CAT_CAP, "Gate-source overlap capacitance/channel width"),
206 
207  p.addPar ("CGDO", 0.0, false, ParameterType::NO_DEP,
209  U_FARADMM1, CAT_CAP, "Gate-drain overlap capacitance/channel width"),
210 
211  p.addPar ("CGBO", 0.0, false, ParameterType::NO_DEP,
213  U_FARADMM1, CAT_CAP, "Gate-bulk overlap capacitance/channel length"),
214 
215  p.addPar ("RSH", 0.0, false, ParameterType::NO_DEP,
217  U_OHM, CAT_RES, "Drain, source diffusion sheet resistance"),
218 
219  p.addPar ("CJ", 0.0, false, ParameterType::NO_DEP,
222  U_FARADMM2, CAT_CAP, "Bulk p-n zero-bias bottom capacitance/area"),
223 
224  p.addPar ("MJ", 0.5, false, ParameterType::NO_DEP,
226  U_NONE, CAT_DOPING, "Bulk p-n bottom grading coefficient"),
227 
228  p.addPar ("CJSW", 0.0, false, ParameterType::NO_DEP,
231  U_FARADMM2, CAT_CAP, "Bulk p-n zero-bias sidewall capacitance/area"),
232 
233  p.addPar ("MJSW", 0.33, false, ParameterType::NO_DEP,
235  U_NONE, CAT_DOPING, "Bulk p-n sidewall grading coefficient"),
236 
237  p.addPar ("JS", 0.0, false, ParameterType::NO_DEP,
239  U_AMPMM2, CAT_PROCESS, "Bulk p-n saturation current density"),
240 
241  p.addPar ("TOX", 1e-7, true, ParameterType::NO_DEP,
243  U_METER, CAT_GEOMETRY, "Gate oxide thickness"),
244 
245  p.addPar ("LD", 0.0, false, ParameterType::NO_DEP,
247  U_METER, CAT_DOPING, "Lateral diffusion length"),
248 
249  p.addPar ("UO", 600.0, false, ParameterType::NO_DEP,
251  U_CMM2VM1SM1, ParameterCategory(CAT_PROCESS | UNDOCUMENTED), "Surface mobility"),
252 
253  p.addPar ("U0", 600.0, false, ParameterType::NO_DEP,
255  U_CMM2VM1SM1, CAT_PROCESS, "Surface mobility"),
256 
257  p.addPar ("FC", 0.5, false, ParameterType::NO_DEP,
259  U_NONE, CAT_CAP, "Bulk p-n forward-bias capacitance coefficient"),
260 
261  p.addPar ("NSUB", 0.0, false, ParameterType::NO_DEP,
263  U_CMM3, CAT_DOPING, "Substrate doping density"),
264 
265  p.addPar ("NSS", 0.0, false, ParameterType::NO_DEP,
267  U_CMM2, CAT_PROCESS, "Surface state density"),
268 
269  p.addPar ("ETA", 0.0, false, ParameterType::NO_DEP,
270  &MOSFET3::Model::eta, NULL,
271  U_NONE, CAT_PROCESS, "Static feedback"),
272 
273  p.addPar ("DELTA", 0.0, false, ParameterType::NO_DEP,
274  &MOSFET3::Model::delta, NULL,
275  U_NONE, CAT_PROCESS, "Width effect on threshold"),
276 
277  p.addPar ("NFS", 0.0, false, ParameterType::NO_DEP,
279  U_CMM2, CAT_PROCESS, "Fast surface state density"),
280 
281  p.addPar ("THETA", 0.0, false, ParameterType::NO_DEP,
282  &MOSFET3::Model::theta, NULL,
283  U_VOLTM1, CAT_PROCESS, "Mobility modulation"),
284 
285  p.addPar ("VMAX", 0.0, false, ParameterType::NO_DEP,
287  U_MSM1, CAT_PROCESS, "Maximum drift velocity"),
288 
289  p.addPar ("KAPPA", 0.2, false, ParameterType::NO_DEP,
290  &MOSFET3::Model::kappa, NULL,
291  U_NONE, CAT_NONE, "Saturation field factor"),
292 
293  p.addPar ("XJ", 0.0, false, ParameterType::NO_DEP,
295  U_METER, CAT_GEOMETRY, "Metallurgical junction depth"),
296 
297  p.addPar ("TNOM", 27.0, false, ParameterType::NO_DEP,
298  &MOSFET3::Model::tnom, NULL,
299  STANDARD, CAT_NONE, ""),
300 
301  p.addPar ("KF", 0.0, false, ParameterType::NO_DEP,
302  &MOSFET3::Model::fNcoef, NULL,
303  U_NONE, CAT_FLICKER, "Flicker noise coefficient"),
304 
305  p.addPar ("AF", 1.0, false, ParameterType::NO_DEP,
306  &MOSFET3::Model::fNexp, NULL,
307  U_NONE, CAT_FLICKER, "Flicker noise exponent"),
308 
309  // Set up non-double precision variables:
310  p.addPar ("TPG", 1, false, ParameterType::NO_DEP,
312  U_NONE, CAT_MATERIAL, "Gate material type (-1 = same as substrate,"
313  " 0 = aluminum, 1 = opposite of substrate)");
314 
316 }
317 
318 
319 
320 std::vector< std::vector<int> > Instance::jacStamp_DC_SC;
321 std::vector< std::vector<int> > Instance::jacStamp_DC;
322 std::vector< std::vector<int> > Instance::jacStamp_SC;
323 std::vector< std::vector<int> > Instance::jacStamp;
324 
325 std::vector<int> Instance::jacMap_DC_SC;
326 std::vector<int> Instance::jacMap_DC;
327 std::vector<int> Instance::jacMap_SC;
328 std::vector<int> Instance::jacMap;
329 
330 std::vector< std::vector<int> > Instance::jacMap2_DC_SC;
331 std::vector< std::vector<int> > Instance::jacMap2_DC;
332 std::vector< std::vector<int> > Instance::jacMap2_SC;
333 std::vector< std::vector<int> > Instance::jacMap2;
334 
335 // Class Instance
336 //-----------------------------------------------------------------------------
337 // Function : Instance::processParams
338 // Purpose :
339 // Special Notes :
340 // Scope : public
341 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
342 // Creation Date : 6/03/02
343 //-----------------------------------------------------------------------------
345 {
346 
347  // now set the temperature related stuff
349 
350  return true;
351 }
352 
353 //-----------------------------------------------------------------------------
354 // Function : Instance::Instance
355 // Purpose : instance block constructor
356 // Special Notes :
357 // Scope : public
358 // Creator : Tom Russo, Component Information and Models
359 // Creation Date : 3/21/01
360 //-----------------------------------------------------------------------------
362  const Configuration & configuration,
363  const InstanceBlock & IB,
364  Model & Miter,
365  const FactoryBlock & factory_block)
366  : DeviceInstance(IB, configuration.getInstanceParameters(), factory_block),
367  model_(Miter),
368  dNode(0),
369  gNode(0),
370  sNode(0),
371  bNode(0),
372  dNodePrime(0),
373  sNodePrime(0),
374  l(getDeviceOptions().defl),
375  w(getDeviceOptions().defw),
376  OFF(false),
377  drainArea(getDeviceOptions().defad),
378  sourceArea(getDeviceOptions().defas),
379  drainSquares(1.0),
380  sourceSquares(1.0),
381  drainPerimeter(0.0),
382  sourcePerimeter(0.0),
383  sourceConductance(0.0),
384  drainConductance(0.0),
385  temp(getDeviceOptions().temp.getImmutableValue<double>()),
386  numberParallel(1.0),
387  tTransconductance(0.0),
388  tSurfMob(0.0),
389  tPhi(0.0),
390  tVto(0.0),
391  tSatCur(0.0),
392  tSatCurDens(0.0),
393  tCbd(0.0),
394  tCbs(0.0),
395  tCj(0.0),
396  tCjsw(0.0),
397  tBulkPot(0.0),
398  tDepCap(0.0),
399  tVbi(0.0),
400  icVBS(0.0),
401  icVDS(0.0),
402  icVGS(0.0),
403  von(0.0),
404  vdsat(0.0),
405  sourceVcrit(0.0),
406  drainVcrit(0.0),
407  cd(0.0),
408  cbs(0.0),
409  cbd(0.0),
410  gmbs(0.0),
411  gm(0.0),
412  gds(0.0),
413  gbd(0.0),
414  gbs(0.0),
415  capbd(0.0),
416  capbs(0.0),
417  Cbd(0.0),
418  Cbdsw(0.0),
419  Cbs(0.0),
420  Cbssw(0.0),
421  f2d(0.0),
422  f3d(0.0),
423  f4d(0.0),
424  f2s(0.0),
425  f3s(0.0),
426  f4s(0.0),
427  mode(1),
428  mode_low(0.0),
429  mode_high(0.0),
430  limitedFlag(false),
431  IC_GIVEN(false),
432  Idrain(0.0),
433  Isource(0.0),
434  //calculated quantities
435  EffectiveLength(0),
436  DrainSatCur(0),
437  SourceSatCur(0),
438  GateSourceOverlapCap(0),
439  GateDrainOverlapCap(0),
440  GateBulkOverlapCap(0),
441  OxideCap(0),
442  // local indices
443  li_Drain(-1),
444  li_DrainPrime(-1),
445  li_Source(-1),
446  li_SourcePrime(-1),
447  li_Gate(-1),
448  li_Bulk(-1),
449  // matrix and vector pointers:
450  // jacobian:
451  // drain row
452  ADrainEquDrainNodeOffset(-1),
453  ADrainEquDrainPrimeNodeOffset(-1),
454  // gate row
455  AGateEquGateNodeOffset(-1),
456  AGateEquBulkNodeOffset(-1),
457  AGateEquDrainPrimeNodeOffset(-1),
458  AGateEquSourcePrimeNodeOffset(-1),
459  // source row
460  ASourceEquSourceNodeOffset(-1),
461  ASourceEquSourcePrimeNodeOffset(-1),
462  // bulk row
463  ABulkEquGateNodeOffset(-1),
464  ABulkEquBulkNodeOffset(-1),
465  ABulkEquDrainPrimeNodeOffset(-1),
466  ABulkEquSourcePrimeNodeOffset(-1),
467  // drain' row
468  ADrainPrimeEquDrainNodeOffset(-1),
469  ADrainPrimeEquGateNodeOffset(-1),
470  ADrainPrimeEquBulkNodeOffset(-1),
471  ADrainPrimeEquDrainPrimeNodeOffset(-1),
472  ADrainPrimeEquSourcePrimeNodeOffset(-1),
473  // source' row
474  ASourcePrimeEquGateNodeOffset(-1),
475  ASourcePrimeEquSourceNodeOffset(-1),
476  ASourcePrimeEquBulkNodeOffset(-1),
477  ASourcePrimeEquDrainPrimeNodeOffset(-1),
478  ASourcePrimeEquSourcePrimeNodeOffset(-1),
479 
481  // F-vector pointers:
482  // V_d Row:
483  f_DrainEquDrainNodePtr(0), // a
484  f_DrainEquDrainPrimeNodePtr(0), // b
485  // V_g Row:
486  f_GateEquGateNodePtr(0), // c
487  f_GateEquBulkNodePtr(0), // d
488  f_GateEquDrainPrimeNodePtr(0), // e
489  f_GateEquSourcePrimeNodePtr(0), // f
490  // V_s Row:
491  f_SourceEquSourceNodePtr(0), // g
492  f_SourceEquSourcePrimeNodePtr(0), // h
493  // V_b Row:
494  f_BulkEquGateNodePtr(0), // i
495  f_BulkEquBulkNodePtr(0), // j
496  f_BulkEquDrainPrimeNodePtr(0), // k
497  f_BulkEquSourcePrimeNodePtr(0), // l
498  // V_d' Row:
499  f_DrainPrimeEquDrainNodePtr(0), // m
500  f_DrainPrimeEquGateNodePtr(0), // n
501  f_DrainPrimeEquBulkNodePtr(0), // o
502  f_DrainPrimeEquDrainPrimeNodePtr(0), // p
503  f_DrainPrimeEquSourcePrimeNodePtr(0), // q
504  // V_s' Row:
505  f_SourcePrimeEquGateNodePtr(0), // r
506  f_SourcePrimeEquSourceNodePtr(0), // s
507  f_SourcePrimeEquBulkNodePtr(0), // t
508  f_SourcePrimeEquDrainPrimeNodePtr(0), // u
509  f_SourcePrimeEquSourcePrimeNodePtr(0), // v
510  // Q-vector pointers:
511  // V_d Row:
512  q_DrainEquDrainNodePtr(0), // a
513  q_DrainEquDrainPrimeNodePtr(0), // b
514  // V_g Row:
515  q_GateEquGateNodePtr(0), // c
516  q_GateEquBulkNodePtr(0), // d
517  q_GateEquDrainPrimeNodePtr(0), // e
518  q_GateEquSourcePrimeNodePtr(0), // f
519  // V_s Row:
520  q_SourceEquSourceNodePtr(0), // g
521  q_SourceEquSourcePrimeNodePtr(0), // h
522  // V_b Row:
523  q_BulkEquGateNodePtr(0), // i
524  q_BulkEquBulkNodePtr(0), // j
525  q_BulkEquDrainPrimeNodePtr(0), // k
526  q_BulkEquSourcePrimeNodePtr(0), // l
527  // V_d' Row:
528  q_DrainPrimeEquDrainNodePtr(0), // m
529  q_DrainPrimeEquGateNodePtr(0), // n
530  q_DrainPrimeEquBulkNodePtr(0), // o
531  q_DrainPrimeEquDrainPrimeNodePtr(0), // p
532  q_DrainPrimeEquSourcePrimeNodePtr(0), // q
533  // V_s' Row:
534  q_SourcePrimeEquGateNodePtr(0), // r
535  q_SourcePrimeEquSourceNodePtr(0), // s
536  q_SourcePrimeEquBulkNodePtr(0), // t
537  q_SourcePrimeEquDrainPrimeNodePtr(0), // u
538  q_SourcePrimeEquSourcePrimeNodePtr(0), // v
539 #endif
540 
541  vbd(0.0),
542  vbs(0.0),
543  vgs(0.0),
544  vds(0.0),
545  vbd_old(0.0),
546  vbs_old(0.0),
547  vgs_old(0.0),
548  vds_old(0.0),
549  vbd_orig(0.0),
550  vbs_orig(0.0),
551  vgs_orig(0.0),
552  vds_orig(0.0),
553  capgs(0.0),
554  qgs(0.0),
555  capgd(0.0),
556  qgd(0.0),
557  capgb(0.0),
558  qgb(0.0),
559  qbd(0.0),
560  qbs(0.0),
561  // local indices
562  li_store_vbd(-1),
563  li_store_vbs(-1),
564  li_store_vgs(-1),
565  li_store_vds(-1),
566  li_store_von(-1),
567  li_store_dev_id(-1),
568  li_store_dev_is(-1),
569  li_store_dev_ig(-1),
570  li_store_dev_ib(-1),
571  li_state_qgs(-1),
572  li_state_qgd(-1),
573  li_state_qgb(-1),
574  li_state_capgs(-1),
575  li_state_capgd(-1),
576  li_state_capgb(-1),
577  li_state_qbd(-1),
578  li_state_qbs(-1),
579  blockHomotopyID(0),
580  randomPerturb(0.0)
581 {
582  numIntVars = 2;
583  numExtVars = 4;
584 
585  setNumStoreVars(5);
586  numLeadCurrentStoreVars = 4; // drain, gate, source & base lead currents
587  numStateVars = 8;
588 
589  devConMap.resize(4);
590  devConMap[0] = 1;
591  devConMap[1] = 2;
592  devConMap[2] = 1;
593  devConMap[3] = 3;
594 
596  devSupport.getGainScaleBlockID(getDeviceOptions().numGainScaleBlocks);
597  randomPerturb =
599 
600  if( jacStamp.empty() )
601  {
602  // stamp for RS!=0, RD!=0
603  jacStamp_DC_SC.resize(6);
604  jacStamp_DC_SC[0].resize(2); // Drain row
605  jacStamp_DC_SC[0][0]=0; // d-d
606  jacStamp_DC_SC[0][1]=4; // d-d'
607  jacStamp_DC_SC[1].resize(4); // Gate row
608  jacStamp_DC_SC[1][0]=1; // g-g
609  jacStamp_DC_SC[1][1]=3; // g-b
610  jacStamp_DC_SC[1][2]=4; // g-d'
611  jacStamp_DC_SC[1][3]=5; // g-s'
612  jacStamp_DC_SC[2].resize(2); // Source row
613  jacStamp_DC_SC[2][0]=2; // s-s
614  jacStamp_DC_SC[2][1]=5; // s-s'
615  jacStamp_DC_SC[3].resize(4); // Bulk row
616  jacStamp_DC_SC[3][0]=1; // b-g
617  jacStamp_DC_SC[3][1]=3; // b-b
618  jacStamp_DC_SC[3][2]=4; // b-d'
619  jacStamp_DC_SC[3][3]=5; // b-s'
620  jacStamp_DC_SC[4].resize(5); // Drain' row
621  jacStamp_DC_SC[4][0]=0; // d'-d
622  jacStamp_DC_SC[4][1]=1; // d'-g
623  jacStamp_DC_SC[4][2]=3; // d'-b
624  jacStamp_DC_SC[4][3]=4; // d'-d'
625  jacStamp_DC_SC[4][4]=5; // d'-s'
626  jacStamp_DC_SC[5].resize(5); // Source' row
627  jacStamp_DC_SC[5][0]=1; // s'-g
628  jacStamp_DC_SC[5][1]=2; // s'-s
629  jacStamp_DC_SC[5][2]=3; // s'-b
630  jacStamp_DC_SC[5][3]=4; // s'-d'
631  jacStamp_DC_SC[5][4]=5; // s'-s'
632 
633  jacMap_DC_SC.clear();
635  jacStamp_DC, jacMap_DC, jacMap2_DC, 5, 2, 6);
636 
638  jacStamp_SC, jacMap_SC, jacMap2_SC, 4, 0, 6);
639 
641  jacStamp, jacMap, jacMap2, 4, 0, 6);
642  }
643 
644  // Set params to constant default values:
645  setDefaultParams ();
646 
647  // Set params according to instance line and constant defaults from metadata:
648  setParams (IB.params);
649 
650  // Set any non-constant parameter defaults:
651  if (!given("TEMP"))
652  temp = getDeviceOptions().temp.getImmutableValue<double>();
653  if (!given("L"))
654  l =model_.model_l;
655  if (!given("W"))
656  w = model_.model_w;
657 
658  if (!given("AD"))
660  if (!given("AS"))
662 
663  // Note: processParams needs to be before the drain, source resistance calculations.
664  processParams ();
665 
666  // process source/drain series resistance (from mos1temp)
667  if(model_.drainResistance != 0)
668  {
670  }
671  else if (model_.given("RSH"))
672  {
673  if(model_.sheetResistance != 0)
674  {
677  }
678  else
679  {
680  drainConductance = 0;
681  }
682  }
683  else
684  {
685  drainConductance = 0;
686  }
687  if(model_.sourceResistance != 0)
688  {
690  }
691  else if (model_.given("RSH"))
692  {
693  if(model_.sheetResistance != 0)
694  {
697  }
698  else
699  {
700  sourceConductance = 0;
701  }
702  }
703  else
704  {
705  sourceConductance = 0;
706  }
707 
708  // Calculate any parameters specified as expressions:
709 
711 
712  // calculate dependent (ie computed) params and check for errors:
713 
714  if(l - 2 * model_.latDiff <=0)
715  {
716  UserError0(*this) << "Effective channel length less than zero.";
717  }
718 
724 
725  numIntVars = (((sourceConductance == 0.0)?0:1)+((drainConductance == 0.0) ? 0:1));
726 }
727 
728 //-----------------------------------------------------------------------------
729 // Function : Instance::~Instance
730 // Purpose : destructor
731 // Special Notes :
732 // Scope : public
733 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
734 // Creation Date : 3/16/00
735 //-----------------------------------------------------------------------------
737 {
738 }
739 
740 //-----------------------------------------------------------------------------
741 // Function : Instance::registerLIDs
742 // Purpose :
743 // Special Notes :
744 // Scope : public
745 // Creator : Robert Hoekstra, Computational Sciences
746 // Creation Date : 6/21/02
747 //-----------------------------------------------------------------------------
748 void Instance::registerLIDs( const std::vector<int> & intLIDVecRef,
749  const std::vector<int> & extLIDVecRef )
750 {
751  numIntVars = (((sourceConductance == 0.0)?0:1)+((drainConductance == 0.0) ? 0:1));
752 
753  AssertLIDs(intLIDVecRef.size() == numIntVars);
754  AssertLIDs(extLIDVecRef.size() == numExtVars);
755 
756 #ifdef Xyce_DEBUG_DEVICE
757  if (getDeviceOptions().debugLevel > 0)
758  {
759  Xyce::dout() << section_divider << std::endl;
760  Xyce::dout() << " In Instance::register LIDs\n\n";
761  Xyce::dout() << " name = " << getName() << std::endl;
762  Xyce::dout() << " number of internal variables: " << numIntVars << std::endl;
763  Xyce::dout() << " number of external variables: " << numExtVars << std::endl;
764  }
765 #endif
766 
767  // copy over the global ID lists.
768  intLIDVec = intLIDVecRef;
769  extLIDVec = extLIDVecRef;
770 
771  // now use these lists to obtain the indices into the
772  // linear algebra entities. This assumes an order.
773  // For the matrix indices, first do the rows.
774 
775  li_Drain = extLIDVec[0];
776  li_Gate = extLIDVec[1];
777  li_Source = extLIDVec[2];
778  li_Bulk = extLIDVec[3];
779 
780  int intLoc = 0;
781 
782  if( drainConductance )
783  li_DrainPrime = intLIDVec[intLoc++];
784  else
786 
787  if( sourceConductance )
788  li_SourcePrime = intLIDVec[intLoc];
789  else
791 
792 #ifdef Xyce_DEBUG_DEVICE
793  if (getDeviceOptions().debugLevel > 0)
794  {
795  Xyce::dout() << "\n variable local indices:\n";
796  Xyce::dout() << " li_Drain = " << li_Drain << std::endl;
797  Xyce::dout() << " li_DrainPrime = " << li_DrainPrime << std::endl;
798  Xyce::dout() << " li_Source = " << li_Source << std::endl;
799  Xyce::dout() << " li_SourcePrime = " << li_SourcePrime << std::endl;
800  Xyce::dout() << " li_Gate = " << li_Gate << std::endl;
801  Xyce::dout() << " li_Bulk = " << li_Bulk << std::endl;
802 
803  Xyce::dout() << section_divider << std::endl;
804  }
805 #endif
806 
807 }
808 
809 //-----------------------------------------------------------------------------
810 // Function : Instance::getIntNameMap
811 // Purpose :
812 // Special Notes :
813 // Scope : public
814 // Creator : Eric R. Keiter, SNL, Parallel Computational Sciences
815 // Creation Date : 05/13/05
816 //-----------------------------------------------------------------------------
817 std::map<int,std::string> & Instance::getIntNameMap ()
818 {
819  // set up the internal name map, if it hasn't been already.
820  if (intNameMap.empty ())
821  {
822  if ( li_DrainPrime != li_Drain )
823  {
824  intNameMap[ li_DrainPrime ] = spiceInternalName(getName(), "drainprime");
825  }
826 
827  if ( li_SourcePrime != li_Source )
828  {
829  intNameMap[ li_SourcePrime ] = spiceInternalName(getName(), "sourceprime");
830  }
831  }
832 
833  return intNameMap;
834 }
835 
836 //-----------------------------------------------------------------------------
837 // Function : N_DEV_MOSFET3Instance::getStoreNameMap
838 // Purpose :
839 // Special Notes :
840 // Scope : public
841 // Creator : Richard Schiek, Electrical Systems Modeling
842 // Creation Date : 4/3/2013
843 //-----------------------------------------------------------------------------
844 std::map<int,std::string> & N_DEV_MOSFET3Instance::getStoreNameMap ()
845 {
846  // set up the internal name map, if it hasn't been already.
847  if( loadLeadCurrent && storeNameMap.empty ())
848  {
849  storeNameMap[ li_store_dev_id ] = spiceStoreName(getName(), "DEV_ID");
850  storeNameMap[ li_store_dev_is ] = spiceStoreName(getName(), "DEV_IS");
851  storeNameMap[ li_store_dev_ig ] = spiceStoreName(getName(), "DEV_IG");
852  storeNameMap[ li_store_dev_ib ] = spiceStoreName(getName(), "DEV_IB");
853  }
854 
855  return storeNameMap;
856 }
857 
858 
859 //-----------------------------------------------------------------------------
860 // Function : Instance::registerStateLIDs
861 // Purpose :
862 // Special Notes :
863 // Scope : public
864 // Creator : Robert Hoekstra, Computational Sciences
865 // Creation Date : 6/21/02
866 //-----------------------------------------------------------------------------
867 void Instance::registerStateLIDs( const std::vector<int> & staLIDVecRef )
868 {
869  AssertLIDs(staLIDVecRef.size() == numStateVars);
870 
871 #ifdef Xyce_DEBUG_DEVICE
872  if (getDeviceOptions().debugLevel > 0)
873  {
874  Xyce::dout() << std::endl;
875  Xyce::dout() << section_divider << std::endl;
876  Xyce::dout() << " In Instance::registerStateLIDs\n\n";
877  Xyce::dout() << " name = " << getName() << std::endl;
878  Xyce::dout() << " Number of State LIDs: " << numStateVars << std::endl;
879  }
880 #endif
881 
882  // Copy over the global ID lists:
883  staLIDVec = staLIDVecRef;
884 
885  int lid=0;
886 
887  li_state_qgs = staLIDVec[lid++];
888  li_state_qgd = staLIDVec[lid++];
889  li_state_qgb = staLIDVec[lid++];
890 
891  li_state_capgs = staLIDVec[lid++];
892  li_state_capgd = staLIDVec[lid++];
893  li_state_capgb = staLIDVec[lid++];
894 
895  li_state_qbd = staLIDVec[lid++];
896  li_state_qbs = staLIDVec[lid++];
897 
898 
899 #ifdef Xyce_DEBUG_DEVICE
900  if (getDeviceOptions().debugLevel > 0)
901  {
902  Xyce::dout() << " State local indices:" << std::endl;
903  Xyce::dout() << std::endl;
904  Xyce::dout() << " li_state_qgs = " << li_state_qgs ;
905  Xyce::dout() << " li_state_capgs = " << li_state_capgs;
906  Xyce::dout() << " li_state_capgd = " << li_state_capgd;
907  Xyce::dout() << " li_state_capgb = " << li_state_capgb;
908  Xyce::dout() << " li_state_qgd = " << li_state_qgd;
909  Xyce::dout() << " li_state_qgb = " << li_state_qgb;
910  Xyce::dout() << " li_state_qbs = " << li_state_qbs;
911  Xyce::dout() << " li_state_qbd = " << li_state_qbd;
912  Xyce::dout() << std::endl;
913  Xyce::dout() << section_divider << std::endl;
914  }
915 #endif
916 }
917 
918 //-----------------------------------------------------------------------------
919 // Function : Instance::registerStoreLIDs
920 // Purpose :
921 // Special Notes :
922 // Scope : public
923 // Creator : Eric Keiter, SNL
924 // Creation Date : 12/11/11
925 //-----------------------------------------------------------------------------
926 void Instance::registerStoreLIDs( const std::vector<int> & stoLIDVecRef )
927 {
928  AssertLIDs(stoLIDVecRef.size() == getNumStoreVars());
929 
930  // Copy over the global ID lists:
931  stoLIDVec = stoLIDVecRef;
932 
933  int lid=0;
934  li_store_vbd = stoLIDVec[lid++];
935  li_store_vbs = stoLIDVec[lid++];
936  li_store_vgs = stoLIDVec[lid++];
937  li_store_vds = stoLIDVec[lid++];
938  li_store_von = stoLIDVec[lid++];
939 
940  if( loadLeadCurrent )
941  {
942  li_store_dev_id = stoLIDVec[lid++];
943  li_store_dev_ig = stoLIDVec[lid++];
944  li_store_dev_is = stoLIDVec[lid++];
945  li_store_dev_ib = stoLIDVec[lid++];
946  }
947 }
948 
949 //-----------------------------------------------------------------------------
950 // Function : Instance::jacobianStamp
951 // Purpose :
952 // Special Notes :
953 // Scope : public
954 // Creator : Robert Hoekstra, Computational Sciences
955 // Creation Date : 9/3/02
956 //-----------------------------------------------------------------------------
957 const std::vector< std::vector<int> > & Instance::jacobianStamp() const
958 {
959  if( drainConductance != 0.0 && sourceConductance != 0.0 )
960  return jacStamp_DC_SC;
961  else if( drainConductance != 0.0 && sourceConductance == 0.0 )
962  return jacStamp_DC;
963  else if( drainConductance == 0.0 && sourceConductance != 0.0 )
964  return jacStamp_SC;
965 
966  return jacStamp;
967 }
968 
969 //-----------------------------------------------------------------------------
970 // Function : Instance::registerJacLIDs
971 // Purpose :
972 // Special Notes :
973 // Scope : public
974 // Creator : Robert Hoekstra, Computational Sciences
975 // Creation Date : 9/3/02
976 //-----------------------------------------------------------------------------
977 void Instance::registerJacLIDs( const std::vector< std::vector<int> > & jacLIDVec )
978 {
979  DeviceInstance::registerJacLIDs( jacLIDVec );
980  std::vector<int> map;
981  std::vector< std::vector<int> > map2;
982 
983  if (drainConductance != 0.0)
984  {
985  if (sourceConductance != 0.0)
986  {
987  map = jacMap_DC_SC;
988  map2 = jacMap2_DC_SC;
989  }
990  else
991  {
992  map = jacMap_DC;
993  map2 = jacMap2_DC;
994  }
995  }
996  else
997  {
998  if (sourceConductance != 0.0)
999  {
1000  map = jacMap_SC;
1001  map2 = jacMap2_SC;
1002  }
1003  else
1004  {
1005  map = jacMap;
1006  map2 = jacMap2;
1007  }
1008  }
1009  ADrainEquDrainNodeOffset = jacLIDVec[map[0]][map2[0][0]];
1010  ADrainEquDrainPrimeNodeOffset = jacLIDVec[map[0]][map2[0][1]];
1011 
1012  AGateEquGateNodeOffset = jacLIDVec[map[1]][map2[1][0]];
1013  AGateEquBulkNodeOffset = jacLIDVec[map[1]][map2[1][1]];
1014  AGateEquDrainPrimeNodeOffset = jacLIDVec[map[1]][map2[1][2]];
1015  AGateEquSourcePrimeNodeOffset = jacLIDVec[map[1]][map2[1][3]];
1016 
1017  ASourceEquSourceNodeOffset = jacLIDVec[map[2]][map2[2][0]];
1018  ASourceEquSourcePrimeNodeOffset = jacLIDVec[map[2]][map2[2][1]];
1019 
1020  ABulkEquGateNodeOffset = jacLIDVec[map[3]][map2[3][0]];
1021  ABulkEquBulkNodeOffset = jacLIDVec[map[3]][map2[3][1]];
1022  ABulkEquDrainPrimeNodeOffset = jacLIDVec[map[3]][map2[3][2]];
1023  ABulkEquSourcePrimeNodeOffset = jacLIDVec[map[3]][map2[3][3]];
1024 
1025  ADrainPrimeEquDrainNodeOffset = jacLIDVec[map[4]][map2[4][0]];
1026  ADrainPrimeEquGateNodeOffset = jacLIDVec[map[4]][map2[4][1]];
1027  ADrainPrimeEquBulkNodeOffset = jacLIDVec[map[4]][map2[4][2]];
1028  ADrainPrimeEquDrainPrimeNodeOffset = jacLIDVec[map[4]][map2[4][3]];
1029  ADrainPrimeEquSourcePrimeNodeOffset = jacLIDVec[map[4]][map2[4][4]];
1030 
1031  ASourcePrimeEquGateNodeOffset = jacLIDVec[map[5]][map2[5][0]];
1032  ASourcePrimeEquSourceNodeOffset = jacLIDVec[map[5]][map2[5][1]];
1033  ASourcePrimeEquBulkNodeOffset = jacLIDVec[map[5]][map2[5][2]];
1034  ASourcePrimeEquDrainPrimeNodeOffset = jacLIDVec[map[5]][map2[5][3]];
1035  ASourcePrimeEquSourcePrimeNodeOffset = jacLIDVec[map[5]][map2[5][4]];
1036 }
1037 
1038 //-----------------------------------------------------------------------------
1039 // Function : Instance::setupPointers
1040 // Purpose :
1041 // Special Notes :
1042 // Scope : public
1043 // Creator : Eric Keiter, SNL
1044 // Creation Date : 12/06/08
1045 //-----------------------------------------------------------------------------
1047 {
1048 #ifndef Xyce_NONPOINTER_MATRIX_LOAD
1049  N_LAS_Matrix & dFdx = *(extData.dFdxMatrixPtr);
1050  N_LAS_Matrix & dQdx = *(extData.dQdxMatrixPtr);
1051 
1052  // F-pointers:
1055 
1060 
1063 
1068 
1074 
1080 
1081  // Q-pointers:
1084 
1089 
1092 
1097 
1103 
1109 #endif
1110 }
1111 
1112 //-----------------------------------------------------------------------------
1113 // Function : Instance::loadDAEQVector
1114 //
1115 // Purpose : Loads the Q-vector contributions for a single
1116 // diode instance.
1117 //
1118 // Special Notes : The "Q" vector is part of a standard DAE formalism in
1119 // which the system of equations is represented as:
1120 //
1121 // f(x) = dQ(x)/dt + F(x) - B(t) = 0
1122 //
1123 // This is similar to the loadRHS function, only this function
1124 // only loads capacitor charges, and loads them into the daeQ vector.
1125 //
1126 // Scope : public
1127 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1128 // Creation Date : 03/06/04
1129 //-----------------------------------------------------------------------------
1131 {
1132  double * qVec = extData.daeQVectorRawPtr;
1133  double coef(0.0);
1134 
1135  double Qeqbs(0.0),Qeqbd(0.0),Qeqgb(0.0), Qeqgs(0.0), Qeqgd(0.0);
1136  //double ceqbs,ceqbd,ceqgb, ceqgs, ceqgd; // 3f5 vars
1137  int Dtype=model_.dtype;
1138 
1139  // do the same Dtype corrections on the charges that
1140  // are performed on the currents in the loadRHS function.
1141 
1142  // What is cbs and cbd? They are diode currents (from exponentials),
1143  // so they are left out of this function.
1144  Qeqbs = Dtype*(qbs);
1145  Qeqbd = Dtype*(qbd);
1146  // These need "Dtype" here because we use them later *without*
1147  // Dtype, where SPICE uses it *with*
1148  Qeqgb = Dtype*(qgb);
1149  Qeqgs = Dtype*(qgs);
1150  Qeqgd = Dtype*(qgd);
1151 
1152  // 2 KCL for gate node
1153  coef = (Qeqgs+Qeqgd+Qeqgb);
1154  qVec[li_Gate] += coef*numberParallel;
1155 
1156  // 4 KCL for bulk node
1157  coef = Qeqbs + Qeqbd - Qeqgb;
1158  qVec[li_Bulk] += coef*numberParallel;
1159 
1160  // 5 KCL for drain' node
1161  coef = -(Qeqbd + Qeqgd);
1162  qVec[li_DrainPrime] += coef*numberParallel;
1163 
1164  // 6 KCL for source' node
1165  coef = -(Qeqbs + Qeqgs);
1166  qVec[li_SourcePrime] += coef*numberParallel;
1167 
1168  if( loadLeadCurrent )
1169  {
1170  double * storeLeadQ = extData.storeLeadCurrQCompRawPtr;
1171  storeLeadQ[li_store_dev_id] = (-(Qeqbd + Qeqgd))*numberParallel;
1172  storeLeadQ[li_store_dev_is] = (-(Qeqbs + Qeqgs))*numberParallel;
1173  storeLeadQ[li_store_dev_ig] = (Qeqgs+Qeqgd+Qeqgb)*numberParallel;
1174  storeLeadQ[li_store_dev_ib] = (Qeqbs + Qeqbd - Qeqgb)*numberParallel;
1175  }
1176 
1177  // Same as for the loadRHS function, but with capacitive terms:
1178  // gcgd = Capgd;
1179  // gcgs = Capgs;
1180  // gcgb = Capgb;
1181  // gcbs = capbs;
1182  // gcbd = capbd;
1183  if(!origFlag)
1184  {
1185  // The setup of gcgd, etc. is the same as in the loadDAEdQdxVector
1186  // function.
1187  double gcgd, gcgs, gcgb, gcbs, gcbd;
1189  {
1190  gcgd = Capgd;
1191  gcgs = Capgs;
1192  gcgb = Capgb;
1193  // get at the two parasitic caps the same way
1194  gcbs = capbs;
1195  gcbd = capbd;
1196  }
1197  else
1198  {
1199  gcgd = 0.0; gcgs = 0.0; gcgb = 0.0; gcbs = 0.0; gcbd = 0.0;
1200  }
1201 
1202  // KCL 2
1203  double coef_Jdxp2 = Dtype*(gcgd*(vgd-vgd_orig)+gcgs*(vgs-vgs_orig)+
1204  gcgb*(vgs-vgs_orig-vbs+vbs_orig));
1205 
1206  // 4 KCL for bulk node
1207  double coef_Jdxp4 = Dtype*(
1208  - (gcgb)*(vgs-vgs_orig-vbs+vbs_orig)
1209  + (gcgb)*(vbd-vbd_orig)
1210  + (gcbs)*(vbs-vbs_orig));
1211 
1212  // 5 KCL for drain' node
1213  double coef_Jdxp5 = Dtype*(
1214  -(gcgd)*(vgd-vgd_orig)
1215  -(gcbd)*(vbd-vbd_orig));
1216 
1217  // 6 KCL for source' node
1218  double coef_Jdxp6 = Dtype*(-gcgs*(vgs-vgs_orig)-(gcbs)*(vbs-vbs_orig));
1219 
1220  double * dQdxdVp = extData.dQdxdVpVectorRawPtr;
1221  dQdxdVp[li_Gate ] += coef_Jdxp2*numberParallel;
1222  dQdxdVp[li_Bulk ] += coef_Jdxp4*numberParallel;
1223  dQdxdVp[li_DrainPrime ] += coef_Jdxp5*numberParallel;
1224  dQdxdVp[li_SourcePrime] += coef_Jdxp6*numberParallel;
1225  }
1226 
1227  return true;
1228 }
1229 
1230 //-----------------------------------------------------------------------------
1231 // Function : Instance::loadDAEFVector
1232 //
1233 // Purpose : Loads the F-vector contributions for a single
1234 // diode instance.
1235 //
1236 // Special Notes : See the special notes for loadDAEFVector.
1237 //
1238 // Scope : public
1239 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1240 // Creation Date : 03/06/04
1241 //-----------------------------------------------------------------------------
1243 {
1244  double * fVec = extData.daeFVectorRawPtr;
1245  double coef(0.0);
1246  double ceqbs(0.0),ceqbd(0.0),ceqgb(0.0), ceqgs(0.0), ceqgd(0.0); // 3f5 vars
1247  double gmin1 = getDeviceOptions().gmin;
1248 
1249  int Dtype=model_.dtype;
1250 
1251  // The next few lines are the same as for loadRHS, except
1252  // the capcitor current terms have been set to zero here.
1253  ceqbs = Dtype*(cbs);
1254  ceqbd = Dtype*(cbd);
1255  // These need "Dtype" here because we use them later *without*
1256  // Dtype, where SPICE uses it *with*
1257  ceqgb = 0.0;
1258  ceqgs = 0.0;
1259  ceqgd = 0.0;
1260 
1261  // 1 KCL for drain node
1262  if (drainConductance != 0.0)
1263  {
1264  coef = Idrain;
1265  fVec[li_Drain] += coef*numberParallel;
1266  }
1267 
1268  // 2 KCL for gate node
1269  coef = (ceqgs+ceqgd+ceqgb);
1270  fVec[li_Gate] += coef*numberParallel;
1271 
1272  // 3 KCL for source node
1273  if (sourceConductance != 0.0)
1274  {
1275  coef = Isource;
1276  fVec[li_Source] += coef*numberParallel;
1277  }
1278 
1279  // 4 KCL for bulk node
1280  coef = ceqbs + ceqbd - ceqgb;
1281  fVec[li_Bulk] += coef*numberParallel;
1282 
1283  // 5 KCL for drain' node
1284  coef = -Idrain-(ceqbd - cdreq + ceqgd);
1285  fVec[li_DrainPrime] += coef*numberParallel;
1286 
1287  // 6 KCL for source' node
1288  coef = -Isource-(ceqbs + cdreq + ceqgs);
1289  fVec[li_SourcePrime] += coef*numberParallel;
1290 
1291  // Same as for the loadRHS function, but without capacitive terms:
1292  // gcgd = Capgd;
1293  // gcgs = Capgs;
1294  // gcgb = Capgb;
1295  // gcbs = capbs;
1296  // gcbd = capbd;
1297  if (!origFlag)
1298  {
1299  // 4 KCL for bulk node
1300  double coef_Jdxp4 = Dtype*(
1301  + ((gbd-gmin1))*(vbd-vbd_orig)
1302  + ((gbs-gmin1))*(vbs-vbs_orig));
1303 
1304  // 5 KCL for drain' node
1305  double coef_Jdxp5 = Dtype*(
1306  -((gbd-gmin1))*(vbd-vbd_orig)
1307  +gds*(vds-vds_orig)
1308  +Gm*((mode>0)?(vgs-vgs_orig):(vgd-vgd_orig))
1309  +Gmbs*((mode>0)?(vbs-vbs_orig):(vbd-vbd_orig)));
1310 
1311  // 6 KCL for source' node
1312  double coef_Jdxp6 = Dtype*(
1313  -((gbs-gmin1))*(vbs-vbs_orig)
1314  -gds*(vds-vds_orig)
1315  -Gm*((mode>0)?(vgs-vgs_orig):(vgd-vgd_orig))
1316  -Gmbs*((mode>0)?(vbs-vbs_orig):(vbd-vbd_orig)));
1317 
1318  double * dFdxdVp = extData.dFdxdVpVectorRawPtr;
1319  dFdxdVp[li_Bulk ] += coef_Jdxp4*numberParallel;
1320  dFdxdVp[li_DrainPrime ] += coef_Jdxp5*numberParallel;
1321  dFdxdVp[li_SourcePrime] += coef_Jdxp6*numberParallel;
1322  }
1323 
1324  if( loadLeadCurrent )
1325  {
1326  double * storeLeadF = extData.nextStoVectorRawPtr;
1327  storeLeadF[li_store_dev_id] = (-(ceqbd - cdreq + ceqgd))*numberParallel;
1328  storeLeadF[li_store_dev_is] = (-(ceqbs + cdreq + ceqgs))*numberParallel;
1329  storeLeadF[li_store_dev_ig] = (ceqgs+ceqgd+ceqgb)*numberParallel;
1330  storeLeadF[li_store_dev_ib] = (ceqbs + ceqbd - ceqgb)*numberParallel;
1331  }
1332 
1333  return true;
1334 }
1335 
1336 //-----------------------------------------------------------------------------
1337 // Function : Instance::loadDAEdQdx
1338 //
1339 // Purpose : Loads the Q-vector contributions for a single
1340 // diode instance.
1341 //
1342 // Special Notes : The "Q" vector is part of a standard DAE formalism in
1343 // which the system of equations is represented as:
1344 //
1345 // f(x) = dQ(x)/dt + F(x) - B(t) = 0
1346 //
1347 // Scope : public
1348 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1349 // Creation Date : 03/06/04
1350 //-----------------------------------------------------------------------------
1352 {
1353  N_LAS_Matrix & dQdx = *(extData.dQdxMatrixPtr);
1354 
1355  double gcgd(0.0); // d(cqgd)/dVgd
1356  double gcgs(0.0); // d(cqgs)/dVgs
1357  double gcgb(0.0); // d(cqgb)/dVgb
1358  double gcbs(0.0); // d(cqbs)/dVbs
1359  double gcbd(0.0); // d(cqbd)/dVbd
1360 
1361  // get at the "conductances" for the gate capacitors with this trick
1362  // gcgd = model_.dtype*Capgd;
1363  // gcgs = model_.dtype*Capgs;
1364  // gcgb = model_.dtype*Capgb;
1365  //
1366  // In the loadRHS function, these would all be multiplied by
1367  // getSolverState().pdt. Here, for dQdx, the pdt term is left out.
1368  if (getSolverState().tranopFlag || getSolverState().acopFlag || getSolverState().transientFlag)
1369  {
1370  gcgd = Capgd;
1371  gcgs = Capgs;
1372  gcgb = Capgb;
1373  // get at the two parasitic caps the same way
1374  gcbs = capbs;
1375  gcbd = capbd;
1376  }
1377 
1378  dQdx[li_Gate][AGateEquGateNodeOffset] += (gcgd+gcgs+gcgb)
1379  *numberParallel;
1383 
1385  dQdx[li_Bulk][ABulkEquBulkNodeOffset] += +(gcbs+gcbd+gcgb)
1386  *numberParallel;
1389  +gcbs*numberParallel;
1390 
1392  -gcgd*numberParallel;
1394  -gcbd*numberParallel;
1396  +(gcbd+gcgd)*numberParallel;
1397 
1399  gcgs*numberParallel;
1401  +gcbs*numberParallel;
1403  +(gcbs+gcgs)*numberParallel;
1404 
1405  return true;
1406 }
1407 
1408 //-----------------------------------------------------------------------------
1409 // Function : Instance::loadDAEdFdx ()
1410 //
1411 // Purpose : Loads the F-vector contributions for a single
1412 // diode instance.
1413 //
1414 // Special Notes :
1415 //
1416 // Scope : public
1417 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1418 // Creation Date : 03/06/04
1419 //-----------------------------------------------------------------------------
1421 {
1422  N_LAS_Matrix & dFdx = *(extData.dFdxMatrixPtr);
1423 
1428 
1433 
1435  (gbs+gbd)*numberParallel;
1438 
1444  (-gbd+Gmbs)*numberParallel;
1446  (drainConductance+gds+gbd+revsum)*numberParallel;
1448  (-gds-nrmsum)*numberParallel;
1449 
1455  (gbs+Gmbs)*numberParallel;
1457  (gds+revsum)*numberParallel;
1459  (sourceConductance+gds+gbs+nrmsum)*numberParallel;
1460 
1461  return true;
1462 }
1463 
1464 //-----------------------------------------------------------------------------
1465 // Function : Instance::updateIntermediateVars
1466 // Purpose :
1467 // Special Notes :
1468 // Scope : public
1469 // Creator : Tom Russo
1470 // Creation Date : 03/01/01
1471 //-----------------------------------------------------------------------------
1473 {
1474  bool bsuccess = true;
1475  // 3f5 likes to use the same variable names in local variables and in
1476  // structures. Messes with us! Define some local versions with capitals
1477  // instead
1478  double Von;
1479  double Vdsat;
1480  double Beta;
1481  //
1482  double evbs;
1483  double evbd;
1484  double sarg;
1485  double sargsw;
1486  // double vgs1;
1487  // double vgd1;
1488  // double vgb1;
1489  double arg;
1490  int Check = 1;
1491 
1492  double capgs_old;
1493  double capgd_old;
1494  double capgb_old;
1495 
1496  // temporary storage for vgs/vgd/vds so that homotopy doesn't impact
1497  // voltage limiting "jdxp" terms
1498 
1499  double vgs_save;
1500  double vgd_save;
1501  double vds_save;
1502 
1503  // This is one of the vars that are set up at the top of mos3load that
1504  // should *not* be moved to the instance constructor! tTransconductance
1505  // is set by updateTemperature. Perhaps I should remove it from the
1506  // instance variables, too, since now it's pretty much a local thing.
1507  // same goes for the other things that depend on the t* variables!
1508 
1509  if( (tSatCurDens == 0) || (drainArea == 0) || (sourceArea == 0))
1510  {
1511  DrainSatCur = tSatCur;
1513  }
1514  else
1515  {
1518  }
1520 
1521  // don't do this anymore, use the one from the manager
1522  // newtonIter = nlsMgrPtr->getNonLinearIter ();
1523 
1524  // we need our solution variables for any of this stuff
1525 
1532 
1533  // now we need voltage drops
1534  Vddp = Vd - Vdp;
1535  Vssp = Vs - Vsp;
1536  Vbsp = Vb - Vsp;
1537  Vbdp = Vb - Vdp;
1538  Vgsp = Vg - Vsp;
1539  Vgdp = Vg - Vdp;
1540  Vgb = Vg - Vb;
1541  Vdpsp = Vdp - Vsp;
1542 
1543  // Now the things that the 3f5 code really uses (from mos3load's
1544  // "general iteration" part at lines 276-295
1545  vbs = model_.dtype * Vbsp;
1546  vgs = model_.dtype * Vgsp;
1547  vds = model_.dtype * Vdpsp;
1548 
1549  vbd = vbs-vds;
1550  vgd = vgs-vds;
1551 
1552  origFlag = 1;
1553  limitedFlag=false;
1554  vgs_orig = vgs;
1555  vds_orig = vds;
1556  vbs_orig = vbs;
1557  vbd_orig = vbd;
1558  vgd_orig = vgd;
1559 
1560  if (getSolverState().initJctFlag && !OFF && getDeviceOptions().voltageLimiterFlag)
1561  {
1562  if (IC_GIVEN)
1563  {
1564  vds = model_.dtype*icVDS;
1565  vgs = model_.dtype*icVGS;
1566  vbs = model_.dtype*icVBS;
1567  vbd = vbs - vds;
1568  vgd = vgs - vds;
1569  origFlag = false;
1570  }
1571  else
1572  {
1573  if (getSolverState().inputOPFlag)
1574  {
1575  N_LAS_Vector * flagSolVectorPtr = extData.flagSolVectorPtr;
1576  if ((*flagSolVectorPtr)[li_Drain] == 0 || (*flagSolVectorPtr)[li_Gate] == 0 ||
1577  (*flagSolVectorPtr)[li_Source] == 0 || (*flagSolVectorPtr)[li_SourcePrime] ||
1578  (*flagSolVectorPtr)[li_DrainPrime] || (*flagSolVectorPtr)[li_Bulk] )
1579  {
1580  vbs = -1;
1581  vgs = model_.dtype*tVto;
1582  vds = 0;
1583  vbd = vbs-vds;
1584  vgd = vgs-vds;
1585  }
1586  }
1587  else
1588  {
1589  vbs = -1;
1590  vgs = model_.dtype*tVto;
1591  vds = 0;
1592  vbd = vbs-vds;
1593  vgd = vgs-vds;
1594  }
1595  }
1596  }
1597  else if ((getSolverState().initFixFlag || getSolverState().initJctFlag) && OFF)
1598  {
1599  vbs = vgs = vds = 0;
1600  vbd = vgd = 0;
1601  }
1602 
1603  if (getSolverState().newtonIter == 0)
1604  {
1605 
1606  if (!(getSolverState().dcopFlag)||(getSolverState().locaEnabledFlag && getSolverState().dcopFlag))
1607  {
1612  Von = model_.dtype *
1614  }
1615  else
1616  { // otherwise there is no history
1617  vbs_old = vbs;
1618  vbd_old = vbd;
1619  vgs_old = vgs;
1620  vds_old = vds;
1621  Von = 0.0;
1622  }
1624  }
1625  else
1626  {
1631  Von = model_.dtype *
1634  }
1635 
1636  ////////////////////////////////////////////
1637  // SPICE-type Voltage Limiting
1638  ////////////////////////////////////////////
1640  {
1641  // Do not do limiting if mode initfix and OFF:
1642  if (! (getSolverState().initFixFlag && OFF))
1643  {
1644  if (vds_old >= 0)
1645  {
1646  vgs = devSupport.fetlim( vgs, vgs_old, Von);
1647  vds = vgs - vgd;
1648  vds = devSupport.limvds( vds, vds_old);
1649  vgd = vgs - vds;
1650  }
1651  else
1652  {
1653  vgd = devSupport.fetlim( vgd, vgd_old, Von);
1654  vds = vgs - vgd;
1655  vds = -devSupport.limvds( -vds, -vds_old );
1656  vgs = vgd + vds;
1657  }
1658 
1659  if (vds >= 0.0)
1660  {
1661  vbs = devSupport.pnjlim( vbs, vbs_old, vt, sourceVcrit, &Check);
1662  vbd = vbs - vds;
1663  }
1664  else
1665  {
1666  vbd = devSupport.pnjlim( vbd, vbd_old, vt, drainVcrit, &Check);
1667  vbs = vbd + vds;
1668  }
1669 
1670  // for convergence:
1671  if (Check == 1) limitedFlag=true;
1672 
1673  }
1674  }
1675 
1676  ////
1677  // now all the preliminaries are over - we can start doing the
1678  // real work
1679  ////
1680  vbd = vbs - vds;
1681  vgd = vgs - vds;
1682  Vgb = vgs - vbs;
1683 
1684  // Now set the origFlag
1685  if (vgs_orig != vgs || vds_orig != vds ||
1686  vbs_orig != vbs || vbd_orig != vbd || vgd_orig != vgd) origFlag = 0;
1687 
1688 
1689  ////
1690  // bulk-source and bulk-drain diodes
1691  // here we just evaluate the ideal diode current and the
1692  // corresponding derivative (conductance).
1693  ////
1694  if(vbs <= 0)
1695  {
1696  gbs = SourceSatCur/vt;
1697  gbs += getDeviceOptions().gmin;
1698  cbs = gbs*vbs;
1699  }
1700  else
1701  {
1702  evbs = exp(Xycemin(CONSTMAX_EXP_ARG,vbs/vt));
1703  gbs = (SourceSatCur*evbs/vt + getDeviceOptions().gmin);
1704  cbs = (SourceSatCur * (evbs-1) + getDeviceOptions().gmin*vbs);
1705  }
1706  if(vbd <= 0)
1707  {
1708  gbd = DrainSatCur/vt;
1709  gbd += getDeviceOptions().gmin;
1710  cbd = gbd *vbd;
1711  }
1712  else
1713  {
1714  evbd = exp(Xycemin(CONSTMAX_EXP_ARG,vbd/vt));
1715  gbd = (DrainSatCur*evbd/vt + getDeviceOptions().gmin);
1716  cbd = (DrainSatCur *(evbd-1) + getDeviceOptions().gmin*vbd);
1717  }
1718 
1719  // 3f5 does this simple stuff
1720  if (vds >= 0)
1721  mode = 1;
1722  else
1723  mode = -1;
1724 
1725  {
1726  // here 3f5 seems to have inserted a c-translation of a fortran routine
1727  // Sadly, there are GOTO's and labeled statements all over this thing.
1728  // I'll do what I can to eliminate them all, but I'll start by
1729  // leaving it VERBATIM and ugly
1730  //
1731  // evaluate the drain current, its derivatives and the
1732  // charges associated with the gate, channel and bulk for mosfets based on
1733  // semi-empirical equations
1734 
1735  ////
1736  // * subroutine moseq3(vds,vbs,vgs,gm,gds,gmbs,
1737  // * qg,qc,qb,cggb,cgdb,cgsb,cbgb,cbdb,cbsb)
1738  ////
1739 
1740  ////
1741  // * this routine evaluates the drain current, its derivatives and
1742  // * the charges associated with the gate, channel and bulk
1743  // * for mosfets based on semi-empirical equations
1744  ////
1745 
1746  //
1747  // common /mosarg/ vto,beta,gamma,phi,phib,cox,xnsub,xnfs,xd,xj,xld,
1748  // 1 xlamda,uo,uexp,vbp,utra,vmax,xneff,xl,xw,vbi,von,vdsat,qspof,
1749  // 2 beta0,beta1,cdrain,xqco,xqc,fnarrw,fshort,lev
1750  // common /status/ omega,time,delta,delold(7),ag(7),vt,xni,egfet,
1751  // 1 xmu,sfactr,mode,modedc,icalc,initf,method,iord,maxord,noncon,
1752  // 2 iterno,itemno,nosolv,modac,ipiv,ivmflg,ipostp,iscrch,iofile
1753  // common /knstnt/ twopi,xlog2,xlog10,root2,rad,boltz,charge,ctok,
1754  // 1 gmin,reltol,abstol,vntol,trtol,chgtol,eps0,epssil,epsox,
1755  // 2 pivtol,pivrel
1756  //
1757 
1758  // // equivalence (xlamda,alpha),(vbp,theta),(uexp,eta),(utra,xkappa)
1759 
1760  double coeff0 = 0.0631353e0;
1761  double coeff1 = 0.8013292e0;
1762  double coeff2 = -0.01110777e0;
1763  double oneoverxl; // 1/effective length
1764  double eta; // eta from model after length factor */
1765  double phibs; // phi - vbs */
1766  double sqphbs; // square root of phibs */
1767  double dsqdvb; // */
1768  double sqphis; // square root of phi */
1769  double sqphs3; // square root of phi cubed */
1770  double wps;
1771  double oneoverxj; // 1/junction depth */
1772  double xjonxl; // junction depth/effective length */
1773  double djonxj;
1774  double wponxj;
1775  double arga;
1776  double argb;
1777  double argc;
1778  double dwpdvb;
1779  double dadvb;
1780  double dbdvb;
1781  double gammas;
1782  double fbodys;
1783  double fbody;
1784  double onfbdy;
1785  double qbonco;
1786  double vbix;
1787  double wconxj;
1788  double dfsdvb;
1789  double dfbdvb;
1790  double dqbdvb;
1791  double vth;
1792  double dvtdvb;
1793  double csonco;
1794  double cdonco;
1795  double dxndvb;
1796  double dvodvb;
1797  double dvodvd;
1798  double vgsx;
1799  double dvtdvd;
1800  double onfg;
1801  double fgate;
1802  double us;
1803  double dfgdvg;
1804  double dfgdvd;
1805  double dfgdvb;
1806  double dvsdvg;
1807  double dvsdvb;
1808  double dvsdvd;
1809  double xn;
1810  double vdsc;
1811  double onvdsc;
1812  double dvsdga;
1813  double vdsx;
1814  double dcodvb;
1815  double cdnorm;
1816  double cdo;
1817  double cd1;
1818  double fdrain;
1819  double fd2;
1820  double dfddvg;
1821  double dfddvb;
1822  double dfddvd;
1823  double gdsat;
1824  double cdsat;
1825  double gdoncd;
1826  double gdonfd;
1827  double gdonfg;
1828  double dgdvg;
1829  double dgdvd;
1830  double dgdvb;
1831  double emax;
1832  double emongd;
1833  double demdvg;
1834  double demdvd;
1835  double demdvb;
1836  double delxl;
1837  double dldvd;
1838  double dldem;
1839  double ddldvg;
1840  double ddldvd;
1841  double ddldvb;
1842  double dlonxl;
1843  double xlfact;
1844  double diddl;
1845  double gds0;
1846  double emoncd;
1847  double ondvt;
1848  double onxn;
1849  double wfact;
1850  double gms;
1851  double gmw;
1852  double fshort;
1853 
1854 
1855  // Begin block of mosfet continuation code.
1856  // This idea is based, loosely, on a paper by Jaijeet
1857  // Roychowdhury.
1858 #ifdef Xyce_DEBUG_DEVICE
1860  {
1861  Xyce::dout() << "HOMOTOPY INFO: gainscale = "
1862  << getSolverState().gainScale[blockHomotopyID] << std::endl;
1863  Xyce::dout() << "HOMOTOPY INFO: before vds = " << vds << std::endl;
1864  Xyce::dout() << "HOMOTOPY INFO: before vgs = " << vgs << std::endl;
1865  }
1866 #endif
1867 
1868  // Save these before allowing homotopy to tweak them. It
1869  // is important to restore them before moving on to
1870  // calculate RHS, because then the Jdxp terms will attempt to force
1871  // the external circuit to make these voltage drops the real thing!
1872  vds_save=vds;
1873  vgs_save=vgs;
1874  vgd_save=vgd;
1875 
1876  if (getSolverState().artParameterFlag)
1877  {
1878  double alpha = getSolverState().gainScale[blockHomotopyID];
1879  if (getDeviceOptions().staggerGainScale)
1880  {
1881  alpha *= (0.3 * randomPerturb + 1.0);
1882  if (alpha > 1.0)
1883  {
1884  alpha = 1.0;
1885  }
1886  }
1887  double vgstConst = getDeviceOptions().vgstConst;
1888  if (getDeviceOptions().randomizeVgstConst)
1889  {
1890  vgstConst *= randomPerturb;
1891  }
1892 
1893  vds = devSupport.contVds (vds, getSolverState().nltermScale, getDeviceOptions().vdsScaleMin);
1894 
1895  if (mode==1)
1896  {
1897  vgs = devSupport.contVgst (vgs, alpha, vgstConst);
1898  }
1899  else
1900  {
1901  vgd = devSupport.contVgst (vgd, alpha, vgstConst);
1902  }
1903  }
1904 
1905 #ifdef Xyce_DEBUG_DEVICE
1906  if (getDeviceOptions().debugLevel > 0 && getSolverState().debugTimeFlag)
1907  {
1908  Xyce::dout() << "HOMOTOPY INFO: after vds = " << vds << std::endl;
1909  Xyce::dout() << "HOMOTOPY INFO: after vgs = " << vgs << std::endl;
1910  }
1911 #endif
1912  // End of block of mosfet continuation code.
1913 
1914  ////
1915  // bypasses the computation of charges
1916  ////
1917 
1918  ////
1919  // reference cdrain equations to source and
1920  // charge equations to bulk
1921  ////
1922  Vdsat = 0.0;
1923  oneoverxl = 1.0/EffectiveLength;
1924 
1925  // TVR: Massobrio and Antognetti call this "sigma"
1926  eta = model_.eta * 8.15e-22/(model_.oxideCapFactor*
1928  ////
1929  //.....square root term
1930  ////
1931  if ( (mode==1?vbs:vbd) <= 0.0 )
1932  {
1933  if (tPhi > 0)
1934  sqphis = sqrt(tPhi);
1935  else
1936  sqphis = 0;
1937  sqphs3 = tPhi*sqphis;
1938  phibs = tPhi-(mode==1?vbs:vbd);
1939  sqphbs = sqrt(phibs);
1940  dsqdvb = -0.5/sqphbs;
1941  }
1942  else
1943  {
1944  sqphis = sqrt(tPhi);
1945  sqphs3 = tPhi*sqphis;
1946  sqphbs = sqphis/(1.0+(mode==1?vbs:vbd)/
1947  (tPhi+tPhi));
1948  phibs = sqphbs*sqphbs;
1949  dsqdvb = -phibs/(sqphs3+sqphs3);
1950  }
1951  ////
1952  //.....short channel effect factor
1953  ////
1954  if ( (model_.junctionDepth != 0.0) &&
1955  (model_.coeffDepLayWidth != 0.0) )
1956  {
1957  wps = model_.coeffDepLayWidth*sqphbs;
1958  oneoverxj = 1.0/model_.junctionDepth;
1959  xjonxl = model_.junctionDepth*oneoverxl;
1960  djonxj = model_.latDiff*oneoverxj;
1961  wponxj = wps*oneoverxj;
1962  wconxj = coeff0+coeff1*wponxj+coeff2*wponxj*wponxj;
1963  arga = wconxj+djonxj;
1964  argc = wponxj/(1.0+wponxj);
1965  argb = sqrt(1.0-argc*argc);
1966  fshort = 1.0-xjonxl*(arga*argb-djonxj);
1967  dwpdvb = model_.coeffDepLayWidth*dsqdvb;
1968  dadvb = (coeff1+coeff2*(wponxj+wponxj))*dwpdvb*oneoverxj;
1969  dbdvb = -argc*argc*(1.0-argc)*dwpdvb/(argb*wps);
1970  dfsdvb = -xjonxl*(dadvb*argb+arga*dbdvb);
1971  }
1972  else
1973  {
1974  fshort = 1.0;
1975  dfsdvb = 0.0;
1976  }
1977  ////
1978  //.....body effect
1979  //
1980  gammas = model_.gamma*fshort;
1981  fbodys = 0.5*gammas/(sqphbs+sqphbs);
1982  fbody = fbodys+model_.narrowFactor/w;
1983 
1984  onfbdy = 1.0/(1.0+fbody);
1985  dfbdvb = -fbodys*dsqdvb/sqphbs+fbodys*dfsdvb/fshort;
1986  qbonco =gammas*sqphbs+model_.narrowFactor*phibs/w;
1987  dqbdvb = gammas*dsqdvb+model_.gamma*dfsdvb*sqphbs-
1989  ////
1990  //.....static feedback effect
1991  //
1992  vbix = tVbi*model_.dtype-eta*(mode*vds);
1993  ////
1994  //.....threshold voltage
1995  //
1996  vth = vbix+qbonco;
1997  dvtdvd = -eta;
1998  dvtdvb = dqbdvb;
1999  ////
2000  //.....joint weak inversion and strong inversion
2001  //
2002  Von = vth;
2003 
2004  if ( model_.fastSurfaceStateDensity != 0.0 )
2005  {
2007  1e4 *EffectiveLength*w/OxideCap; // 1e4 to convert (cm**2/m**2)
2008  cdonco = qbonco/(phibs+phibs);
2009  xn = 1.0+csonco+cdonco;
2010  Von = vth+vt*xn;
2011  dxndvb = dqbdvb/(phibs+phibs)-qbonco*dsqdvb/(phibs*sqphbs);
2012  dvodvd = dvtdvd;
2013  dvodvb = dvtdvb+vt*dxndvb;
2014  }
2015  else
2016  {
2017  ////
2018  //.....cutoff region
2019  //
2020 
2021  if ( (mode==1?vgs:vgd) <= Von ) {
2022  cdrain = 0.0;
2023  gm = 0.0;
2024  gds = 0.0;
2025  gmbs = 0.0;
2026  goto innerline1000;
2027  }
2028  }
2029  ////
2030  // *.....device is on
2031  ////
2032 
2033  vgsx = Xycemax((mode==1?vgs:vgd),Von);
2034 
2035  ////
2036  //.....mobility modulation by gate voltage
2037  ////
2038  onfg = 1.0+model_.theta*(vgsx-vth);
2039  fgate = 1.0/onfg;
2040  us = tSurfMob * 1e-4 *fgate; // 1e4 to convert (m**2/cm**2)
2041  dfgdvg = -model_.theta*fgate*fgate;
2042  dfgdvd = -dfgdvg*dvtdvd;
2043  dfgdvb = -dfgdvg*dvtdvb;
2044 
2045  ////
2046  // *.....saturation voltage
2047  ////
2048  Vdsat = (vgsx-vth)*onfbdy;
2049 
2050  if ( model_.maxDriftVel <= 0.0 )
2051  {
2052  dvsdvg = onfbdy;
2053  dvsdvd = -dvsdvg*dvtdvd;
2054  dvsdvb = -dvsdvg*dvtdvb-Vdsat*dfbdvb*onfbdy;
2055  }
2056  else
2057  {
2059  onvdsc = 1.0/vdsc;
2060  arga = (vgsx-vth)*onfbdy;
2061  argb = sqrt(arga*arga+vdsc*vdsc);
2062  Vdsat = arga+vdsc-argb;
2063  dvsdga = (1.0-arga/argb)*onfbdy;
2064  dvsdvg = dvsdga-(1.0-vdsc/argb)*vdsc*dfgdvg*onfg;
2065  dvsdvd = -dvsdvg*dvtdvd;
2066  dvsdvb = -dvsdvg*dvtdvb-arga*dvsdga*dfbdvb;
2067  }
2068  ////
2069  // *.....current factors in linear region
2070  ////
2071  vdsx = Xycemin((mode*vds),Vdsat);
2072  if ( vdsx == 0.0 ) goto line900;
2073 
2074  cdo = vgsx-vth-0.5*(1.0+fbody)*vdsx;
2075  dcodvb = -dvtdvb-0.5*dfbdvb*vdsx;
2076 
2077  ////
2078  // *.....normalized drain current
2079  ////
2080  cdnorm = cdo*vdsx;
2081 
2082  gm = vdsx;
2083  gds = vgsx-vth-(1.0+fbody+dvtdvd)*vdsx;
2084  gmbs = dcodvb*vdsx;
2085  ////
2086  // *.....drain current without velocity saturation effect
2087  ////
2088  cd1 = Beta*cdnorm;
2089  Beta = Beta*fgate;
2090  cdrain = Beta*cdnorm;
2091  gm = Beta*gm+dfgdvg*cd1;
2092  gds = Beta*gds+dfgdvd*cd1;
2093  gmbs = Beta*gmbs;
2094 
2095  ////
2096  // *.....velocity saturation factor
2097  ////
2098  if ( model_.maxDriftVel != 0.0 )
2099  {
2100  fdrain = 1.0/(1.0+vdsx*onvdsc);
2101  fd2 = fdrain*fdrain;
2102  arga = fd2*vdsx*onvdsc*onfg;
2103  dfddvg = -dfgdvg*arga;
2104  dfddvd = -dfgdvd*arga-fd2*onvdsc;
2105  dfddvb = -dfgdvb*arga;
2106  ////
2107  // *.....drain current
2108  ////
2109  gm = fdrain*gm+dfddvg*cdrain;
2110  gds = fdrain*gds+dfddvd*cdrain;
2111  gmbs = fdrain*gmbs+dfddvb*cdrain;
2112  cdrain = fdrain*cdrain;
2113  Beta = Beta*fdrain;
2114  }
2115 
2116  ////
2117  // *.....channel length modulation
2118  ////
2119  if ( (mode*vds) <= Vdsat ) goto line700;
2120  if ( model_.maxDriftVel <= 0.0 ) goto line510;
2121  if (model_.alpha == 0.0) goto line700;
2122  cdsat = cdrain;
2123  gdsat = cdsat*(1.0-fdrain)*onvdsc;
2124  gdsat = Xycemax(1.0e-12,gdsat);
2125  gdoncd = gdsat/cdsat;
2126  gdonfd = gdsat/(1.0-fdrain);
2127  gdonfg = gdsat*onfg;
2128  dgdvg = gdoncd*gm-gdonfd*dfddvg+gdonfg*dfgdvg;
2129  dgdvd = gdoncd*gds-gdonfd*dfddvd+gdonfg*dfgdvd;
2130  dgdvb = gdoncd*gmbs-gdonfd*dfddvb+gdonfg*dfgdvb;
2131 
2132  // to have this condition make sense, the option BADMOS3 must be
2133  // recognized on the options line. A problem with the KAPPA parameter
2134  // was detected and fixed in 3f2. BADMOS3 enables the unfixed deal,
2135  // just in case parameter fitting is affected.
2136  // It has never been implemented in Xyce
2137  //#ifdef BADMOS3_IMPLEMENTED
2138  // if (ckt->CKTbadMos3)
2139  // emax = cdsat*oneoverxl/gdsat;
2140  // else
2141  //#endif
2142  emax = model_.kappa * cdsat*oneoverxl/gdsat;
2143  emoncd = emax/cdsat;
2144  emongd = emax/gdsat;
2145  demdvg = emoncd*gm-emongd*dgdvg;
2146  demdvd = emoncd*gds-emongd*dgdvd;
2147  demdvb = emoncd*gmbs-emongd*dgdvb;
2148 
2149  arga = 0.5*emax*model_.alpha;
2150  argc = model_.kappa*model_.alpha;
2151  argb = sqrt(arga*arga+argc*((mode*vds)-Vdsat));
2152  delxl = argb-arga;
2153  dldvd = argc/(argb+argb);
2154  dldem = 0.5*(arga/argb-1.0)*model_.alpha;
2155  ddldvg = dldem*demdvg;
2156  ddldvd = dldem*demdvd-dldvd;
2157  ddldvb = dldem*demdvb;
2158  goto line520;
2159  line510:
2160  delxl = sqrt(model_.kappa*((mode*vds)-Vdsat)*
2161  model_.alpha);
2162  dldvd = 0.5*delxl/((mode*vds)-Vdsat);
2163  ddldvg = 0.0;
2164  ddldvd = -dldvd;
2165  ddldvb = 0.0;
2166  ////
2167  // *.....punch through approximation
2168  ////
2169  line520:
2170  if ( delxl > (0.5*EffectiveLength) )
2171  {
2173  (4.0*delxl));
2174  arga = 4.0*(EffectiveLength-delxl)*(EffectiveLength-delxl)/
2176  ddldvg = ddldvg*arga;
2177  ddldvd = ddldvd*arga;
2178  ddldvb = ddldvb*arga;
2179  dldvd = dldvd*arga;
2180  }
2181  ////
2182  // *.....saturation region
2183  ////
2184  dlonxl = delxl*oneoverxl;
2185  xlfact = 1.0/(1.0-dlonxl);
2186  cdrain = cdrain*xlfact;
2187  diddl = cdrain/(EffectiveLength-delxl);
2188  gm = gm*xlfact+diddl*ddldvg;
2189  gds0 = gds*xlfact+diddl*ddldvd;
2190  gmbs = gmbs*xlfact+diddl*ddldvb;
2191  gm = gm+gds0*dvsdvg;
2192  gmbs = gmbs+gds0*dvsdvb;
2193  gds = gds0*dvsdvd+diddl*dldvd;
2194 
2195  ////
2196  // *.....finish strong inversion case
2197  ////
2198  line700:
2199  if ( (mode==1?vgs:vgd) < Von )
2200  {
2201  ////
2202  // *.....weak inversion
2203  ////
2204  onxn = 1.0/xn;
2205  ondvt = onxn/vt;
2206  wfact = exp( ((mode==1?vgs:vgd)-Von)*ondvt );
2207  cdrain = cdrain*wfact;
2208  gms = gm*wfact;
2209  gmw = cdrain*ondvt;
2210  gm = gmw;
2211 
2212  if ((mode*vds) > Vdsat)
2213  {
2214  gm = gm+gds0*dvsdvg*wfact;
2215  }
2216  gds = gds*wfact+(gms-gmw)*dvodvd;
2217  gmbs = gmbs*wfact+(gms-gmw)*dvodvb-gmw*
2218  ((mode==1?vgs:vgd)-Von)*onxn*dxndvb;
2219  }
2220  ////
2221  // *.....charge computation
2222  ////
2223  goto innerline1000;
2224  ////
2225  // *.....special case of vds = 0.0d0
2226  ////
2227  line900:
2228 
2229  Beta = Beta*fgate;
2230  cdrain = 0.0;
2231  gm = 0.0;
2232  gds = Beta*(vgsx-vth);
2233  gmbs = 0.0;
2234  if ( (model_.fastSurfaceStateDensity != 0.0) &&
2235  ((mode==1?vgs:vgd) < Von) )
2236  {
2237  gds *=exp(((mode==1?vgs:vgd)-Von)/(vt*xn));
2238  }
2239  innerline1000:;
2240  ////
2241  // *.....done
2242  ////
2243  // end of moseq3
2244  ////
2245  }
2246 
2247  // now deal with n vs p polarity
2248 
2249  von = model_.dtype * Von;
2250  vdsat = model_.dtype * Vdsat;
2251 
2252  ////
2253  // * COMPUTE EQUIVALENT DRAIN CURRENT SOURCE
2254  ////
2255 
2256  cd = mode * cdrain - cbd;
2257  // in 3f5 this is all in a block conditioned on CKTmode, but since
2258  // it's valid for MODETRAN and MODETRANOP we'll just always do it
2259 
2260  ////
2261  // * now we do the hard part of the bulk-drain and bulk-source
2262  // * diode - we evaluate the non-linear capacitance and
2263  // * charge
2264  // *
2265  // * the basic equations are not hard, but the implementation
2266  // * is somewhat long in an attempt to avoid log/exponential
2267  // * evaluations
2268  ////
2269  ////
2270  // * charge storage elements
2271  // *
2272  // *.. bulk-drain and bulk-source depletion capacitances
2273  ////
2274  // I took out all the CAPBYPASS stuff, and the
2275  // unnecessary curly braces that wind up there if you do
2276 
2277  // can't bypass the diode capacitance calculations
2278  if(Cbs != 0 || Cbssw != 0 )
2279  {
2280  if (vbs < tDepCap)
2281  {
2282  arg=1-vbs/tBulkPot;
2283  ////
2284  // * the following block looks somewhat long and messy,
2285  // * but since most users use the default grading
2286  // * coefficients of .5, and sqrt is MUCH faster than an
2287  // * exp(log()) we use this special case code to buy time.
2288  // * (as much as 10% of total job time!)
2289  ////
2291  {
2292  if(model_.bulkJctBotGradingCoeff == .5)
2293  {
2294  sarg = sargsw = 1/sqrt(arg);
2295  }
2296  else
2297  {
2298  sarg = sargsw = exp(-model_.bulkJctBotGradingCoeff*log(arg));
2299  }
2300  }
2301  else
2302  {
2303  if(model_.bulkJctBotGradingCoeff == .5)
2304  {
2305  sarg = 1/sqrt(arg);
2306  }
2307  else
2308  {
2309  sarg = exp(-model_.bulkJctBotGradingCoeff*log(arg));
2310  }
2312  {
2313  sargsw = 1/sqrt(arg);
2314  }
2315  else
2316  {
2317  sargsw =exp(-model_.bulkJctSideGradingCoeff* log(arg));
2318  }
2319  }
2320  qbs = tBulkPot*(Cbs*(1-arg*sarg)/(1-model_.bulkJctBotGradingCoeff)
2321  +Cbssw*(1-arg*sargsw)/(1-model_.bulkJctSideGradingCoeff));
2322  capbs=Cbs*sarg+ Cbssw*sargsw;
2323 
2324  }
2325  else
2326  {
2327  qbs = f4s + vbs*(f2s+vbs*(f3s/2));
2328  capbs=f2s+f3s*vbs;
2329  }
2330  }
2331  else
2332  {
2333  qbs = 0;
2334  capbs=0;
2335  }
2336 
2337  //// can't bypass the diode capacitance calculations
2338  if(Cbd != 0 || Cbdsw != 0 )
2339  {
2340 
2341  if (vbd < tDepCap)
2342  {
2343  arg=1-vbd/tBulkPot;
2344  ////
2345  // * the following block looks somewhat long and messy,
2346  // * but since most users use the default grading
2347  // * coefficients of .5, and sqrt is MUCH faster than an
2348  // * exp(log()) we use this special case code to buy time.
2349  // * (as much as 10% of total job time!)
2350  ////
2351  if(model_.bulkJctBotGradingCoeff == .5 &&
2353  {
2354  sarg = sargsw = 1/sqrt(arg);
2355  }
2356  else
2357  {
2358  if(model_.bulkJctBotGradingCoeff == .5)
2359  {
2360  sarg = 1/sqrt(arg);
2361  }
2362  else
2363  {
2364  sarg = exp(-model_.bulkJctBotGradingCoeff*log(arg));
2365  }
2367  {
2368  sargsw = 1/sqrt(arg);
2369  }
2370  else
2371  {
2372  sargsw =exp(-model_.bulkJctSideGradingCoeff*log(arg));
2373  }
2374  }
2375  qbd =
2376  tBulkPot*(Cbd*
2377  (1-arg*sarg)
2379  +Cbdsw*
2380  (1-arg*sargsw)
2382  capbd=Cbd*sarg+
2383  Cbdsw*sargsw;
2384  }
2385  else
2386  {
2387  qbd = f4d +
2388  vbd * (f2d + vbd * f3d/2);
2389  capbd=f2d + vbd * f3d;
2390  }
2391  }
2392  else
2393  {
2394  qbd = 0;
2395  capbd = 0;
2396  }
2397 
2398  // Now after a mess of convergence stuff that seems not to apply to us
2399  // 3f5 saves the vbs, vbd, etc. in the state vector (we don't, it gets
2400  // saved in updatePrimaryState)
2401 
2402  // Then 3f5 calculates meyer capacitances, capgs, capgb and capgd
2403  // Careful! They use the local von and vdsat, which haven't got dtype
2404  // multiplying them!
2405 
2406  ////
2407  // * calculate meyer's capacitors
2408  ////
2409  ////
2410  // * new cmeyer - this just evaluates at the current time,
2411  // * expects you to remember values from previous time
2412  // * returns 1/2 of non-constant portion of capacitance
2413  // * you must add in the other half from previous time
2414  // * and the constant part
2415  ////
2416 
2417  if (mode > 0)
2418  {
2419  devSupport.qmeyer (vgs,vgd,Vgb,Von,Vdsat,
2421  }
2422  else
2423  {
2424  devSupport.qmeyer (vgd,vgs,Vgb,Von,Vdsat,
2426  }
2427 
2428 
2429  // vgs1 = vgs_old;
2430  // vgd1 = vgs1 - vds_old;
2431  // vgb1 = vgs1 - vbs_old;
2432 
2433  ////
2434  // TVR: Note! Caution with Capgs vs. capgs. If I used the instance var
2435  // capgs on the left hand side, it's OK as long as we never try to implement
2436  // meyer back averaging, since capgs is going to be recalculated each
2437  // time through. But if we do the averaging, the old one will have the
2438  // constant part and old old part added in, which is not what we wanted.
2439  // So I'll continue 3f5's way of having a local Capgs that's actually used
2440  // for the charge computation, and an instance capgs that's saved as state.
2441  ////
2442 
2443  if((getSolverState().dcopFlag))
2444 // if(!(getSolverState().tranopFlag))
2445  {
2446  Capgs = 2 * capgs + GateSourceOverlapCap ;
2447  Capgd = 2 * capgd + GateDrainOverlapCap ;
2448  Capgb = 2 * capgb + GateBulkOverlapCap ;
2449  }
2450  else
2451  {
2452  capgs_old = (*extData.currStaVectorPtr)[li_state_capgs];
2453  capgd_old = (*extData.currStaVectorPtr)[li_state_capgd];
2454  capgb_old = (*extData.currStaVectorPtr)[li_state_capgb];
2455 
2456  Capgs = ( capgs+
2457  capgs_old +
2459  Capgd = ( capgd+
2460  capgd_old +
2462  Capgb = ( capgb+
2463  capgb_old +
2465  }
2466 
2467  // Eric does this kludge in level 1, so I'll do it to make sure capacitances
2468  // are positive
2469  Capgs *= (Capgs < 0.0)?-1.0:1.0;
2470  Capgd *= (Capgd < 0.0)?-1.0:1.0;
2471  Capgb *= (Capgb < 0.0)?-1.0:1.0;
2472 
2473 
2474  // in the sequel, I'll refer to all derivatives of currents w.r.t. voltages
2475  // as conductances, whether they really are or not.
2476 
2477  // when we get here, cdrain has the channel current
2478  // cbd and cbs have the currents through the diodes
2479  // cd has the drain current minus the diode current and seems only to be used
2480  // for 3f5 convergence stuff
2481  // qbs and qbd have the charges on the parasitic capacitors
2482  // capbs and capbd have the capacitances of the parasitics.
2483 
2484  // none of the charges for the gate capacitors have been calculated yet.
2485  // We've saved the capacitances, so we can get the charges in
2486  // updatePrimaryState later.
2487 
2488  // Conductances:
2489  // gbd: the bulk-drain' conductance without the capacitor components
2490  // We'll need to get the capacitor contribution in the actual load
2491  // using C*dt
2492  // gbs: bulk-source' without capacitor
2493  // gm = derivative of channel current w.r.t. gate-source voltage --- gotta
2494  // account for mode=normal or mode=reverse when using this!
2495  // gmbs = derivative of channel current w.r.t bulk-source voltage
2496  // gds = derivative of channel current w.r.t. drain-source voltage
2497 
2498  // the variables gcgs, gcgb, gcgd should be the conductances for the gate
2499  // capacitors, but we won't do those here (vide supra), we'll do them
2500  // in the jacobian load given the capacitances.
2501 
2502  // Now 3f5 doesn't do the resistor currents in the RHS load, because of
2503  // how they do their numerics. We do, so let's save those here.
2504 
2507 
2508  if (mode >= 0) // Normal mode
2509  {
2510  Gm = gm; // (xnrm-xrev)*gm in 3f5
2511  Gmbs = gmbs; // (xnrm-xrev)*gmbs in 3f5
2512  nrmsum = Gm+Gmbs; // xnrm*(gm+gmbs)
2513  revsum = 0; // xrev*(gm+gmbs)
2515  }
2516  else
2517  {
2518  Gm = -gm;
2519  Gmbs = -gmbs;
2520  nrmsum = 0;
2521  revsum = -(Gm+Gmbs); // because Gm and Gmbs already have - in them!
2522  cdreq = -(model_.dtype)*cdrain;
2523  }
2524 
2525  // It is now essential to restore the vds/vgs/vgd variables that might
2526  // have been tweaked by homotopy, lest they have an effect on RHS
2527  // Jdxp terms.
2528 
2529  vds=vds_save;
2530  vgs=vgs_save;
2531  vgd=vgd_save;
2532 
2533  /// CURRENTS to load into RHS:
2534 
2535  // so at this point:
2536 
2537  // current out of drain is
2538  // Idrain
2539 
2540  // current out of gate:
2541  // dtype*( (deriv of qgs) + (deriv of qgd) + (deriv of qgb))
2542 
2543  // the current *out of* the source should be simply
2544  // Isource.
2545 
2546  // current out of bulk is
2547  // dtype*(deriv of qbd) + dtype*cbd + dtype*cbs + dtype*(deriv of qbs)
2548  // - dtype*(deriv of qgb)
2549 
2550  // current out of drain' is
2551  // -Idrain - dtype*(deriv of qgd) - (deriv of qbd) - dtype*cbd +
2552  // mode*dtype*cdrain
2553 
2554  // the current out of the source' is
2555  // -Isource - dtype*(deriv of qgs) - dtype*cbs - (deriv of qbs) -
2556  // mode*dtype*cdrain
2557 
2558  //////Conductances to load into Jacobian as they relate to things here:
2559  /// all of the places where I say Cap/dt I really mean dtype*Cap/dt for
2560  // the meyer capacitors. No dtype for the parasitics, though
2561 
2562  // 3f5 handles the mode by doing:
2563  // where xnrm=1, xrev=0 if mode>=0, xnrm=0,xrev=1 if mode<0
2564 
2565  // drain-drain = a = drainConductance
2566  // drain-drain' = b = -drainConductance
2567 
2568  // gate-gate = c = "gcgd+gcgs+gcgb" = Capgd/dt+Capgs/dt+Capgb/dt
2569  // gate-bulk = d = -gcgb = -Capgb/dt
2570  // gate-drain' = e = -gcgd = -Capgd/dt
2571  // gate-source' = f = -gcgs = -Capgs/dt
2572 
2573  // source-source = g = sourceConductance
2574  // source-source' = h = -sourceConductance
2575 
2576  // bulk-gate = i = -gcgb = -Capgb/dt
2577  // bulk-bulk = j = gbs+gbd+gcgb+parasitics=gbs+gbd+Capgb/dt+capbs/dt+capbd/dt
2578  // bulk-drain' = k= -gbd-capbd/dt
2579  // bulk-source' = l= -gbs-capbs/dt
2580 
2581  // drain'-drain = m = -drainConductance
2582  // drain'-gate = n = (xnrm-xrev)*gm-Capgd/dt
2583  // drain'-bulk = o = -gbd-capbd/dt+(xnrm-xrev)*gmbs
2584  // drain'-drain' = p = drainConductance+gds+gbd+capbd/dt+
2585  // xrev*(gm+gmbs)+ Capgd/dt
2586  // drain'-source' = q = -gds-xnrm*(gm+gmbs)
2587 
2588  // source'-gate = r = -(xnrm-xrev)*gm-Capgs/dt
2589  // source'-source = s = -sourceConductance
2590  // source'-bulk = t = -gbs-capbs/dt-(xnrm-xrev)*gmbs
2591  // source'-drain' = u= -gds-xrev*(gm+gmbs)
2592  // source'-source' = v = sourceConductance+gds+gbs+capbs/dt+xnrm*(gm+gmbs)+
2593  // Capgs/dt
2594 
2595  return bsuccess;
2596 }
2597 
2598 
2599 //-----------------------------------------------------------------------------
2600 // Function : Instance::updateTemperature
2601 // Purpose :
2602 // Special Notes :
2603 // Scope : public
2604 // Creator : Tom Russo, Component Information and Models
2605 // Creation Date : 02/27/01
2606 //-----------------------------------------------------------------------------
2607 bool Instance::updateTemperature ( const double & temp_tmp)
2608 {
2609  // mos3temp vars
2610  double czbd; // zero voltage bulk-drain capacitance
2611  double czbdsw; // zero voltage bulk-drain sidewall capacitance
2612  double czbs; // zero voltage bulk-source capacitance
2613  double czbssw; // zero voltage bulk-source sidewall capacitance
2614  double arg; // 1 - fc
2615  double sarg; // (1-fc) ^^ (-mj)
2616  double sargsw; // (1-fc) ^^ (-mjsw)
2617  double ratio,ratio4;
2618  double fact2;
2619  double kt;
2620  double egfet;
2621  double pbfact;
2622  double capfact;
2623  double phio;
2624  double pbo;
2625  double gmanew,gmaold;
2626  // end of mos3temp stuff
2627 
2628  double tnom;
2629 
2630 #ifdef Xyce_DEBUG_DEVICE
2631  if (getDeviceOptions().debugLevel > 0 && getSolverState().debugTimeFlag)
2632  {
2633  Xyce::dout() << subsection_divider << std::endl;
2634  Xyce::dout() << " Instance::Begin of updateTemperature. \n";
2635  Xyce::dout() <<" name = " << getName() << std::endl;
2636  Xyce::dout() << std::endl;
2637  }
2638 #endif
2639 
2640  // first set the instance temperature to the new temperature:
2641  if (temp_tmp != -999.0) temp = temp_tmp;
2642 
2644  {
2646  }
2647 
2648  tnom = model_.tnom;
2649  ratio = temp/tnom;
2650 
2651 #ifdef Xyce_DEBUG_DEVICE
2652  if (getDeviceOptions().debugLevel > 0 && getSolverState().debugTimeFlag)
2653  {
2654  Xyce::dout() << "Temperature = "<< temp << std::endl;
2655  Xyce::dout() << "tnom = " << tnom << std::endl;
2656  Xyce::dout() << "ratio = " << ratio << std::endl;
2657  }
2658 #endif
2659 
2660  vt = temp * CONSTKoverQ;
2661  ratio = temp/tnom;
2662  fact2 = temp/CONSTREFTEMP;
2663  kt = temp * CONSTboltz;
2664  egfet = 1.16-(7.02e-4*temp*temp)/(temp+1108);
2665  arg = -egfet/(kt+kt)+1.1150877/(CONSTboltz*(CONSTREFTEMP+CONSTREFTEMP));
2666  pbfact = -2*vt *(1.5*log(fact2)+CONSTQ*arg);
2667 
2668 #ifdef Xyce_DEBUG_DEVICE
2670  {
2671  Xyce::dout() << "vt = " << vt << std::endl;
2672  Xyce::dout() << "ratio = " << ratio << std::endl;
2673  Xyce::dout() << "fact2 = " << fact2 << std::endl;
2674  Xyce::dout() << "kt = " << kt << std::endl;
2675  Xyce::dout() << "egfet = " << egfet << std::endl;
2676  Xyce::dout() << "arg = " << arg << std::endl;
2677  Xyce::dout() << "pbfact = " << pbfact << std::endl;
2678  }
2679 #endif
2680 
2681  // in mos3temp 3f5 does a bunch of parameter defaulting (lines 155-163)
2682  // but we assume that our various parameters have been set already in
2683  // the constructors
2684 
2685  // lines 164-203 of mos3temp moved to instance block constructor
2686 
2687  // Here's the entire guts of the mos3temp instance loop, with obvious
2688  // modifications (here->MOS3 goes away, model->MOS3 turns into model_.)
2689 
2690  ratio4 = ratio * sqrt(ratio);
2692  tSurfMob = model_.surfaceMobility/ratio4;
2693  phio= (model_.phi-model_.pbfact1)/model_.fact1;
2694  tPhi = fact2 * phio + pbfact;
2695  tVbi = model_.vt0 - model_.dtype *
2696  (model_.gamma* sqrt(model_.phi))+.5*(model_.egfet1-egfet)
2697  + model_.dtype*.5* (tPhi-model_.phi);
2698  tVto = tVbi + model_.dtype * model_.gamma * sqrt(tPhi);
2702  gmaold = (model_.bulkJctPotential-pbo)/pbo;
2703  capfact = 1/(1+model_.bulkJctBotGradingCoeff*
2704  (4e-4*(model_.tnom-CONSTREFTEMP)-gmaold));
2705  tCbd = model_.capBD * capfact;
2706  tCbs = model_.capBS * capfact;
2707  tCj = model_.bulkCapFactor * capfact;
2708  capfact = 1/(1+model_.bulkJctSideGradingCoeff*
2709  (4e-4*(model_.tnom-CONSTREFTEMP)-gmaold));
2710  tCjsw = model_.sideWallCapFactor * capfact;
2711  tBulkPot = fact2 * pbo+pbfact;
2712  gmanew = (tBulkPot-pbo)/pbo;
2713  capfact = (1+model_.bulkJctBotGradingCoeff*(4e-4*(temp-CONSTREFTEMP)-gmanew));
2714  tCbd *= capfact;
2715  tCbs *= capfact;
2716  tCj *= capfact;
2717  capfact = (1+model_.bulkJctSideGradingCoeff*(4e-4*(temp-CONSTREFTEMP)-gmanew));
2718  tCjsw *= capfact;
2720 
2721  if( (model_.jctSatCurDensity == 0) || (drainArea == 0) ||
2722  (sourceArea == 0) )
2723  {
2725  vt*log(vt/(CONSTroot2*model_.jctSatCur));
2726  }
2727  else
2728  {
2729  drainVcrit = vt * log( vt / (CONSTroot2 *
2731  sourceVcrit = vt * log( vt / (CONSTroot2 *
2733  }
2734  if(model_.capBDGiven)
2735  {
2736  czbd = tCbd;
2737  }
2738  else
2739  {
2741  {
2742  czbd=tCj*drainArea;
2743  }
2744  else
2745  {
2746  czbd=0;
2747  }
2748  }
2750  {
2751  czbdsw= tCjsw * drainPerimeter;
2752  }
2753  else
2754  {
2755  czbdsw=0;
2756  }
2757  arg = 1-model_.fwdCapDepCoeff;
2758  sarg = exp( (-model_.bulkJctBotGradingCoeff) * log(arg) );
2759  sargsw = exp( (-model_.bulkJctSideGradingCoeff) * log(arg) );
2760  Cbd = czbd;
2761  Cbdsw = czbdsw;
2762 
2763  // The following lines were taken verbatim from the SPICE level 3 mosfet.
2764  // There is a mistake in f3d and f4d, which incorrectly use bulkJctPotential
2765  // instead of tBulkPot. The result of this mistake is to have an incorrect
2766  // discontinuity in the charge calculations --- the derivative of charge
2767  // is right as the voltage drop approaches the discontinuity from either side
2768  // but when numerical differentiation is done to get currents one obtains a
2769  // massive contribution to the right hand side. Since spice never checks
2770  // the RHS residual norm this seems not to have any effect on SPICE, but
2771  // Xyce pukes.
2772  // f2d = czbd*(1-model_.fwdCapDepCoeff*
2773  // (1+model_.bulkJctBotGradingCoeff))* sarg/arg
2774  // + czbdsw*(1-model_.fwdCapDepCoeff*
2775  // (1+model_.bulkJctSideGradingCoeff))*
2776  // sargsw/arg;
2777  // f3d = czbd * model_.bulkJctBotGradingCoeff * sarg/arg/
2778  // model_.bulkJctPotential
2779  // + czbdsw * model_.bulkJctSideGradingCoeff * sargsw/arg /
2780  // model_.bulkJctPotential;
2781  // f4d = czbd*model_.bulkJctPotential*(1-arg*sarg)/
2782  // (1-model_.bulkJctBotGradingCoeff)
2783  // + czbdsw*model_.bulkJctPotential*(1-arg*sargsw)/
2784  // (1-model_.bulkJctSideGradingCoeff)
2785  // -f3d/2*
2786  // (tDepCap*tDepCap)
2787  // -tDepCap * f2d;
2788 
2789  // These lines were taken from the equivalent section of the level 1 mosfet
2790  // and do not have the mistake in the lines above.
2791  f2d = czbd*(1-model_.fwdCapDepCoeff*
2792  (1+model_.bulkJctBotGradingCoeff))* sarg/arg
2793  + czbdsw*(1-model_.fwdCapDepCoeff*
2795  sargsw/arg;
2796  f3d = czbd * model_.bulkJctBotGradingCoeff * sarg/arg/
2797  tBulkPot
2798  + czbdsw * model_.bulkJctSideGradingCoeff * sargsw/arg /
2799  tBulkPot;
2800  f4d = czbd*tBulkPot*(1-arg*sarg)/
2802  + czbdsw*tBulkPot*(1-arg*sargsw)/
2804  -f3d/2*
2805  (tDepCap*tDepCap)
2806  -tDepCap * f2d;
2807  if(model_.capBSGiven)
2808  {
2809  czbs=tCbs;
2810  }
2811  else
2812  {
2814  {
2815  czbs=tCj*sourceArea;
2816  }
2817  else
2818  {
2819  czbs=0;
2820  }
2821  }
2823  {
2824  czbssw = tCjsw * sourcePerimeter;
2825  }
2826  else
2827  {
2828  czbssw=0;
2829  }
2830  arg = 1-model_.fwdCapDepCoeff;
2831  sarg = exp( (-model_.bulkJctBotGradingCoeff) * log(arg) );
2832  sargsw = exp( (-model_.bulkJctSideGradingCoeff) * log(arg) );
2833  Cbs = czbs;
2834  Cbssw = czbssw;
2835 
2836  // See the comments above regarding f3d and f4d --- the same error
2837  // exists in the SPICE mosfet3 code
2838  // f2s = czbs*(1-model_.fwdCapDepCoeff*
2839  // (1+model_.bulkJctBotGradingCoeff))* sarg/arg
2840  // + czbssw*(1-model_.fwdCapDepCoeff*
2841  // (1+model_.bulkJctSideGradingCoeff))*
2842  // sargsw/arg;
2843  // f3s = czbs * model_.bulkJctBotGradingCoeff * sarg/arg/
2844  // model_.bulkJctPotential
2845  // + czbssw * model_.bulkJctSideGradingCoeff * sargsw/arg /
2846  // model_.bulkJctPotential;
2847  // f4s = czbs*model_.bulkJctPotential*(1-arg*sarg)/
2848  // (1-model_.bulkJctBotGradingCoeff)
2849  // + czbssw*model_.bulkJctPotential*(1-arg*sargsw)/
2850  // (1-model_.bulkJctSideGradingCoeff)
2851  // -f3s/2*
2852  // (tBulkPot*tBulkPot)
2853  // -tBulkPot * f2s;
2854 
2855  // so we use these lines from the MOSFET 1 instead.
2856  f2s = czbs*(1-model_.fwdCapDepCoeff*
2857  (1+model_.bulkJctBotGradingCoeff))* sarg/arg
2858  + czbssw*(1-model_.fwdCapDepCoeff*
2860  sargsw/arg;
2861  f3s = czbs * model_.bulkJctBotGradingCoeff * sarg/arg/
2862  tBulkPot
2863  + czbssw * model_.bulkJctSideGradingCoeff * sargsw/arg /
2864  tBulkPot;
2865  f4s = czbs*tBulkPot*(1-arg*sarg)/
2867  + czbssw*tBulkPot*(1-arg*sargsw)/
2869  -f3s/2*
2870  (tDepCap*tDepCap)
2871  -tDepCap * f2s;
2872 
2873  return true;
2874 }
2875 
2876 //-----------------------------------------------------------------------------
2877 // Function : Instance::updatePrimaryState
2878 // Purpose :
2879 // Special Notes :
2880 // Scope : public
2881 // Creator : Tom Russo, Component Information and Models
2882 // Creation Date : 02/28/01
2883 //-----------------------------------------------------------------------------
2885 {
2886  double * staVector = extData.nextStaVectorRawPtr;
2887  double * oldstaVector = extData.currStaVectorRawPtr;
2888  double * stoVector = extData.nextStoVectorRawPtr;
2889  double * oldstoVector = extData.currStoVectorRawPtr;
2890 
2891  double vgs1, vgd1, vbs1,vgb1, vds1;
2892 
2893  bool bsuccess = updateIntermediateVars ();
2894 
2895  // voltage drops:
2896  stoVector[li_store_vbd] = vbd;
2897  stoVector[li_store_vbs] = vbs;
2898  stoVector[li_store_vgs] = vgs;
2899  stoVector[li_store_vds] = vds;
2900  stoVector[li_store_von] = von;
2901 
2902  // now the meyer capacitances
2903  // we didn't calculate these charges in update IntermediateVars
2904  // but we did calculate the voltage drops and capacitances.
2905  // first store the capacitances themselves:
2906  staVector[li_state_capgs] = capgs;
2907  staVector[li_state_capgd] = capgd;
2908  staVector[li_state_capgb] = capgb;
2909 
2910  // now the charges
2911  // BE CAREFUL! We can only do Q=CV for DCOP! Otherwise it's
2912  // supposed to be *INTEGRATED*:
2913  // Q = int(t0,t1)C(V)*dV --- and we approximate that by
2914  // Q(t1)-Q(t0) = CBar*(V(t1)-V(t0)) where CBar is the average.
2915  // Now with Meyer back averaging, Capxx is the average between the last
2916  // time step and this one. So we gotta do the right thing for non-DCOP
2917  // when backaverage is on.
2918 
2919  if((getSolverState().dcopFlag))
2920 // if(!(getSolverState().tranopFlag))
2921  {
2922  qgs = Capgs*vgs;
2923  qgd = Capgd*vgd;
2924  qgb = Capgb*Vgb;
2925  }
2926  else
2927  {
2928  // get the ones from last time step
2929  qgs = oldstaVector[li_state_qgs];
2930  qgd = oldstaVector[li_state_qgd];
2931  qgb = oldstaVector[li_state_qgb];
2932  // get the voltage drops, too
2933  vgs1 = oldstoVector[li_store_vgs];
2934  vbs1 = oldstoVector[li_store_vbs];
2935  vds1 = oldstoVector[li_store_vds];
2936 
2937  vgb1 = vgs1-vbs1;
2938  vgd1 = vgs1-vds1;
2939 
2940  // NOW we can calculate the charge update
2941  qgs += Capgs*(vgs-vgs1);
2942  qgd += Capgd*(vgd-vgd1);
2943  qgb += Capgb*((vgs-vbs)-vgb1);
2944  }
2945 
2946  staVector[li_state_qgs] = qgs;
2947  staVector[li_state_qgd] = qgd;
2948  staVector[li_state_qgb] = qgb;
2949 
2950  // and the diode parasitic capacitors
2951  // these charges were set in updateIntermediateVars
2952  staVector[li_state_qbd] = qbd;
2953  staVector[li_state_qbs] = qbs;
2954 
2955  return bsuccess;
2956 }
2957 
2958 // Additional Declarations
2959 
2960 // Class Model
2961 
2962 //-----------------------------------------------------------------------------
2963 // Function : Model::processParams
2964 // Purpose :
2965 // Special Notes :
2966 // Scope : public
2967 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
2968 // Creation Date : 6/03/02
2969 //-----------------------------------------------------------------------------
2971 {
2972  double wkfngs;
2973  double wkfng;
2974  double fermig;
2975  double fermis;
2976  double vfb;
2977  double kt1;
2978  double arg1;
2979 
2982  kt1 = CONSTboltz * tnom;
2983  egfet1 = 1.16-(7.02e-4*tnom*tnom)/(tnom+1108);
2984  arg1 = -egfet1/(kt1+kt1)+1.1150877/(CONSTboltz*(CONSTREFTEMP+CONSTREFTEMP));
2985  pbfact1 = -2*vtnom *(1.5*log(fact1)+CONSTQ*arg1);
2986 
2987  if(oxideThickness == 0)
2988  {
2989  UserError0(*this) << getName() << " has TOX=0";
2990  }
2991  else
2992  {
2993  oxideCapFactor = 3.9 * 8.854214871e-12/oxideThickness;
2994  }
2995  if(!given("U0") && !given("UO")) surfaceMobility=600;
2996  if(!given("KP"))
2998  if(given("NSUB"))
2999  {
3000  if(substrateDoping*1e6 >1.45e16)
3001  {
3002  if(!given("PHI"))
3003  {
3004  phi = 2*vtnom*
3005  log(substrateDoping*1e6/1.45e16);
3006  phi = Xycemax(0.1,phi);
3007  }
3008  fermis = dtype * .5 * phi;
3009  wkfng = 3.2;
3010  if(!given("TPG")) gateType=1;
3011  if(gateType != 0)
3012  {
3013  fermig = dtype *gateType*.5*egfet1;
3014  wkfng = 3.25 + .5 * egfet1 - fermig;
3015  }
3016  wkfngs = wkfng - (3.25 + .5 * egfet1 +fermis);
3017  if(!given("GAMMA"))
3018  {
3019  gamma = sqrt(2 * 11.70 * CONSTperm0 *
3020  CONSTQ * substrateDoping*1e6)/
3022  }
3023  if(!given("VTO"))
3024  {
3025  if(!given("NSS"))
3027  vfb = wkfngs - surfaceStateDensity*1e4*CONSTQ/oxideCapFactor;
3028  vt0 = vfb + dtype * (gamma * sqrt(phi)+ phi);
3029  }
3030  else
3031  {
3032  vfb = vt0 - dtype * (gamma*sqrt(phi)+phi);
3033  }
3034  alpha = ((11.7*CONSTperm0)+(11.7*CONSTperm0))/
3035  (CONSTQ*substrateDoping*1e6); //(cm**3/m**3)
3036  coeffDepLayWidth = sqrt(alpha);
3037  }
3038  else
3039  {
3040  UserError0(*this) << "Nsub < Ni";
3041  }
3042  }
3043 
3044  // now model parameter preprocessing
3045  double mpi = M_PI;
3046  narrowFactor = delta * 0.5 * mpi * (11.7*CONSTperm0) /oxideCapFactor ;
3047 
3048  return true;
3049 }
3050 
3051 //----------------------------------------------------------------------------
3052 // Function : Model::processInstanceParams
3053 // Purpose :
3054 // Special Notes :
3055 // Scope : public
3056 // Creator : Dave Shirely, PSSI
3057 // Creation Date : 03/23/06
3058 //----------------------------------------------------------------------------
3060 {
3061  std::vector<Instance*>::iterator iter;
3062  std::vector<Instance*>::iterator first = instanceContainer.begin();
3063  std::vector<Instance*>::iterator last = instanceContainer.end();
3064 
3065  for (iter=first; iter!=last; ++iter)
3066  {
3067  (*iter)->processParams();
3068  }
3069 
3070  return true;
3071 }
3072 
3073 //-----------------------------------------------------------------------------
3074 // Function : Model::Model
3075 // Purpose :
3076 // Special Notes :
3077 // Scope : public
3078 // Creator : Tom Russo, Component Information and Models
3079 // Creation Date : 2/26/01
3080 //-----------------------------------------------------------------------------
3082  const Configuration & configuration,
3083  const ModelBlock & MB,
3084  const FactoryBlock & factory_block)
3085  : DeviceModel(MB, configuration.getModelParameters(), factory_block),
3086  dtype(CONSTNMOS),
3087  tnom(getDeviceOptions().tnom),
3088  latDiff(0.0),
3089  jctSatCurDensity(0.0),
3090  jctSatCur(0.0),
3091  drainResistance(0.0),
3092  sourceResistance(0.0),
3093  sheetResistance(0.0),
3094  transconductance(0.0),
3095  gateSourceOverlapCapFactor(0.0),
3096  gateDrainOverlapCapFactor(0.0),
3097  gateBulkOverlapCapFactor(0.0),
3098  oxideCapFactor(0.0),
3099  vt0(0.0),
3100  capBD(0.0),
3101  capBS(0.0),
3102  bulkCapFactor(0.0),
3103  sideWallCapFactor(0.0),
3104  bulkJctPotential(0.0),
3105  bulkJctBotGradingCoeff(0.0),
3106  bulkJctSideGradingCoeff(0.0),
3107  fwdCapDepCoeff(0.0),
3108  phi(0.0),
3109  gamma(0.0),
3110  substrateDoping(0.0),
3111  gateType(0),
3112  surfaceStateDensity(0.0),
3113  oxideThickness(0.0),
3114  surfaceMobility(0.0),
3115  eta(0.0),
3116  junctionDepth(0.0),
3117  coeffDepLayWidth(0.0),
3118  narrowFactor(0.0),
3119  delta(0.0),
3120  fastSurfaceStateDensity(0.0),
3121  theta(0.0),
3122  maxDriftVel(0.0),
3123  alpha(0.0),
3124  kappa(0.0),
3125  fNcoef(0.0),
3126  fNexp(0.0),
3127  capBDGiven(0),
3128  capBSGiven(0),
3129  bulkCapFactorGiven(0),
3130  sideWallCapFactorGiven(0)
3131 {
3132  if (getType() != "")
3133  {
3134  if (getType() == "NMOS") {
3135  dtype = CONSTNMOS;
3136  }
3137  else if (getType() == "PMOS") {
3138  dtype = CONSTPMOS;
3139  }
3140  else
3141  {
3142  UserError0(*this) << "Could not recognize the type for model " << getName();
3143  }
3144  }
3145 
3146 
3147  // Set params to constant default values:
3148  setDefaultParams ();
3149 
3150  // Set params according to .model line and constant defaults from metadata:
3151  setModParams (MB.params);
3152 
3153  // Set any non-constant parameter defaults:
3154  if (!given("L"))
3156  if (!given("W"))
3158  if (!given("TNOM"))
3160  if (capBD != 0)
3161  capBDGiven = true;
3162  if (capBS != 0)
3163  capBSGiven = true;
3164 
3165  // Calculate any parameters specified as expressions:
3167 
3168  // calculate dependent (ie computed) params and check for errors:
3169  if (given("U0"))
3170  {
3171  if (given("UO"))
3172  UserError0(*this) << "Both uo and u0 have been specified and, which is not allowed";
3173  else
3174  UserWarning0(*this) << "Surface mobility has been specified as u0 instead of uo, uo is the preferred syntax";
3175 
3177  }
3178 
3179  processParams ();
3180 }
3181 
3182 //-----------------------------------------------------------------------------
3183 // Function : Model::~Model
3184 // Purpose : destructor
3185 // Special Notes :
3186 // Scope : public
3187 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
3188 // Creation Date : 3/16/00
3189 //-----------------------------------------------------------------------------
3191 {
3192  std::vector<Instance*>::iterator iter;
3193  std::vector<Instance*>::iterator first = instanceContainer.begin();
3194  std::vector<Instance*>::iterator last = instanceContainer.end();
3195 
3196  for (iter=first; iter!=last; ++iter)
3197  {
3198  delete (*iter);
3199  }
3200 
3201 }
3202 
3203 //-----------------------------------------------------------------------------
3204 // Function : Model::printOutInstances
3205 // Purpose : debugging tool.
3206 // Special Notes :
3207 // Scope : public
3208 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
3209 // Creation Date : 4/03/00
3210 //-----------------------------------------------------------------------------
3211 std::ostream &Model::printOutInstances(std::ostream &os) const
3212 {
3213  std::vector<Instance*>::const_iterator iter;
3214  std::vector<Instance*>::const_iterator first = instanceContainer.begin();
3215  std::vector<Instance*>::const_iterator last = instanceContainer.end();
3216 
3217  int i;
3218  os << std::endl;
3219  os << " name model name Parameters" << std::endl;
3220  for (i=0, iter=first; iter!=last; ++iter, ++i)
3221  {
3222  os << " " << i << ": " << (*iter)->getName() << "\t";
3223  os << getName();
3224  os << std::endl;
3225  }
3226  os << std::endl;
3227 
3228  return os;
3229 }
3230 
3231 //-----------------------------------------------------------------------------
3232 // Function : Model::forEachInstance
3233 // Purpose :
3234 // Special Notes :
3235 // Scope : public
3236 // Creator : David Baur
3237 // Creation Date : 2/4/2014
3238 //-----------------------------------------------------------------------------
3239 /// Apply a device instance "op" to all instances associated with this
3240 /// model
3241 ///
3242 /// @param[in] op Operator to apply to all instances.
3243 ///
3244 ///
3245 void Model::forEachInstance(DeviceInstanceOp &op) const /* override */
3246 {
3247  for (std::vector<Instance *>::const_iterator it = instanceContainer.begin(); it != instanceContainer.end(); ++it)
3248  op(*it);
3249 }
3250 
3251 
3252 //-----------------------------------------------------------------------------
3253 // MOSFET3 Master functions:
3254 //-----------------------------------------------------------------------------
3255 
3256 //-----------------------------------------------------------------------------
3257 // Function : Master::updateState
3258 // Purpose :
3259 // Special Notes :
3260 // Scope : public
3261 // Creator : Eric Keiter, SNL
3262 // Creation Date : 11/26/08
3263 //-----------------------------------------------------------------------------
3264 bool Master::updateState (double * solVec, double * staVec, double * stoVec)
3265 {
3266  bool bsuccess = true;
3267 
3268  for (InstanceVector::const_iterator it = getInstanceBegin(); it != getInstanceEnd(); ++it)
3269  {
3270  Instance & mi = *(*it);
3271 
3272  double * oldstaVectorPtr = mi.extData.currStaVectorRawPtr;
3273  double * stoVec = mi.extData.nextStoVectorRawPtr;
3274  double * oldstoVec = mi.extData.currStoVectorRawPtr;
3275 
3276  double vgs1(0.0), vgd1(0.0), vbs1(0.0),vgb1(0.0), vds1(0.0);
3277 
3278  bool btmp = mi.updateIntermediateVars ();
3279  bsuccess = bsuccess && btmp;
3280 
3281  // voltage drops:
3282  stoVec[mi.li_store_vbd] = mi.vbd;
3283  stoVec[mi.li_store_vbs] = mi.vbs;
3284  stoVec[mi.li_store_vgs] = mi.vgs;
3285  stoVec[mi.li_store_vds] = mi.vds;
3286  stoVec[mi.li_store_von] = mi.von;
3287 
3288  // now the meyer capacitances
3289  // we didn't calculate these charges in update IntermediateVars
3290  // but we did calculate the voltage drops and capacitances.
3291  // first store the capacitances themselves:
3292  staVec[mi.li_state_capgs] = mi.capgs;
3293  staVec[mi.li_state_capgd] = mi.capgd;
3294  staVec[mi.li_state_capgb] = mi.capgb;
3295 
3296  // now the charges
3297  // BE CAREFUL! We can only do Q=CV for DCOP! Otherwise it's
3298  // supposed to be *INTEGRATED*:
3299  // Q = int(t0,t1)C(V)*dV --- and we approximate that by
3300  // Q(t1)-Q(t0) = CBar*(V(t1)-V(t0)) where CBar is the average.
3301  // Now with Meyer back averaging, Capxx is the average between the last
3302  // time step and this one. So we gotta do the right thing for non-DCOP
3303  // when backaverage is on.
3304 
3305  if((getSolverState().dcopFlag))
3306 // if(!(getSolverState().tranopFlag))
3307  {
3308  mi.qgs = mi.Capgs*mi.vgs;
3309  mi.qgd = mi.Capgd*mi.vgd;
3310  mi.qgb = mi.Capgb*mi.Vgb;
3311  }
3312  else
3313  {
3314  // get the ones from last time step
3315  mi.qgs = (oldstaVectorPtr)[mi.li_state_qgs];
3316  mi.qgd = (oldstaVectorPtr)[mi.li_state_qgd];
3317  mi.qgb = (oldstaVectorPtr)[mi.li_state_qgb];
3318  // get the voltage drops, too
3319  vgs1 = oldstoVec[mi.li_store_vgs];
3320  vbs1 = oldstoVec[mi.li_store_vbs];
3321  vds1 = oldstoVec[mi.li_store_vds];
3322 
3323  vgb1 = vgs1-vbs1;
3324  vgd1 = vgs1-vds1;
3325 
3326  // NOW we can calculate the charge update
3327  mi.qgs += mi.Capgs*(mi.vgs-vgs1);
3328  mi.qgd += mi.Capgd*(mi.vgd-vgd1);
3329  mi.qgb += mi.Capgb*((mi.vgs-mi.vbs)-vgb1);
3330  }
3331 
3332  staVec[mi.li_state_qgs] = mi.qgs;
3333  staVec[mi.li_state_qgd] = mi.qgd;
3334  staVec[mi.li_state_qgb] = mi.qgb;
3335 
3336  // and the diode parasitic capacitors
3337  // these charges were set in updateIntermediateVars
3338  staVec[mi.li_state_qbd] = mi.qbd;
3339  staVec[mi.li_state_qbs] = mi.qbs;
3340  }
3341 
3342  return bsuccess;
3343 }
3344 
3345 //-----------------------------------------------------------------------------
3346 // Function : Master::loadDAEVectors
3347 // Purpose :
3348 // Special Notes :
3349 // Scope : public
3350 // Creator : Eric Keiter, SNL
3351 // Creation Date : 11/26/08
3352 //-----------------------------------------------------------------------------
3353 bool Master::loadDAEVectors (double * solVec, double * fVec, double *qVec, double * bVec, double * storeLeadF, double * storeLeadQ)
3354 {
3355  double gmin1 = getDeviceOptions().gmin;
3356 
3357  for (InstanceVector::const_iterator it = getInstanceBegin(); it != getInstanceEnd(); ++it)
3358  {
3359  Instance & mi = *(*it);
3360 
3361  int Dtype=mi.getModel().dtype;
3362  double ceqbs(0.0),ceqbd(0.0),ceqgb(0.0), ceqgs(0.0), ceqgd(0.0);
3363  double Qeqbs(0.0),Qeqbd(0.0),Qeqgb(0.0), Qeqgs(0.0), Qeqgd(0.0);
3364  double coef(0.0);
3365 
3366  // F-Vector:
3367  ceqbs = Dtype*(mi.cbs);
3368  ceqbd = Dtype*(mi.cbd);
3369  // These need "Dtype" here because we use them later *without*
3370  // Dtype, where SPICE uses it *with*
3371  ceqgb = 0.0;
3372  ceqgs = 0.0;
3373  ceqgd = 0.0;
3374 
3375  if (mi.drainConductance != 0.0)
3376  {
3377  fVec[mi.li_Drain] += mi.Idrain*mi.numberParallel;
3378  }
3379 
3380  coef = (ceqgs+ceqgd+ceqgb);
3381 
3382  fVec[mi.li_Gate] += coef*mi.numberParallel;
3383 
3384  if (mi.sourceConductance != 0.0)
3385  {
3386  fVec[mi.li_Source] += mi.Isource*mi.numberParallel;
3387  }
3388 
3389  coef = ceqbs + ceqbd - ceqgb;
3390 
3391  fVec[mi.li_Bulk] += coef*mi.numberParallel;
3392 
3393  coef = -mi.Idrain-(ceqbd - mi.cdreq + ceqgd);
3394 
3395  fVec[mi.li_DrainPrime] += coef*mi.numberParallel;
3396 
3397  coef = -mi.Isource-(ceqbs + mi.cdreq + ceqgs);
3398 
3399  fVec[mi.li_SourcePrime] += coef*mi.numberParallel;
3400 
3401  // Q-Vector:
3402  Qeqbs = Dtype*(mi.qbs);
3403  Qeqbd = Dtype*(mi.qbd);
3404  // These need "Dtype" here because we use them later *without*
3405  // Dtype, where SPICE uses it *with*
3406  Qeqgb = Dtype*(mi.qgb);
3407  Qeqgs = Dtype*(mi.qgs);
3408  Qeqgd = Dtype*(mi.qgd);
3409 
3410  coef = (Qeqgs+Qeqgd+Qeqgb);
3411 
3412  qVec[mi.li_Gate] += coef*mi.numberParallel;
3413 
3414  coef = Qeqbs + Qeqbd - Qeqgb;
3415 
3416  qVec[mi.li_Bulk] += coef*mi.numberParallel;
3417 
3418  coef = -(Qeqbd + Qeqgd);
3419 
3420  qVec[mi.li_DrainPrime] += coef*mi.numberParallel;
3421 
3422  coef = -(Qeqbs + Qeqgs);
3423 
3424  qVec[mi.li_SourcePrime] += coef*mi.numberParallel;
3425 
3426  // voltage limiters:
3427  if (!mi.origFlag)
3428  {
3429  // F-limiters:
3430  double coef_Jdxp4 = Dtype*(
3431  + ((mi.gbd-gmin1))*(mi.vbd-mi.vbd_orig)
3432  + ((mi.gbs-gmin1))*(mi.vbs-mi.vbs_orig));
3433 
3434  double coef_Jdxp5 = Dtype*(
3435  -((mi.gbd-gmin1))*(mi.vbd-mi.vbd_orig)
3436  +mi.gds*(mi.vds-mi.vds_orig)
3437  +mi.Gm*((mi.mode>0)?(mi.vgs-mi.vgs_orig):(mi.vgd-mi.vgd_orig))
3438  +mi.Gmbs*((mi.mode>0)?(mi.vbs-mi.vbs_orig):(mi.vbd-mi.vbd_orig)));
3439 
3440  double coef_Jdxp6 = Dtype*(
3441  -((mi.gbs-gmin1))*(mi.vbs-mi.vbs_orig)
3442  -mi.gds*(mi.vds-mi.vds_orig)
3443  -mi.Gm*((mi.mode>0)?(mi.vgs-mi.vgs_orig):(mi.vgd-mi.vgd_orig))
3444  -mi.Gmbs*((mi.mode>0)?(mi.vbs-mi.vbs_orig):(mi.vbd-mi.vbd_orig)));
3445 
3446  double * dFdxdVp = mi.extData.dFdxdVpVectorRawPtr;
3447  dFdxdVp[mi.li_Bulk ] += coef_Jdxp4*mi.numberParallel;
3448  dFdxdVp[mi.li_DrainPrime ] += coef_Jdxp5*mi.numberParallel;
3449  dFdxdVp[mi.li_SourcePrime] += coef_Jdxp6*mi.numberParallel;
3450 
3451  // Q-limiters:
3452  {
3453  double gcgd(0.0), gcgs(0.0), gcgb(0.0), gcbs(0.0), gcbd(0.0);
3454  if (getSolverState().tranopFlag || getSolverState().acopFlag || getSolverState().transientFlag)
3455  {
3456  gcgd = mi.Capgd;
3457  gcgs = mi.Capgs;
3458  gcgb = mi.Capgb;
3459  // get at the two parasitic caps the same way
3460  gcbs = mi.capbs;
3461  gcbd = mi.capbd;
3462  }
3463  else
3464  {
3465  gcgd = 0.0; gcgs = 0.0; gcgb = 0.0; gcbs = 0.0; gcbd = 0.0;
3466  }
3467 
3468  double coef_Jdxp2 =
3469  Dtype*(gcgd*(mi.vgd-mi.vgd_orig)+gcgs*(mi.vgs-mi.vgs_orig)+
3470  gcgb*(mi.vgs-mi.vgs_orig-mi.vbs+mi.vbs_orig));
3471 
3472  double coef_Jdxp4 = Dtype*(
3473  - (gcgb)*(mi.vgs-mi.vgs_orig-mi.vbs+mi.vbs_orig)
3474  + (gcgb)*(mi.vbd-mi.vbd_orig)
3475  + (gcbs)*(mi.vbs-mi.vbs_orig));
3476 
3477  double coef_Jdxp5 = Dtype*(
3478  -(gcgd)*(mi.vgd-mi.vgd_orig)
3479  -(gcbd)*(mi.vbd-mi.vbd_orig));
3480 
3481  // 6 KCL for source' node
3482  double coef_Jdxp6 = Dtype*
3483  (-gcgs*(mi.vgs-mi.vgs_orig)-(gcbs)*(mi.vbs-mi.vbs_orig));
3484 
3485  double * dQdxdVp = mi.extData.dQdxdVpVectorRawPtr;
3486  dQdxdVp[mi.li_Gate ] += coef_Jdxp2*mi.numberParallel;
3487  dQdxdVp[mi.li_Bulk ] += coef_Jdxp4*mi.numberParallel;
3488  dQdxdVp[mi.li_DrainPrime ] += coef_Jdxp5*mi.numberParallel;
3489  dQdxdVp[mi.li_SourcePrime] += coef_Jdxp6*mi.numberParallel;
3490  }
3491  }
3492 
3493  if( mi.loadLeadCurrent )
3494  {
3495  storeLeadF[mi.li_store_dev_id] = (-(ceqbd - mi.cdreq + ceqgd))*mi.numberParallel;
3496  storeLeadQ[mi.li_store_dev_id] = (-(Qeqbd + Qeqgd))*mi.numberParallel;
3497  storeLeadF[mi.li_store_dev_is] = (-(ceqbs + mi.cdreq + ceqgs))*mi.numberParallel;
3498  storeLeadQ[mi.li_store_dev_is] = (-(Qeqbs + Qeqgs))*mi.numberParallel;
3499  storeLeadF[mi.li_store_dev_ig] = (ceqgs+ceqgd+ceqgb)*mi.numberParallel;
3500  storeLeadQ[mi.li_store_dev_ig] = (Qeqgs+Qeqgd+Qeqgb)*mi.numberParallel;
3501  storeLeadF[mi.li_store_dev_ib] = (ceqbs + ceqbd - ceqgb)*mi.numberParallel;
3502  storeLeadQ[mi.li_store_dev_ib] = (Qeqbs + Qeqbd - Qeqgb)*mi.numberParallel;
3503  }
3504  }
3505 
3506  return true;
3507 }
3508 
3509 #ifndef Xyce_NONPOINTER_MATRIX_LOAD
3510 //-----------------------------------------------------------------------------
3511 // Function : Master::loadDAEMatrices
3512 // Purpose :
3513 // Special Notes :
3514 // Scope : public
3515 // Creator : Eric Keiter, SNL
3516 // Creation Date : 11/26/08
3517 //-----------------------------------------------------------------------------
3518 bool Master::loadDAEMatrices (N_LAS_Matrix & dFdx, N_LAS_Matrix & dQdx)
3519 {
3520  for (InstanceVector::const_iterator it = getInstanceBegin(); it != getInstanceEnd(); ++it)
3521  {
3522  Instance & mi = *(*it);
3523 
3524  // F-matrix:
3525 
3526  *mi.f_DrainEquDrainNodePtr +=
3528 
3531 
3532 
3535 
3538 
3539 
3540  *mi.f_BulkEquBulkNodePtr +=
3541  (mi.gbs+mi.gbd)*mi.numberParallel;
3542 
3544 
3546 
3547 
3550 
3552  mi.Gm*mi.numberParallel;
3553 
3555  (-mi.gbd+mi.Gmbs)*mi.numberParallel;
3556 
3558  (mi.drainConductance+mi.gds+mi.gbd+mi.revsum)*mi.numberParallel;
3559 
3561  (-mi.gds-mi.nrmsum)*mi.numberParallel;
3562 
3563 
3565  mi.Gm*mi.numberParallel;
3566 
3569 
3571  (mi.gbs+mi.Gmbs)*mi.numberParallel;
3572 
3574  (mi.gds+mi.revsum)*mi.numberParallel;
3575 
3577  (mi.sourceConductance+mi.gds+mi.gbs+mi.nrmsum)*mi.numberParallel;
3578 
3579  // Q-matrix:
3580  double gcgd(0.0); // d(cqgd)/dVgd
3581  double gcgs(0.0); // d(cqgs)/dVgs
3582  double gcgb(0.0); // d(cqgb)/dVgb
3583  double gcbs(0.0); // d(cqbs)/dVbs
3584  double gcbd(0.0); // d(cqbd)/dVbd
3585 
3586  // get at the "conductances" for the gate capacitors with this trick
3587  // gcgd = model_.dtype*Capgd;
3588  // gcgs = model_.dtype*Capgs;
3589  // gcgb = model_.dtype*Capgb;
3590  //
3591  // In the loadRHS function, these would all be multiplied by
3592  // getSolverState().pdt. Here, for *mi.q_, the pdt term is left out.
3593  if (getSolverState().tranopFlag || getSolverState().acopFlag || getSolverState().transientFlag)
3594  {
3595  gcgd = mi.Capgd;
3596  gcgs = mi.Capgs;
3597  gcgb = mi.Capgb;
3598  // get at the two parasitic caps the same way
3599  gcbs = mi.capbs;
3600  gcbd = mi.capbd;
3601  }
3602 
3603 
3604  *mi.q_GateEquGateNodePtr +=
3605  (gcgd+gcgs+gcgb)*mi.numberParallel;
3606 
3607  *mi.q_GateEquBulkNodePtr -= gcgb*mi.numberParallel;
3608 
3610 
3612 
3613 
3614  *mi.q_BulkEquGateNodePtr -= gcgb*mi.numberParallel;
3615 
3616  *mi.q_BulkEquBulkNodePtr +=
3617  (+gcbs+gcbd+gcgb)*mi.numberParallel;
3618 
3620 
3622  +gcbs*mi.numberParallel;
3623 
3624 
3626  -gcgd*mi.numberParallel;
3627 
3629  -gcbd*mi.numberParallel;
3630 
3632  (+gcbd+gcgd)*mi.numberParallel;
3633 
3634 
3636  gcgs*mi.numberParallel;
3637 
3639  +gcbs*mi.numberParallel;
3640 
3642  (+gcbs+gcgs)*mi.numberParallel;
3643  }
3644  return true;
3645 }
3646 #else
3647 //-----------------------------------------------------------------------------
3648 // Function : Master::loadDAEMatrices
3649 // Purpose :
3650 // Special Notes :
3651 // Scope : public
3652 // Creator : Eric Keiter, SNL
3653 // Creation Date : 11/26/08
3654 //-----------------------------------------------------------------------------
3655 bool Master::loadDAEMatrices (N_LAS_Matrix & dFdx, N_LAS_Matrix & dQdx)
3656 {
3657  int sizeInstances = instanceContainer_.size();
3658  for (int i=0; i<sizeInstances; ++i)
3659  {
3660  Instance & mi = *(instanceContainer_.at(i));
3661 
3662  // F-matrix:
3663  dFdx[mi.li_Drain][mi.ADrainEquDrainNodeOffset] +=
3665 
3666  dFdx[mi.li_Drain][mi.ADrainEquDrainPrimeNodeOffset] -=
3668 
3669  dFdx[mi.li_Source][mi.ASourceEquSourceNodeOffset] +=
3671 
3674 
3675  dFdx[mi.li_Bulk][mi.ABulkEquBulkNodeOffset] +=
3676  (mi.gbs+mi.gbd)*mi.numberParallel;
3677 
3680 
3681 
3684 
3686  mi.Gm*mi.numberParallel;
3687 
3689  (-mi.gbd+mi.Gmbs)*mi.numberParallel;
3690 
3692  (mi.drainConductance+mi.gds+mi.gbd+mi.revsum)*mi.numberParallel;
3693 
3695  (-mi.gds-mi.nrmsum)*mi.numberParallel;
3696 
3697 
3699  mi.Gm*mi.numberParallel;
3700 
3703 
3705  (mi.gbs+mi.Gmbs)*mi.numberParallel;
3706 
3708  (mi.gds+mi.revsum)*mi.numberParallel;
3709 
3711  (mi.sourceConductance+mi.gds+mi.gbs+mi.nrmsum)*mi.numberParallel;
3712 
3713  // Q-matrix:
3714  double gcgd(0.0); // d(cqgd)/dVgd
3715  double gcgs(0.0); // d(cqgs)/dVgs
3716  double gcgb(0.0); // d(cqgb)/dVgb
3717  double gcbs(0.0); // d(cqbs)/dVbs
3718  double gcbd(0.0); // d(cqbd)/dVbd
3719 
3720  // get at the "conductances" for the gate capacitors with this trick
3721  // gcgd = model_.dtype*Capgd;
3722  // gcgs = model_.dtype*Capgs;
3723  // gcgb = model_.dtype*Capgb;
3724  //
3725  // In the loadRHS function, these would all be multiplied by
3726  // getSolverState().pdt. Here, for dQdx, the pdt term is left out.
3727  if (getSolverState().tranopFlag || getSolverState().acopFlag || getSolverState().transientFlag)
3728  {
3729  gcgd = mi.Capgd;
3730  gcgs = mi.Capgs;
3731  gcgb = mi.Capgb;
3732  // get at the two parasitic caps the same way
3733  gcbs = mi.capbs;
3734  gcbd = mi.capbd;
3735  }
3736 
3737 
3738  dQdx[mi.li_Gate][mi.AGateEquGateNodeOffset] +=
3739  (gcgd+gcgs+gcgb)*mi.numberParallel;
3740 
3741  dQdx[mi.li_Gate][mi.AGateEquBulkNodeOffset] -= gcgb*mi.numberParallel;
3742  dQdx[mi.li_Gate][mi.AGateEquDrainPrimeNodeOffset] -= gcgd*mi.numberParallel;
3743  dQdx[mi.li_Gate][mi.AGateEquSourcePrimeNodeOffset] -= gcgs*mi.numberParallel;
3744  dQdx[mi.li_Bulk][mi.ABulkEquGateNodeOffset] -= gcgb*mi.numberParallel;
3745  dQdx[mi.li_Bulk][mi.ABulkEquBulkNodeOffset] +=
3746  (+gcbs+gcbd+gcgb)*mi.numberParallel;
3747  dQdx[mi.li_Bulk][mi.ABulkEquDrainPrimeNodeOffset] -= +gcbd*mi.numberParallel;
3748  dQdx[mi.li_Bulk][mi.ABulkEquSourcePrimeNodeOffset] -=
3749  +gcbs*mi.numberParallel;
3751  -gcgd*mi.numberParallel;
3753  -gcbd*mi.numberParallel;
3755  (+gcbd+gcgd)*mi.numberParallel;
3757  gcgs*mi.numberParallel;
3759  +gcbs*mi.numberParallel;
3761  (+gcbs+gcgs)*mi.numberParallel;
3762  }
3763  return true;
3764 }
3765 #endif
3766 
3767 Device *Traits::factory(const Configuration &configuration, const FactoryBlock &factory_block)
3768 {
3769 
3770  return new Master(configuration, factory_block, factory_block.solverState_, factory_block.deviceOptions_);
3771 }
3772 
3774 {
3776  .registerDevice("m", 3)
3777  .registerModelType("pmos", 3)
3778  .registerModelType("nmos", 3);
3779 }
3780 
3781 } // namespace MOSFET3
3782 } // namespace Device
3783 } // namespace Xyce