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