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