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