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.79.2.3 $
40 //
41 // Revision Date : $Date: 2014/03/06 23:33:43 $
42 //
43 // Current Owner : $Author: tvrusso $
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  // set up the internal name map:
836  std::string tmpstr;
837  if ( li_DrainPrime != li_Drain )
838  {
839  tmpstr = getName()+"_drainprime";
840  spiceInternalName (tmpstr);
841  intNameMap[ li_DrainPrime ] = tmpstr;
842  }
843 
844  if ( li_SourcePrime != li_Source )
845  {
846  tmpstr = getName()+"_sourceprime";
847  spiceInternalName (tmpstr);
848  intNameMap[ li_SourcePrime ] = tmpstr;
849  }
850  }
851 
852  return intNameMap;
853 }
854 
855 //-----------------------------------------------------------------------------
856 // Function : N_DEV_MOSFET6Instance::getStoreNameMap
857 // Purpose :
858 // Special Notes :
859 // Scope : public
860 // Creator : Richard Schiek, Electrical Systems Modeling
861 // Creation Date : 4/3/2013
862 //-----------------------------------------------------------------------------
863 std::map<int,std::string> & N_DEV_MOSFET6Instance::getStoreNameMap ()
864 {
865  // set up the internal name map, if it hasn't been already.
866  if( loadLeadCurrent && storeNameMap.empty ())
867  {
868  // change subcircuitname:devicetype_deviceName to
869  // devicetype:subcircuitName:deviceName
870  std::string modName(getName());
871  spiceInternalName(modName);
872  std::string tmpstr;
873  tmpstr = modName+":DEV_ID";
874  storeNameMap[ li_store_dev_id ] = tmpstr;
875  tmpstr = modName+":DEV_IG";
876  storeNameMap[ li_store_dev_ig ] = tmpstr;
877  tmpstr = modName+":DEV_IS";
878  storeNameMap[ li_store_dev_is ] = tmpstr;
879  tmpstr = modName+":DEV_IB";
880  storeNameMap[ li_store_dev_ib ] = tmpstr;
881  }
882 
883  return storeNameMap;
884 }
885 
886 //-----------------------------------------------------------------------------
887 // Function : Instance::registerStateLIDs
888 // Purpose :
889 // Special Notes :
890 // Scope : public
891 // Creator : Robert Hoekstra, Computational Sciences
892 // Creation Date : 6/21/02
893 //-----------------------------------------------------------------------------
894 void Instance::registerStateLIDs( const std::vector<int> & staLIDVecRef )
895 {
896  AssertLIDs(staLIDVecRef.size() == numStateVars);
897 
898 #ifdef Xyce_DEBUG_DEVICE
899  if (getDeviceOptions().debugLevel > 0)
900  {
901  Xyce::dout() << std::endl;
902  Xyce::dout() << section_divider << std::endl;
903  Xyce::dout() << " In Instance::registerStateLIDs\n\n";
904  Xyce::dout() << " name = " << getName() << std::endl;
905  Xyce::dout() << " Number of State LIDs: " << numStateVars << std::endl;
906  }
907 #endif
908 
909  // Copy over the global ID lists:
910  staLIDVec = staLIDVecRef;
911 
912  int lid=0;
913 
914  li_state_qgs = staLIDVec[lid++];
915  li_state_qgd = staLIDVec[lid++];
916  li_state_qgb = staLIDVec[lid++];
917 
918  li_state_capgs = staLIDVec[lid++];
919  li_state_capgd = staLIDVec[lid++];
920  li_state_capgb = staLIDVec[lid++];
921 
922  li_state_qbd = staLIDVec[lid++];
923  li_state_qbs = staLIDVec[lid++];
924 
925 #ifdef Xyce_DEBUG_DEVICE
926  if (getDeviceOptions().debugLevel > 0)
927  {
928  Xyce::dout() << " State local indices:" << std::endl;
929  Xyce::dout() << std::endl;
930 
931  Xyce::dout() << " li_state_qgs = " << li_state_qgs <<std::endl;
932  Xyce::dout() << " li_state_capgs = " << li_state_capgs<<std::endl;
933  Xyce::dout() << " li_state_capgd = " << li_state_capgd<<std::endl;
934  Xyce::dout() << " li_state_capgb = " << li_state_capgb<<std::endl;
935  Xyce::dout() << " li_state_qgd = " << li_state_qgd<<std::endl;
936  Xyce::dout() << " li_state_qgb = " << li_state_qgb<<std::endl;
937  Xyce::dout() << " li_state_qbs = " << li_state_qbs<<std::endl;
938  Xyce::dout() << " li_state_qbd = " << li_state_qbd<<std::endl;
939  Xyce::dout() << std::endl;
940  Xyce::dout() << section_divider << std::endl;
941  }
942 #endif
943 }
944 
945 
946 //-----------------------------------------------------------------------------
947 // Function : Instance::registerStoreLIDs
948 // Purpose :
949 // Special Notes :
950 // Scope : public
951 // Creator : Robert Hoekstra, Computational Sciences
952 // Creation Date : 12/11/11
953 //-----------------------------------------------------------------------------
954 void Instance::registerStoreLIDs( const std::vector<int> & stoLIDVecRef )
955 {
956  AssertLIDs(stoLIDVecRef.size() == getNumStoreVars());
957 
958  // Copy over the global ID lists:
959  stoLIDVec = stoLIDVecRef;
960 
961  int lid=0;
962  li_store_vbd = stoLIDVec[lid++];
963  li_store_vbs = stoLIDVec[lid++];
964  li_store_vgs = stoLIDVec[lid++];
965  li_store_vds = stoLIDVec[lid++];
966  li_store_von = stoLIDVec[lid++];
967 
968  if( loadLeadCurrent )
969  {
970  li_store_dev_id = stoLIDVec[lid++];
971  li_store_dev_ig = stoLIDVec[lid++];
972  li_store_dev_is = stoLIDVec[lid++];
973  li_store_dev_ib = stoLIDVec[lid++];
974  }
975 }
976 
977 //-----------------------------------------------------------------------------
978 // Function : Instance::jacobianStamp
979 // Purpose :
980 // Special Notes :
981 // Scope : public
982 // Creator : Robert Hoekstra, Computational Sciences
983 // Creation Date : 9/3/02
984 //-----------------------------------------------------------------------------
985 const std::vector< std::vector<int> > & Instance::jacobianStamp() const
986 {
987  if( drainConductance != 0.0 && sourceConductance != 0.0 )
988  return jacStamp_DC_SC;
989  else if( drainConductance != 0.0 && sourceConductance == 0.0 )
990  return jacStamp_DC;
991  else if( drainConductance == 0.0 && sourceConductance != 0.0 )
992  return jacStamp_SC;
993 
994  return jacStamp;
995 }
996 
997 //-----------------------------------------------------------------------------
998 // Function : Instance::registerJacLIDs
999 // Purpose :
1000 // Special Notes :
1001 // Scope : public
1002 // Creator : Robert Hoekstra, Computational Sciences
1003 // Creation Date : 9/3/02
1004 //-----------------------------------------------------------------------------
1005 void Instance::registerJacLIDs( const std::vector< std::vector<int> > & jacLIDVec )
1006 {
1007  DeviceInstance::registerJacLIDs( jacLIDVec );
1008  std::vector<int> map;
1009  std::vector< std::vector<int> > map2;
1010 
1011  if (drainConductance != 0.0)
1012  {
1013  if (sourceConductance != 0.0)
1014  {
1015  map = jacMap_DC_SC;
1016  map2 = jacMap2_DC_SC;
1017  }
1018  else
1019  {
1020  map = jacMap_DC;
1021  map2 = jacMap2_DC;
1022  }
1023  }
1024  else
1025  {
1026  if (sourceConductance != 0.0)
1027  {
1028  map = jacMap_SC;
1029  map2 = jacMap2_SC;
1030  }
1031  else
1032  {
1033  map = jacMap;
1034  map2 = jacMap2;
1035  }
1036  }
1037  ADrainEquDrainNodeOffset = jacLIDVec[map[0]][map2[0][0]];
1038  ADrainEquDrainPrimeNodeOffset = jacLIDVec[map[0]][map2[0][1]];
1039 
1040  AGateEquGateNodeOffset = jacLIDVec[map[1]][map2[1][0]];
1041  AGateEquBulkNodeOffset = jacLIDVec[map[1]][map2[1][1]];
1042  AGateEquDrainPrimeNodeOffset = jacLIDVec[map[1]][map2[1][2]];
1043  AGateEquSourcePrimeNodeOffset = jacLIDVec[map[1]][map2[1][3]];
1044 
1045  ASourceEquSourceNodeOffset = jacLIDVec[map[2]][map2[2][0]];
1046  ASourceEquSourcePrimeNodeOffset = jacLIDVec[map[2]][map2[2][1]];
1047 
1048  ABulkEquGateNodeOffset = jacLIDVec[map[3]][map2[3][0]];
1049  ABulkEquBulkNodeOffset = jacLIDVec[map[3]][map2[3][1]];
1050  ABulkEquDrainPrimeNodeOffset = jacLIDVec[map[3]][map2[3][2]];
1051  ABulkEquSourcePrimeNodeOffset = jacLIDVec[map[3]][map2[3][3]];
1052 
1053  ADrainPrimeEquDrainNodeOffset = jacLIDVec[map[4]][map2[4][0]];
1054  ADrainPrimeEquGateNodeOffset = jacLIDVec[map[4]][map2[4][1]];
1055  ADrainPrimeEquBulkNodeOffset = jacLIDVec[map[4]][map2[4][2]];
1056  ADrainPrimeEquDrainPrimeNodeOffset = jacLIDVec[map[4]][map2[4][3]];
1057  ADrainPrimeEquSourcePrimeNodeOffset = jacLIDVec[map[4]][map2[4][4]];
1058 
1059  ASourcePrimeEquGateNodeOffset = jacLIDVec[map[5]][map2[5][0]];
1060  ASourcePrimeEquSourceNodeOffset = jacLIDVec[map[5]][map2[5][1]];
1061  ASourcePrimeEquBulkNodeOffset = jacLIDVec[map[5]][map2[5][2]];
1062  ASourcePrimeEquDrainPrimeNodeOffset = jacLIDVec[map[5]][map2[5][3]];
1063  ASourcePrimeEquSourcePrimeNodeOffset = jacLIDVec[map[5]][map2[5][4]];
1064 }
1065 
1066 
1067 //-----------------------------------------------------------------------------
1068 // Function : Instance::setupPointers
1069 // Purpose :
1070 // Special Notes :
1071 // Scope : public
1072 // Creator : Eric Keiter, SNL
1073 // Creation Date : 12/06/08
1074 //-----------------------------------------------------------------------------
1076 {
1077 #ifndef Xyce_NONPOINTER_MATRIX_LOAD
1078  N_LAS_Matrix & dFdx = *(extData.dFdxMatrixPtr);
1079  N_LAS_Matrix & dQdx = *(extData.dQdxMatrixPtr);
1080 
1081  // F-pointers:
1084 
1089 
1092 
1097 
1103 
1109 
1110  // Q-pointers:
1113 
1118 
1121 
1126 
1132 
1138 #endif
1139 }
1140 
1141 //-----------------------------------------------------------------------------
1142 // Function : Instance::loadDAEQVector
1143 //
1144 // Purpose : Loads the Q-vector contributions for a single
1145 // diode instance.
1146 //
1147 // Special Notes : The "Q" vector is part of a standard DAE formalism in
1148 // which the system of equations is represented as:
1149 //
1150 // f(x) = dQ(x)/dt + F(x) - B(t) = 0
1151 //
1152 // Scope : public
1153 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1154 // Creation Date : 03/06/04
1155 //-----------------------------------------------------------------------------
1157 {
1158  double * qVec = extData.daeQVectorRawPtr;
1159 
1160  double coef(0.0);
1161 
1162  double Qeqbs(0.0),Qeqbd(0.0),Qeqgb(0.0), Qeqgs(0.0), Qeqgd(0.0);
1163  //double ceqbs,ceqbd,ceqgb, ceqgs, ceqgd; // 3f5 vars
1164  int Dtype=model_.dtype;
1165 
1166  // do the same Dtype corrections on the charges that
1167  // are performed on the currents in the loadRHS function.
1168 
1169  // What is cbs and cbd? They are diode currents (from exponentials),
1170  // so they are left out of this function.
1171  Qeqbs = Dtype*(qbs);
1172  Qeqbd = Dtype*(qbd);
1173  // These need "Dtype" here because we use them later *without*
1174  // Dtype, where SPICE uses it *with*
1175  Qeqgb = Dtype*(qgb);
1176  Qeqgs = Dtype*(qgs);
1177  Qeqgd = Dtype*(qgd);
1178 
1179  // 2 KCL for gate node
1180  coef = (Qeqgs+Qeqgd+Qeqgb);
1181  qVec[li_Gate] += coef*numberParallel;
1182 
1183  // 4 KCL for bulk node
1184  coef = Qeqbs + Qeqbd - Qeqgb;
1185  qVec[li_Bulk] += coef*numberParallel;
1186 
1187  // 5 KCL for drain' node
1188  coef = -(Qeqbd + Qeqgd);
1189  qVec[li_DrainPrime] += coef*numberParallel;
1190 
1191  // 6 KCL for source' node
1192  coef = -(Qeqbs + Qeqgs);
1193  qVec[li_SourcePrime] += coef*numberParallel;
1194 
1195  if( loadLeadCurrent )
1196  {
1197  double * storeLeadQ = extData.storeLeadCurrQCompRawPtr;
1198  if (drainConductance == 0.0)
1199  {
1200  storeLeadQ[li_store_dev_id] = (-(Qeqbd + Qeqgd))*numberParallel;
1201  }
1202  if (sourceConductance == 0.0)
1203  {
1204  storeLeadQ[li_store_dev_is] = (-(Qeqbs + Qeqgs))*numberParallel;
1205  }
1206  storeLeadQ[li_store_dev_ig] = (Qeqgs+Qeqgd+Qeqgb)*numberParallel;
1207  storeLeadQ[li_store_dev_ib] = (Qeqbs + Qeqbd - Qeqgb)*numberParallel;
1208  }
1209 
1210  // Same as for the loadRHS function, but with capacitive terms:
1211  // gcgd = Capgd;
1212  // gcgs = Capgs;
1213  // gcgb = Capgb;
1214  // gcbs = capbs;
1215  // gcbd = capbd;
1216  if(!origFlag)
1217  {
1218  // THe setup of gcgd, etc. is the same as in the loadDAEdQdxVector
1219  // function.
1220  double gcgd, gcgs, gcgb, gcbs, gcbd;
1222  {
1223  gcgd = Capgd;
1224  gcgs = Capgs;
1225  gcgb = Capgb;
1226  // get at the two parasitic caps the same way
1227  gcbs = capbs;
1228  gcbd = capbd;
1229  }
1230  else
1231  {
1232  gcgd = 0.0; gcgs = 0.0; gcgb = 0.0; gcbs = 0.0; gcbd = 0.0;
1233  }
1234 
1235  // KCL 2
1236  double coef_Jdxp2 = Dtype*(gcgd*(vgd-vgd_orig)+gcgs*(vgs-vgs_orig)+
1237  gcgb*(vgs-vgs_orig-vbs+vbs_orig));
1238 
1239  // 4 KCL for bulk node
1240  double coef_Jdxp4 = Dtype*(
1241  - (gcgb)*(vgs-vgs_orig-vbs+vbs_orig)
1242  + (gcgb)*(vbd-vbd_orig)
1243  + (gcbs)*(vbs-vbs_orig));
1244 
1245  // 5 KCL for drain' node
1246  double coef_Jdxp5 = Dtype*(
1247  -(gcgd)*(vgd-vgd_orig)
1248  -(gcbd)*(vbd-vbd_orig));
1249 
1250  // 6 KCL for source' node
1251  double coef_Jdxp6 = Dtype*(-gcgs*(vgs-vgs_orig)-(gcbs)*(vbs-vbs_orig));
1252 
1253  double * dQdxdVp = extData.dQdxdVpVectorRawPtr;
1254  dQdxdVp[li_Gate ] += coef_Jdxp2*numberParallel;
1255  dQdxdVp[li_Bulk ] += coef_Jdxp4*numberParallel;
1256  dQdxdVp[li_DrainPrime ] += coef_Jdxp5*numberParallel;
1257  dQdxdVp[li_SourcePrime] += coef_Jdxp6*numberParallel;
1258  }
1259 
1260  return true;
1261 }
1262 
1263 //-----------------------------------------------------------------------------
1264 // Function : Instance::loadDAEFVector
1265 //
1266 // Purpose : Loads the F-vector contributions for a single
1267 // diode instance.
1268 //
1269 // Special Notes :
1270 //
1271 // Scope : public
1272 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1273 // Creation Date : 03/06/04
1274 //-----------------------------------------------------------------------------
1276 {
1277  double * fVec = extData.daeFVectorRawPtr;
1278  double coef(0.0);
1279  double ceqbs(0.0),ceqbd(0.0),ceqgb(0.0), ceqgs(0.0), ceqgd(0.0); // 3f5 vars
1280  double gmin1 = getDeviceOptions().gmin;
1281 
1282  int Dtype=model_.dtype;
1283 
1284  // The next few lines are the same as for loadRHS, except
1285  // the capcitor current terms have been set to zero here.
1286  ceqbs = Dtype*(cbs);
1287  ceqbd = Dtype*(cbd);
1288  // These need "Dtype" here because we use them later *without*
1289  // Dtype, where SPICE uses it *with*
1290  ceqgb = 0.0;
1291  ceqgs = 0.0;
1292  ceqgd = 0.0;
1293 
1294  // 1 KCL for drain node
1295  if (drainConductance != 0.0)
1296  {
1297  coef = Idrain;
1298  fVec[li_Drain] += coef*numberParallel;
1299  }
1300 
1301  // 2 KCL for gate node
1302  coef = (ceqgs+ceqgd+ceqgb);
1303  fVec[li_Gate] += coef*numberParallel;
1304 
1305  // 3 KCL for source node
1306  if (sourceConductance != 0.0)
1307  {
1308  coef = Isource;
1309  fVec[li_Source] += coef*numberParallel;
1310  }
1311 
1312  // 4 KCL for bulk node
1313  coef = ceqbs + ceqbd - ceqgb;
1314  fVec[li_Bulk] += coef*numberParallel;
1315 
1316  // 5 KCL for drain' node
1317  coef = -Idrain-(ceqbd - cdreq + ceqgd);
1318  fVec[li_DrainPrime] += coef*numberParallel;
1319 
1320  // 6 KCL for source' node
1321  coef = -Isource-(ceqbs + cdreq + ceqgs);
1322  fVec[li_SourcePrime] += coef*numberParallel;
1323 
1324  // Same as for the loadRHS function, but without capacitive terms:
1325  // gcgd = Capgd;
1326  // gcgs = Capgs;
1327  // gcgb = Capgb;
1328  // gcbs = capbs;
1329  // gcbd = capbd;
1330  if (!origFlag)
1331  {
1332  // 4 KCL for bulk node
1333  double coef_Jdxp4 = Dtype*(
1334  + ((gbd-gmin1))*(vbd-vbd_orig)
1335  + ((gbs-gmin1))*(vbs-vbs_orig));
1336 
1337  // 5 KCL for drain' node
1338  double coef_Jdxp5 = Dtype*(
1339  -((gbd-gmin1))*(vbd-vbd_orig)
1340  +gds*(vds-vds_orig)
1341  +Gm*((mode>0)?(vgs-vgs_orig):(vgd-vgd_orig))
1342  +Gmbs*((mode>0)?(vbs-vbs_orig):(vbd-vbd_orig)));
1343 
1344  // 6 KCL for source' node
1345  double coef_Jdxp6 = Dtype*(
1346  -((gbs-gmin1))*(vbs-vbs_orig)
1347  -gds*(vds-vds_orig)
1348  -Gm*((mode>0)?(vgs-vgs_orig):(vgd-vgd_orig))
1349  -Gmbs*((mode>0)?(vbs-vbs_orig):(vbd-vbd_orig)));
1350 
1351  double * dFdxdVp = extData.dFdxdVpVectorRawPtr;
1352  dFdxdVp[li_Bulk ] += coef_Jdxp4*numberParallel;
1353  dFdxdVp[li_DrainPrime ] += coef_Jdxp5*numberParallel;
1354  dFdxdVp[li_SourcePrime] += coef_Jdxp6*numberParallel;
1355  }
1356 
1357  if( loadLeadCurrent )
1358  {
1359  double * storeLeadF = extData.nextStoVectorRawPtr;
1360  if (drainConductance != 0.0)
1361  {
1362  storeLeadF[li_store_dev_id] = Idrain*numberParallel;
1363  }
1364  else
1365  {
1366  storeLeadF[li_store_dev_id] = (-Idrain-(ceqbd - cdreq + ceqgd))*numberParallel;
1367  }
1368  if (sourceConductance != 0.0)
1369  {
1370  storeLeadF[li_store_dev_is] = Isource*numberParallel;
1371  }
1372  else
1373  {
1374  storeLeadF[li_store_dev_is] = (-Isource-(ceqbs + cdreq + ceqgs))*numberParallel;
1375  }
1376  storeLeadF[li_store_dev_ig] = (ceqgs+ceqgd+ceqgb)*numberParallel;
1377  storeLeadF[li_store_dev_ib] = (ceqbs + ceqbd - ceqgb)*numberParallel;
1378  }
1379 
1380  return true;
1381 }
1382 
1383 //-----------------------------------------------------------------------------
1384 // Function : Instance::loadDAEdQdx
1385 //
1386 // Purpose : Loads the Q-vector contributions for a single
1387 // diode instance.
1388 //
1389 // Special Notes : The "Q" vector is part of a standard DAE formalism in
1390 // which the system of equations is represented as:
1391 //
1392 // f(x) = dQ(x)/dt + F(x) - B(t) = 0
1393 //
1394 // Scope : public
1395 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1396 // Creation Date : 03/06/04
1397 //-----------------------------------------------------------------------------
1399 {
1400  N_LAS_Matrix & dQdx = *(extData.dQdxMatrixPtr);
1401 
1402  double gcgd(0.0); // d(cqgd)/dVgd
1403  double gcgs(0.0); // d(cqgs)/dVgs
1404  double gcgb(0.0); // d(cqgb)/dVgb
1405  double gcbs(0.0); // d(cqbs)/dVbs
1406  double gcbd(0.0); // d(cqbd)/dVbd
1407 
1408  // get at the "conductances" for the gate capacitors with this trick
1409  // gcgd = model_.dtype*Capgd;
1410  // gcgs = model_.dtype*Capgs;
1411  // gcgb = model_.dtype*Capgb;
1412  //
1413  // In the loadRHS function, these would all be multiplied by
1414  // getSolverState().pdt. Here, for dQdx, the pdt term is left out.
1415  if (getSolverState().tranopFlag || getSolverState().acopFlag || getSolverState().transientFlag)
1416  {
1417  gcgd = Capgd;
1418  gcgs = Capgs;
1419  gcgb = Capgb;
1420  // get at the two parasitic caps the same way
1421  gcbs = capbs;
1422  gcbd = capbd;
1423  }
1424 
1425  dQdx[li_Gate][AGateEquGateNodeOffset] += (gcgd+gcgs+gcgb)
1426  *numberParallel;
1430 
1432  dQdx[li_Bulk][ABulkEquBulkNodeOffset] += +(gcbs+gcbd+gcgb)
1433  *numberParallel;
1436 
1438  -gcgd*numberParallel;
1440  -gcbd*numberParallel;
1442  +(gcbd+gcgd)*numberParallel;
1443 
1445  gcgs*numberParallel;
1447  +gcbs*numberParallel;
1449  +(gcbs+gcgs)*numberParallel;
1450 
1451  return true;
1452 }
1453 
1454 //-----------------------------------------------------------------------------
1455 // Function : Instance::loadDAEdFdx ()
1456 //
1457 // Purpose : Loads the F-vector contributions for a single
1458 // diode instance.
1459 //
1460 // Special Notes :
1461 //
1462 // Scope : public
1463 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1464 // Creation Date : 03/06/04
1465 //-----------------------------------------------------------------------------
1467 {
1468  N_LAS_Matrix & dFdx = *(extData.dFdxMatrixPtr);
1469 
1474 
1479 
1481  (gbs+gbd)*numberParallel;
1484 
1490  (-gbd+Gmbs)*numberParallel;
1492  (drainConductance+gds+gbd+revsum)*numberParallel;
1494  (-gds-nrmsum)*numberParallel;
1495 
1501  (gbs+Gmbs)*numberParallel;
1503  (gds+revsum)*numberParallel;
1505  (sourceConductance+gds+gbs+nrmsum)*numberParallel;
1506 
1507  return true;
1508 }
1509 
1510 //-----------------------------------------------------------------------------
1511 // Function : Instance::updateIntermediateVars
1512 // Purpose :
1513 // Special Notes :
1514 // Scope : public
1515 // Creator : Tom Russo
1516 // Creation Date : 03/01/01
1517 //-----------------------------------------------------------------------------
1519 {
1520  bool bsuccess = true;
1521 
1522  // 3f5 likes to use the same variable names in local variables and in
1523  // structures. Messes with us! Define some local versions with capitals
1524  // instead
1525  double Von(0.0);
1526  double Vdsat(0.0);
1527  double betac(0.0);
1528  //
1529  double evbs(0.0);
1530  double evbd(0.0);
1531  double sarg(0.0);
1532  double sargsw(0.0);
1533  // double vgs1;
1534  // double vgd1;
1535  // double vgb1;
1536  double arg(0.0);
1537  int Check = 1;
1538 
1539  double capgs_old(0.0);
1540  double capgd_old(0.0);
1541  double capgb_old(0.0);
1542 
1543  // temporary storage for vgs/vgd/vds so that homotopy doesn't impact
1544  // voltage limiting "jdxp" terms
1545 
1546  double vgs_save(0.0);
1547  double vgd_save(0.0);
1548  double vds_save(0.0);
1549 
1550  // This is one of the vars that are set up at the top of mos6load that
1551  // should *not* be moved to the instance constructor! tTransconductance
1552  // is set by updateTemperature. Perhaps I should remove it from the
1553  // instance variables, too, since now it's pretty much a local thing.
1554  // same goes for the other things that depend on the t* variables!
1555 
1556  if( (tSatCurDens == 0) || (drainArea == 0) || (sourceArea == 0))
1557  {
1558  DrainSatCur = tSatCur;
1560  }
1561  else
1562  {
1565  }
1566  betac = tKc * w/EffectiveLength;
1567 
1568  // don't do this anymore, use the one from the manager
1569  // newtonIter = nlsMgrPtr->getNonLinearIter ();
1570 
1571  // we need our solution variables for any of this stuff
1578 
1579  // now we need voltage drops
1580  Vddp = Vd - Vdp;
1581  Vssp = Vs - Vsp;
1582  Vbsp = Vb - Vsp;
1583  Vbdp = Vb - Vdp;
1584  Vgsp = Vg - Vsp;
1585  Vgdp = Vg - Vdp;
1586  Vgb = Vg - Vb;
1587  Vdpsp = Vdp - Vsp;
1588 
1589 
1590  // Now the things that the 3f5 code really uses (from mos6load's
1591  // "general iteration" part at lines 276-295
1592  vbs = model_.dtype * Vbsp;
1593  vgs = model_.dtype * Vgsp;
1594  vds = model_.dtype * Vdpsp;
1595 
1596  vbd = vbs-vds;
1597  vgd = vgs-vds;
1598 
1599  origFlag = 1;
1600  limitedFlag = false;
1601  vgs_orig = vgs;
1602  vds_orig = vds;
1603  vbs_orig = vbs;
1604  vbd_orig = vbd;
1605  vgd_orig = vgd;
1606 
1608  {
1609  if (IC_GIVEN)
1610  {
1611  vds = model_.dtype*icVDS;
1612  vgs = model_.dtype*icVGS;
1613  vbs = model_.dtype*icVBS;
1614  vbd = vbs - vds;
1615  vgd = vgs - vds;
1616  origFlag = false;
1617  }
1618  else
1619  {
1621  {
1622  N_LAS_Vector * flagSolVectorPtr = extData.flagSolVectorPtr;
1623  if ((*flagSolVectorPtr)[li_Drain] == 0 || (*flagSolVectorPtr)[li_Gate] == 0 ||
1624  (*flagSolVectorPtr)[li_Source] == 0 || (*flagSolVectorPtr)[li_SourcePrime] ||
1625  (*flagSolVectorPtr)[li_DrainPrime] || (*flagSolVectorPtr)[li_Bulk] )
1626  {
1627  vbs = -1;
1628  vgs = model_.dtype*tVto;
1629  vds = 0;
1630  vbd = vbs-vds;
1631  vgd = vgs-vds;
1632  }
1633  }
1634  else
1635  {
1636  vbs = -1;
1637  vgs = model_.dtype*tVto;
1638  vds = 0;
1639  vbd = vbs-vds;
1640  vgd = vgs-vds;
1641  }
1642  }
1643  }
1644  else if ((getSolverState().initFixFlag || getSolverState().initJctFlag) && OFF)
1645  {
1646  vbs = vgs = vds = 0;
1647  vbd = vgd = 0;
1648  }
1649 
1650  if (getSolverState().newtonIter == 0)
1651  {
1652 
1654  {
1659  Von = model_.dtype *
1661  }
1662  else
1663  { // otherwise there is no history
1664  vbs_old = vbs;
1665  vbd_old = vbd;
1666  vgs_old = vgs;
1667  vds_old = vds;
1668  Von = 0.0;
1669  }
1671  }
1672  else
1673  {
1678  Von = model_.dtype *
1681  }
1682 
1683  ////////////////////////////////////////////
1684  // SPICE-type Voltage Limiting
1685  ////////////////////////////////////////////
1687  {
1688 
1689 #ifdef Xyce_DEBUG_DEVICE
1691  {
1692  Xyce::dout() << " checking whether to limit voltages "<< std::endl;
1693  Xyce::dout() << " Von = " << Von << std::endl;
1694  Xyce::dout() << " Blim: vgd = " << vgd << " vgd old = " << vgd_old << std::endl;
1695  Xyce::dout() << " Blim: vgs = " << vgs << " vgs_old = " << vgs_old << std::endl;
1696  Xyce::dout() << " Blim: vds = " << vds << " vds_old = " << vds_old << std::endl;
1697  Xyce::dout() << " Blim: vbs = " << vbs << " vbs_old = " << vbs_old << std::endl;
1698  Xyce::dout() << " Blim: vbd = " << vbd << " vbd_old = " << vbd_old << std::endl;
1699  }
1700 #endif
1701 
1702  // Do not do limiting if mode initfix and OFF:
1703  if (! (getSolverState().initFixFlag && OFF))
1704  {
1705  if (vds_old >= 0)
1706  {
1707  vgs = devSupport.fetlim( vgs, vgs_old, Von);
1708  vds = vgs - vgd;
1709  vds = devSupport.limvds( vds, vds_old);
1710  vgd = vgs - vds;
1711  }
1712  else
1713  {
1714  vgd = devSupport.fetlim( vgd, vgd_old, Von);
1715  vds = vgs - vgd;
1716  vds = -devSupport.limvds( -vds, -vds_old );
1717  vgs = vgd + vds;
1718  }
1719 
1720  if (vds >= 0.0)
1721  {
1722  vbs = devSupport.pnjlim( vbs, vbs_old, vt, sourceVcrit, &Check);
1723  vbd = vbs - vds;
1724  }
1725  else
1726  {
1727  vbd = devSupport.pnjlim( vbd, vbd_old, vt, drainVcrit, &Check);
1728  vbs = vbd + vds;
1729  }
1730 
1731  // for convergence:
1732  if (Check == 1) limitedFlag=true;
1733 
1734  }
1735 
1736 #ifdef Xyce_DEBUG_DEVICE
1737  if (getDeviceOptions().debugLevel > 0 && getSolverState().debugTimeFlag)
1738  {
1739  Xyce::dout() << " Alim: vgd = " << vgd << std::endl;
1740  Xyce::dout() << " Alim: vgs = " << vgs << std::endl;
1741  Xyce::dout() << " Alim: vds = " << vds << std::endl;
1742  Xyce::dout() << " Alim: vbs = " << vbs << std::endl;
1743  Xyce::dout() << " Alim: vbd = " << vbd << std::endl;
1744  }
1745 #endif
1746  }
1747 
1748  ////
1749  // now all the preliminaries are over - we can start doing the
1750  // real work
1751  ////
1752  vbd = vbs - vds;
1753  vgd = vgs - vds;
1754  Vgb = vgs - vbs;
1755 
1756  // Now set the origFlag
1757  if (vgs_orig != vgs || vds_orig != vds ||
1758  vbs_orig != vbs || vbd_orig != vbd || vgd_orig != vgd) origFlag = 0;
1759 
1760 #ifdef Xyce_DEBUG_DEVICE
1761  if (getDeviceOptions().debugLevel > 0 && getSolverState().debugTimeFlag)
1762  {
1763  if (origFlag == 0)
1764  {
1765  Xyce::dout() << " Something modified the voltages. " << std::endl;
1766  Xyce::dout() << " Voltage before after diff " << std::endl;
1767  Xyce::dout() << " vgs " << vgs_orig << " " << vgs << " " << vgs-vgs_orig << std::endl;
1768  Xyce::dout() << " vds " << vds_orig << " " << vds << " " << vds-vds_orig << std::endl;
1769  Xyce::dout() << " vbs " << vbs_orig << " " << vbs << " " << vbs-vbs_orig << std::endl;
1770  Xyce::dout() << " vbd " << vbd_orig << " " << vbd << " " << vbd-vbd_orig << std::endl;
1771  Xyce::dout() << " vgd " << vgd_orig << " " << vgd << " " << vgd-vgd_orig << std::endl;
1772  }
1773  }
1774 #endif
1775 
1776 
1777  ////
1778  // bulk-source and bulk-drain diodes
1779  // here we just evaluate the ideal diode current and the
1780  // corresponding derivative (conductance).
1781  ////
1782  if(vbs <= 0)
1783  {
1784  gbs = SourceSatCur/vt;
1785  gbs += getDeviceOptions().gmin;
1786  cbs = gbs*vbs;
1787  }
1788  else
1789  {
1790  evbs = exp(Xycemin(CONSTMAX_EXP_ARG,vbs/vt));
1791  gbs = (SourceSatCur*evbs/vt + getDeviceOptions().gmin);
1792  cbs = (SourceSatCur * (evbs-1) + getDeviceOptions().gmin*vbs);
1793  }
1794  if(vbd <= 0)
1795  {
1796  gbd = DrainSatCur/vt;
1797  gbd += getDeviceOptions().gmin;
1798  cbd = gbd *vbd;
1799  }
1800  else
1801  {
1802  evbd = exp(Xycemin(CONSTMAX_EXP_ARG,vbd/vt));
1803  gbd = (DrainSatCur*evbd/vt + getDeviceOptions().gmin);
1804  cbd = (DrainSatCur *(evbd-1) + getDeviceOptions().gmin*vbd);
1805  }
1806 
1807  // 3f5 does this simple stuff
1808  if (vds >= 0)
1809  mode = 1;
1810  else
1811  mode = -1;
1812 
1813  {
1814  // this block of code evaluates the drain current and its
1815  // derivatives using the n-th power MOS model and the
1816  // charges associated with the gate, channel and bulk for
1817  // mosfets
1818 
1819  double arg;
1820  double sarg;
1821  double vgon;
1822  double vdshere, vbsvbd;
1823  double idsat, lambda, vonbm;
1824  double vdst, vdst2, ivdst1, vdstg;
1825 
1826 
1827  // Begin block of mosfet continuation code.
1828  // This idea is based, loosely, on a paper by Jaijeet
1829  // Roychowdhury.
1830 
1831  // Save these before allowing homotopy to tweak them. It
1832  // is important to restore them before moving on to
1833  // calculate RHS, because then the Jdxp terms will attempt to force
1834  // the external circuit to make these voltage drops the real thing!
1835  vds_save=vds;
1836  vgs_save=vgs;
1837  vgd_save=vgd;
1838 
1840  {
1841  double alpha = getSolverState().gainScale[blockHomotopyID];
1842  if (getDeviceOptions().staggerGainScale)
1843  {
1844  alpha *= (0.3 * randomPerturb + 1.0);
1845  if (alpha > 1.0)
1846  {
1847  alpha = 1.0;
1848  }
1849  }
1850  double vgstConst = getDeviceOptions().vgstConst;
1851  if (getDeviceOptions().randomizeVgstConst)
1852  {
1853  vgstConst *= randomPerturb;
1854  }
1855 
1856  vds = devSupport.contVds (vds, getSolverState().nltermScale, getDeviceOptions().vdsScaleMin);
1857 
1858  if (mode==1)
1859  {
1860  vgs = devSupport.contVgst (vgs, alpha, vgstConst);
1861  }
1862  else
1863  {
1864  vgd = devSupport.contVgst (vgd, alpha, vgstConst);
1865  }
1866  }
1867  // End of block of mosfet continuation code.
1868 
1869  vbsvbd = (mode==1?vbs:vbd);
1870  if (vbsvbd <= 0 )
1871  {
1872  sarg = sqrt(tPhi - vbsvbd);
1873  }
1874  else
1875  {
1876  sarg = sqrt(tPhi);
1877  sarg = sarg - vbsvbd / (sarg+sarg);
1878  sarg = Xycemax (0.0,sarg);
1879  }
1880 
1881  vdshere = vds * mode;
1882  Von=(tVbi*model_.dtype)+model_.gamma*sarg
1883  - model_.gamma1 * vbsvbd;
1884  - model_.sigma * vdshere;
1885  vgon = (mode==1?vgs:vgd) - Von;
1886 
1887  if (vgon <= 0)
1888  {
1889  // cutoff region
1890  vdsat = 0;
1891  cdrain=0;
1892  gm=0;
1893  gds=0;
1894  gmbs=0;
1895  }
1896  else
1897  {
1898  if (sarg <= 0)
1899  {
1900  arg=0;
1901  }
1902  else
1903  {
1904  if ((mode==1?vbs:vbd) <= 0 )
1905  {
1906  vonbm = model_.gamma1 + model_.gamma / (sarg + sarg);
1907  }
1908  else
1909  {
1910  vonbm = model_.gamma1 + model_.gamma / 2 / sqrt(tPhi);
1911  }
1912  }
1913  sarg = log(vgon);
1914  vdsat = model_.kv * exp(sarg * model_.nv);
1915  idsat = betac * exp(sarg * model_.nc);
1916  lambda = model_.lambda0 - model_.lambda1 * vbsvbd;
1917 
1918  // saturation region
1919  cdrain = idsat * (1 + lambda * vdshere);
1920  gm = cdrain * model_.nc / vgon;
1921  gds = gm * model_.sigma
1922  + idsat * lambda;
1923 
1924  gmbs = gm * vonbm - idsat * model_.lambda1 * vdshere;
1925 
1926  if (vdsat > vdshere)
1927  {
1928  // linear region
1929  vdst = vdshere / vdsat;
1930  vdst2 = (2 - vdst) * vdst;
1931  vdstg = - vdst * model_.nv / vgon;
1932  ivdst1 = cdrain * (2 - vdst - vdst);
1933  cdrain = cdrain * vdst2;
1934  gm = gm * vdst2 + ivdst1 * vdstg;
1935  gds = gds * vdst2 + ivdst1 * (1 / vdsat + vdstg * model_.sigma);
1936  gmbs = gmbs * vdst2 + ivdst1 * vdstg * vonbm;
1937  }
1938 
1939  }
1940 
1941  // finished
1942  }
1943 
1944  // now deal with n vs p polarity
1945 
1946  von = model_.dtype * Von;
1947  vdsat = model_.dtype * Vdsat;
1948 
1949  ////
1950  // * COMPUTE EQUIVALENT DRAIN CURRENT SOURCE
1951  ////
1952 
1953  cd = mode * cdrain - cbd;
1954  // in 3f5 this is all in a block conditioned on CKTmode, but since
1955  // it's valid for MODETRAN and MODETRANOP we'll just always do it
1956 
1957  ////
1958  // * now we do the hard part of the bulk-drain and bulk-source
1959  // * diode - we evaluate the non-linear capacitance and
1960  // * charge
1961  // *
1962  // * the basic equations are not hard, but the implementation
1963  // * is somewhat long in an attempt to avoid log/exponential
1964  // * evaluations
1965  ////
1966  ////
1967  // * charge storage elements
1968  // *
1969  // *.. bulk-drain and bulk-source depletion capacitances
1970  ////
1971  // I took out all the CAPBYPASS stuff, and the
1972  // unnecessary curly braces that wind up there if you do
1973 
1974  // can't bypass the diode capacitance calculations
1975  if(Cbs != 0 || Cbssw != 0 )
1976  {
1977  if (vbs < tDepCap)
1978  {
1979  arg=1-vbs/tBulkPot;
1980  ////
1981  // * the following block looks somewhat long and messy,
1982  // * but since most users use the default grading
1983  // * coefficients of .5, and sqrt is MUCH faster than an
1984  // * exp(log()) we use this special case code to buy time.
1985  // * (as much as 10% of total job time!)
1986  ////
1988  {
1989  if(model_.bulkJctBotGradingCoeff == .5)
1990  {
1991  sarg = sargsw = 1/sqrt(arg);
1992  }
1993  else
1994  {
1995  sarg = sargsw = exp(-model_.bulkJctBotGradingCoeff*log(arg));
1996  }
1997  }
1998  else
1999  {
2000  if(model_.bulkJctBotGradingCoeff == .5)
2001  {
2002  sarg = 1/sqrt(arg);
2003  }
2004  else
2005  {
2006  sarg = exp(-model_.bulkJctBotGradingCoeff*log(arg));
2007  }
2009  {
2010  sargsw = 1/sqrt(arg);
2011  }
2012  else
2013  {
2014  sargsw =exp(-model_.bulkJctSideGradingCoeff* log(arg));
2015  }
2016  }
2017  qbs = tBulkPot*(Cbs*(1-arg*sarg)/(1-model_.bulkJctBotGradingCoeff)
2018  +Cbssw*(1-arg*sargsw)/(1-model_.bulkJctSideGradingCoeff));
2019  capbs=Cbs*sarg+ Cbssw*sargsw;
2020 
2021  }
2022  else
2023  {
2024  qbs = f4s + vbs*(f2s+vbs*(f3s/2));
2025  capbs=f2s+f3s*vbs;
2026  }
2027  }
2028  else
2029  {
2030  qbs = 0;
2031  capbs=0;
2032  }
2033 
2034  //// can't bypass the diode capacitance calculations
2035  if(Cbd != 0 || Cbdsw != 0 )
2036  {
2037 
2038  if (vbd < tDepCap)
2039  {
2040  arg=1-vbd/tBulkPot;
2041  ////
2042  // * the following block looks somewhat long and messy,
2043  // * but since most users use the default grading
2044  // * coefficients of .5, and sqrt is MUCH faster than an
2045  // * exp(log()) we use this special case code to buy time.
2046  // * (as much as 10% of total job time!)
2047  ////
2048  if(model_.bulkJctBotGradingCoeff == .5 &&
2050  {
2051  sarg = sargsw = 1/sqrt(arg);
2052  }
2053  else
2054  {
2055  if(model_.bulkJctBotGradingCoeff == .5)
2056  {
2057  sarg = 1/sqrt(arg);
2058  }
2059  else
2060  {
2061  sarg = exp(-model_.bulkJctBotGradingCoeff*log(arg));
2062  }
2064  {
2065  sargsw = 1/sqrt(arg);
2066  }
2067  else
2068  {
2069  sargsw =exp(-model_.bulkJctSideGradingCoeff*log(arg));
2070  }
2071  }
2072  qbd =
2073  tBulkPot*(Cbd*
2074  (1-arg*sarg)
2076  +Cbdsw*
2077  (1-arg*sargsw)
2079  capbd=Cbd*sarg+
2080  Cbdsw*sargsw;
2081  }
2082  else
2083  {
2084  qbd = f4d +
2085  vbd * (f2d + vbd * f3d/2);
2086  capbd=f2d + vbd * f3d;
2087  }
2088  }
2089  else
2090  {
2091  qbd = 0;
2092  capbd = 0;
2093  }
2094 
2095  // Now after a mess of convergence stuff that seems not to apply to us
2096  // 3f5 saves the vbs, vbd, etc. in the state vector (we don't, it gets
2097  // saved in updatePrimaryState)
2098 
2099  // Then 3f5 calculates meyer capacitances, capgs, capgb and capgd
2100  // Careful! They use the local von and vdsat, which haven't got dtype
2101  // multiplying them!
2102 
2103  ////
2104  // * calculate meyer's capacitors
2105  ////
2106  ////
2107  // * new cmeyer - this just evaluates at the current time,
2108  // * expects you to remember values from previous time
2109  // * returns 1/2 of non-constant portion of capacitance
2110  // * you must add in the other half from previous time
2111  // * and the constant part
2112  ////
2113 
2114  if (mode > 0)
2115  {
2116  devSupport.qmeyer (vgs,vgd,Vgb,Von,Vdsat,
2118  }
2119  else
2120  {
2121  devSupport.qmeyer (vgd,vgs,Vgb,Von,Vdsat,
2123  }
2124 
2125 
2126  // vgs1 = vgs_old;
2127  // vgd1 = vgs1 - vds_old;
2128  // vgb1 = vgs1 - vbs_old;
2129 
2130  ////
2131  // TVR: Note! Caution with Capgs vs. capgs. If I used the instance var
2132  // capgs on the left hand side, it's OK as long as we never try to implement
2133  // meyer back averaging, since capgs is going to be recalculated each
2134  // time through. But if we do the averaging, the old one will have the
2135  // constant part and old old part added in, which is not what we wanted.
2136  // So I'll continue 3f5's way of having a local Capgs that's actually used
2137  // for the charge computation, and an instance capgs that's saved as state.
2138  ////
2139 
2140  if((getSolverState().dcopFlag))
2141  {
2142  Capgs = 2 * capgs + GateSourceOverlapCap ;
2143  Capgd = 2 * capgd + GateDrainOverlapCap ;
2144  Capgb = 2 * capgb + GateBulkOverlapCap ;
2145  }
2146  else
2147  {
2148  capgs_old = (*extData.currStaVectorPtr)[li_state_capgs];
2149  capgd_old = (*extData.currStaVectorPtr)[li_state_capgd];
2150  capgb_old = (*extData.currStaVectorPtr)[li_state_capgb];
2151 
2152  Capgs = ( capgs+
2153  capgs_old +
2155  Capgd = ( capgd+
2156  capgd_old +
2158  Capgb = ( capgb+
2159  capgb_old +
2161  }
2162 
2163  // Eric does this kludge in level 1, so I'll do it to make sure capacitances
2164  // are positive
2165  Capgs *= (Capgs < 0.0)?-1.0:1.0;
2166  Capgd *= (Capgd < 0.0)?-1.0:1.0;
2167  Capgb *= (Capgb < 0.0)?-1.0:1.0;
2168 
2169 
2170  // in the sequel, I'll refer to all derivatives of currents w.r.t. voltages
2171  // as conductances, whether they really are or not.
2172 
2173  // when we get here, cdrain has the channel current
2174  // cbd and cbs have the currents through the diodes
2175  // cd has the drain current minus the diode current and seems only to be used
2176  // for 3f5 convergence stuff
2177  // qbs and qbd have the charges on the parasitic capacitors
2178  // capbs and capbd have the capacitances of the parasitics.
2179 
2180  // none of the charges for the gate capacitors have been calculated yet.
2181  // We've saved the capacitances, so we can get the charges in
2182  // updatePrimaryState later.
2183 
2184  // no currents have been calculated yet.
2185 
2186  // Conductances:
2187  // gbd: the bulk-drain' conductance without the capacitor components
2188  // We'll need to get the capacitor contribution in the actual load
2189  // using C*dt
2190  // gbs: bulk-source' without capacitor
2191  // gm = derivative of channel current w.r.t. gate-source voltage --- gotta
2192  // account for mode=normal or mode=reverse when using this!
2193  // gmbs = derivative of channel current w.r.t bulk-source voltage
2194  // gds = derivative of channel current w.r.t. drain-source voltage
2195 
2196  // the variables gcgs, gcgb, gcgd should be the conductances for the gate
2197  // capacitors, but we won't do those here (vide supra), we'll do them
2198  // in the jacobian load given the capacitances.
2199 
2200  // Now 3f5 doesn't do the resistor currents in the RHS load, because of
2201  // how they do their numerics. We do, so let's save those here.
2202 
2205 
2206  if (mode >= 0) // Normal mode
2207  {
2208  Gm = gm; // (xnrm-xrev)*gm in 3f5
2209  Gmbs = gmbs; // (xnrm-xrev)*gmbs in 3f5
2210  nrmsum = Gm+Gmbs; // xnrm*(gm+gmbs)
2211  revsum = 0; // xrev*(gm+gmbs)
2213  }
2214  else
2215  {
2216  Gm = -gm;
2217  Gmbs = -gmbs;
2218  nrmsum = 0;
2219  revsum = -(Gm+Gmbs); // because Gm and Gmbs already have - in them!
2220  cdreq = -(model_.dtype)*cdrain;
2221  }
2222 
2223  // It is now essential to restore the vds/vgs/vgd variables that might
2224  // have been tweaked by homotopy, lest they have an effect on RHS
2225  // Jdxp terms.
2226 
2227  vds=vds_save;
2228  vgs=vgs_save;
2229  vgd=vgd_save;
2230 
2231  /// CURRENTS to load into RHS:
2232 
2233  // so at this point:
2234 
2235  // current out of drain is
2236  // Idrain
2237 
2238  // current out of gate:
2239  // dtype*( (deriv of qgs) + (deriv of qgd) + (deriv of qgb))
2240 
2241  // the current *out of* the source should be simply
2242  // Isource.
2243 
2244  // current out of bulk is
2245  // dtype*(deriv of qbd) + dtype*cbd + dtype*cbs + dtype*(deriv of qbs)
2246  // - dtype*(deriv of qgb)
2247 
2248  // current out of drain' is
2249  // -Idrain - dtype*(deriv of qgd) - (deriv of qbd) - dtype*cbd +
2250  // mode*dtype*cdrain
2251 
2252  // the current out of the source' is
2253  // -Isource - dtype*(deriv of qgs) - dtype*cbs - (deriv of qbs) -
2254  // mode*dtype*cdrain
2255 
2256  //////Conductances to load into Jacobian as they relate to things here:
2257  /// all of the places where I say Cap/dt I really mean dtype*Cap/dt for
2258  // the meyer capacitors. No dtype for the parasitics, though
2259 
2260  // 3f5 handles the mode by doing:
2261  // where xnrm=1, xrev=0 if mode>=0, xnrm=0,xrev=1 if mode<0
2262 
2263  // drain-drain = a = drainConductance
2264  // drain-drain' = b = -drainConductance
2265 
2266  // gate-gate = c = "gcgd+gcgs+gcgb" = Capgd/dt+Capgs/dt+Capgb/dt
2267  // gate-bulk = d = -gcgb = -Capgb/dt
2268  // gate-drain' = e = -gcgd = -Capgd/dt
2269  // gate-source' = f = -gcgs = -Capgs/dt
2270 
2271  // source-source = g = sourceConductance
2272  // source-source' = h = -sourceConductance
2273 
2274  // bulk-gate = i = -gcgb = -Capgb/dt
2275  // bulk-bulk = j = gbs+gbd+gcgb+parasitics=gbs+gbd+Capgb/dt+capbs/dt+capbd/dt
2276  // bulk-drain' = k= -gbd-capbd/dt
2277  // bulk-source' = l= -gbs-capbs/dt
2278 
2279  // drain'-drain = m = -drainConductance
2280  // drain'-gate = n = (xnrm-xrev)*gm-Capgd/dt
2281  // drain'-bulk = o = -gbd-capbd/dt+(xnrm-xrev)*gmbs
2282  // drain'-drain' = p = drainConductance+gds+gbd+capbd/dt+
2283  // xrev*(gm+gmbs)+ Capgd/dt
2284  // drain'-source' = q = -gds-xnrm*(gm+gmbs)
2285 
2286  // source'-gate = r = -(xnrm-xrev)*gm-Capgs/dt
2287  // source'-source = s = -sourceConductance
2288  // source'-bulk = t = -gbs-capbs/dt-(xnrm-xrev)*gmbs
2289  // source'-drain' = u= -gds-xrev*(gm+gmbs)
2290  // source'-source' = v = sourceConductance+gds+gbs+capbs/dt+xnrm*(gm+gmbs)+
2291  // Capgs/dt
2292 
2293  return bsuccess;
2294 }
2295 
2296 
2297 //-----------------------------------------------------------------------------
2298 // Function : Instance::updateTemperature
2299 // Purpose :
2300 // Special Notes :
2301 // Scope : public
2302 // Creator : Tom Russo, Component Information and Models
2303 // Creation Date : 02/27/01
2304 //-----------------------------------------------------------------------------
2305 bool Instance::updateTemperature ( const double & temp_tmp)
2306 {
2307  // mos6temp vars
2308  double czbd; // zero voltage bulk-drain capacitance
2309  double czbdsw; // zero voltage bulk-drain sidewall capacitance
2310  double czbs; // zero voltage bulk-source capacitance
2311  double czbssw; // zero voltage bulk-source sidewall capacitance
2312  double arg; // 1 - fc
2313  double sarg; // (1-fc) ^^ (-mj)
2314  double sargsw; // (1-fc) ^^ (-mjsw)
2315  double ratio,ratio4;
2316  double fact2;
2317  double kt;
2318  double egfet;
2319  double pbfact;
2320  double capfact;
2321  double phio;
2322  double pbo;
2323  double gmanew,gmaold;
2324 
2325  double fact1;
2326  double vtnom;
2327  double kt1;
2328  double egfet1;
2329  double arg1;
2330  double pbfact1;
2331 
2332  // end of mos6temp stuff
2333 
2334  double tnom;
2335 
2336 
2337 #ifdef Xyce_DEBUG_DEVICE
2338  if (getDeviceOptions().debugLevel > 0 && getSolverState().debugTimeFlag)
2339  {
2340  Xyce::dout() << subsection_divider << std::endl;
2341  Xyce::dout() << " Begin of updateTemperature. \n";
2342  Xyce::dout() << std::endl;
2343  }
2344 #endif
2345 
2346  // first set the instance temperature to the new temperature:
2347  if (temp_tmp != -999.0) temp = temp_tmp;
2348 
2350  {
2352  }
2353 
2354  tnom = model_.tnom;
2355  ratio = temp/tnom;
2356 
2357 #ifdef Xyce_DEBUG_DEVICE
2358  if (getDeviceOptions().debugLevel > 0 && getSolverState().debugTimeFlag)
2359  {
2360  Xyce::dout() << "Temperature = "<< temp << std::endl;
2361  Xyce::dout() << "tnom = " << tnom << std::endl;
2362  Xyce::dout() << "ratio = " << ratio << std::endl;
2363  }
2364 #endif
2365 
2366  vt = temp * CONSTKoverQ;
2367  ratio = temp/tnom;
2368  fact2 = temp/CONSTREFTEMP;
2369  kt = temp * CONSTboltz;
2370  egfet = 1.16-(7.02e-4*temp*temp)/(temp+1108);
2371  arg = -egfet/(kt+kt)+1.1150877/(CONSTboltz*(CONSTREFTEMP+CONSTREFTEMP));
2372  pbfact = -2*vt *(1.5*log(fact2)+CONSTQ*arg);
2373 
2374  //
2375  fact1 = model_.tnom/CONSTREFTEMP;
2376  vtnom = model_.tnom*CONSTKoverQ;
2377  kt1 = CONSTboltz * model_.tnom;
2378  egfet1 = 1.16-(7.02e-4*model_.tnom*model_.tnom)/
2379  (model_.tnom+1108);
2380  arg1 = -egfet1/(kt1+kt1)+1.1150877/(CONSTboltz*(CONSTREFTEMP+CONSTREFTEMP));
2381  pbfact1 = -2*vtnom *(1.5*log(fact1)+CONSTQ*arg1);
2382  //
2383 #ifdef Xyce_DEBUG_DEVICE
2385  {
2386  Xyce::dout() << "vt = " << vt << std::endl;
2387  Xyce::dout() << "ratio = " << ratio << std::endl;
2388  Xyce::dout() << "fact2 = " << fact2 << std::endl;
2389  Xyce::dout() << "kt = " << kt << std::endl;
2390  Xyce::dout() << "egfet = " << egfet << std::endl;
2391  Xyce::dout() << "arg = " << arg << std::endl;
2392  Xyce::dout() << "pbfact = " << pbfact << std::endl;
2393  }
2394 #endif
2395 
2396  // in mos6temp 3f5 does a bunch of parameter defaulting
2397  // but we assume that our various parameters have been set already in
2398  // the constructors
2399 
2400  // some lines of mos6temp moved to instance block constructor
2401 
2402  // Here's the entire guts of the mos6temp instance loop, with obvious
2403  // modifications (here->MOS6 goes away, model->MOS6 turns into model_.)
2404  ////////////
2405  {
2406  ratio4 = ratio * sqrt(ratio);
2407  tKv = model_.kv;
2408  tKc = model_.kc / ratio4;
2409  tSurfMob = model_.surfaceMobility/ratio4;
2410  phio= (model_.phi-pbfact1)/fact1;
2411  tPhi = fact2 * phio + pbfact;
2412 
2413  tVbi = model_.vt0 - model_.dtype *
2414  (model_.gamma* sqrt(model_.phi))
2415  +.5*(egfet1-egfet)
2416  + model_.dtype*.5* (tPhi-model_.phi);
2417  tVto = tVbi + model_.dtype *
2418  model_.gamma * sqrt(tPhi);
2420  exp(-egfet/vt+egfet1/vtnom);
2422  exp(-egfet/vt+egfet1/vtnom);
2423  pbo = (model_.bulkJctPotential - pbfact1)/fact1;
2424  gmaold = (model_.bulkJctPotential-pbo)/pbo;
2425  capfact = 1/(1+model_.bulkJctBotGradingCoeff*
2426  (4e-4*(model_.tnom-CONSTREFTEMP)-gmaold));
2427  tCbd = model_.capBD * capfact;
2428  tCbs = model_.capBS * capfact;
2429  tCj = model_.bulkCapFactor * capfact;
2430  capfact = 1/(1+model_.bulkJctSideGradingCoeff*
2431  (4e-4*(model_.tnom-CONSTREFTEMP)-gmaold));
2432  tCjsw = model_.sideWallCapFactor * capfact;
2433  tBulkPot = fact2 * pbo+pbfact;
2434  gmanew = (tBulkPot-pbo)/pbo;
2435  capfact = (1+model_.bulkJctBotGradingCoeff*
2436  (4e-4*(temp-CONSTREFTEMP)-gmanew));
2437  tCbd *= capfact;
2438  tCbs *= capfact;
2439  tCj *= capfact;
2440  capfact = (1+model_.bulkJctSideGradingCoeff*
2441  (4e-4*(temp-CONSTREFTEMP)-gmanew));
2442  tCjsw *= capfact;
2444 
2445 
2446  if( (tSatCurDens == 0) || (drainArea == 0) || (sourceArea == 0) )
2447  {
2449  }
2450  else
2451  {
2452  drainVcrit = vt * log( vt / (CONSTroot2 * tSatCurDens * drainArea));
2453  sourceVcrit = vt * log( vt / (CONSTroot2 * tSatCurDens * sourceArea));
2454  }
2455 
2456  if(model_.capBDGiven)
2457  {
2458  czbd = tCbd;
2459  }
2460  else
2461  {
2463  {
2464  czbd=tCj*drainArea;
2465  }
2466  else
2467  {
2468  czbd=0;
2469  }
2470  }
2471 
2473  {
2474  czbdsw= tCjsw * drainPerimeter;
2475  }
2476  else
2477  {
2478  czbdsw=0;
2479  }
2480  arg = 1-model_.fwdCapDepCoeff;
2481  sarg = exp( (-model_.bulkJctBotGradingCoeff) * log(arg) );
2482  sargsw = exp( (-model_.bulkJctSideGradingCoeff) * log(arg) );
2483  Cbd = czbd;
2484  Cbdsw = czbdsw;
2485  f2d = czbd*(1-model_.fwdCapDepCoeff*
2486  (1+model_.bulkJctBotGradingCoeff))* sarg/arg
2487  + czbdsw*(1-model_.fwdCapDepCoeff*
2489  sargsw/arg;
2490  f3d = czbd * model_.bulkJctBotGradingCoeff * sarg/arg/
2491  tBulkPot
2492  + czbdsw * model_.bulkJctSideGradingCoeff * sargsw/arg /
2493  tBulkPot;
2494  f4d = czbd*tBulkPot*(1-arg*sarg)/
2496  + czbdsw*tBulkPot*(1-arg*sargsw)/
2498  -f3d/2*
2499  (tDepCap*tDepCap)
2500  -tDepCap * f2d;
2501  if(model_.capBSGiven)
2502  {
2503  czbs=tCbs;
2504  }
2505  else
2506  {
2508  {
2509  czbs=tCj*sourceArea;
2510  }
2511  else
2512  {
2513  czbs=0;
2514  }
2515  }
2516 
2518  {
2519  czbssw = tCjsw * sourcePerimeter;
2520  }
2521  else
2522  {
2523  czbssw=0;
2524  }
2525 
2526  arg = 1-model_.fwdCapDepCoeff;
2527  sarg = exp( (-model_.bulkJctBotGradingCoeff) * log(arg) );
2528  sargsw = exp( (-model_.bulkJctSideGradingCoeff) * log(arg) );
2529  Cbs = czbs;
2530  Cbssw = czbssw;
2531  f2s = czbs*(1-model_.fwdCapDepCoeff*
2532  (1+model_.bulkJctBotGradingCoeff))* sarg/arg
2533  + czbssw*(1-model_.fwdCapDepCoeff*
2535  sargsw/arg;
2536  f3s = czbs * model_.bulkJctBotGradingCoeff * sarg/arg/
2537  tBulkPot
2538  + czbssw * model_.bulkJctSideGradingCoeff * sargsw/arg /
2539  tBulkPot;
2540 
2541  f4s = czbs*tBulkPot*(1-arg*sarg)/
2543  + czbssw*tBulkPot*(1-arg*sargsw)/
2545  -f3s/2*
2546  (tDepCap*tDepCap)
2547  -tDepCap * f2s;
2548  }
2549 
2550  return true;
2551 }
2552 
2553 //-----------------------------------------------------------------------------
2554 // Function : Instance:isConverged ()
2555 // Purpose : Return whether a MOSFET device has done something that
2556 // should be interpreted as invalidating other convergence
2557 // tests.
2558 //
2559 // The mos6 is a little weird. It needs to be forced take
2560 // at least 2 Newton steps, apparently. SPICE's nonlinear
2561 // solver does this by default (for any circuit) from
2562 // what I can see. Xyce doesn't usually do that, but this
2563 // function forces that to be the case for any circuit
2564 // including a MOS6.
2565 //
2566 // This indicates to me that the MOS6 is a lousy device,
2567 // actually.
2568 //
2569 // Special Notes :
2570 // Scope : public
2571 // Creator : Eric Keiter, SNL
2572 // Creation Date : 06/22/08
2573 //-----------------------------------------------------------------------------
2575 {
2576  return (!limitedFlag && (getSolverState().newtonIter > 1));
2577 }
2578 
2579 //-----------------------------------------------------------------------------
2580 // Function : Instance::updatePrimaryState
2581 // Purpose :
2582 // Special Notes :
2583 // Scope : public
2584 // Creator : Tom Russo, Component Information and Models
2585 // Creation Date : 02/28/01
2586 //-----------------------------------------------------------------------------
2588 {
2589  bool bsuccess = true;
2590 
2591  double * staVector = extData.nextStaVectorRawPtr;
2592  double * oldstaVector = extData.currStaVectorRawPtr;
2593  double * stoVector = extData.nextStoVectorRawPtr;
2594  double * oldstoVector = extData.currStoVectorRawPtr;
2595 
2596  double vgs1, vgd1, vbs1,vgb1, vds1;
2597 
2598  bsuccess = updateIntermediateVars ();
2599 
2600  // voltage drops:
2601  stoVector[li_store_vbd] = vbd;
2602  stoVector[li_store_vbs] = vbs;
2603  stoVector[li_store_vgs] = vgs;
2604  stoVector[li_store_vds] = vds;
2605  stoVector[li_store_von] = von;
2606 
2607  // now the meyer capacitances
2608  // we didn't calculate these charges in update IntermediateVars
2609  // but we did calculate the voltage drops and capacitances.
2610  // first store the capacitances themselves:
2611  staVector[li_state_capgs] = capgs;
2612  staVector[li_state_capgd] = capgd;
2613  staVector[li_state_capgb] = capgb;
2614 
2615  // now the charges
2616  // BE CAREFUL! We can only do Q=CV for DCOP! Otherwise it's
2617  // supposed to be *INTEGRATED*:
2618  // Q = int(t0,t1)C(V)*dV --- and we approximate that by
2619  // Q(t1)-Q(t0) = CBar*(V(t1)-V(t0)) where CBar is the average.
2620  // Now with Meyer back averaging, Capxx is the average between the last
2621  // time step and this one. So we gotta do the right thing for non-DCOP
2622  // when backaverage is on.
2623 
2624  if((getSolverState().dcopFlag))
2625  {
2626  qgs = Capgs*vgs;
2627  qgd = Capgd*vgd;
2628  qgb = Capgb*Vgb;
2629  }
2630  else
2631  {
2632  // get the ones from last time step
2633  qgs = oldstaVector[li_state_qgs];
2634  qgd = oldstaVector[li_state_qgd];
2635  qgb = oldstaVector[li_state_qgb];
2636  // get the voltage drops, too
2637  vgs1 = oldstoVector[li_store_vgs];
2638  vbs1 = oldstoVector[li_store_vbs];
2639  vds1 = oldstoVector[li_store_vds];
2640 
2641  vgb1 = vgs1-vbs1;
2642  vgd1 = vgs1-vds1;
2643 
2644  // NOW we can calculate the charge update
2645  qgs += Capgs*(vgs-vgs1);
2646  qgd += Capgd*(vgd-vgd1);
2647  qgb += Capgb*((vgs-vbs)-vgb1);
2648  }
2649 
2650  staVector[li_state_qgs] = qgs;
2651  staVector[li_state_qgd] = qgd;
2652  staVector[li_state_qgb] = qgb;
2653 
2654  // and the diode parasitic capacitors
2655  // these charges were set in updateIntermediateVars
2656  staVector[li_state_qbd] = qbd;
2657  staVector[li_state_qbs] = qbs;
2658 
2659  return bsuccess;
2660 }
2661 
2662 // Additional Declarations
2663 // Class Model
2664 
2665 //-----------------------------------------------------------------------------
2666 // Function : Model::processParams
2667 // Purpose :
2668 // Special Notes :
2669 // Scope : public
2670 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
2671 // Creation Date : 6/03/02
2672 //-----------------------------------------------------------------------------
2674 {
2675 
2676  double wkfngs;
2677  double wkfng;
2678  double fermig;
2679  double fermis;
2680  double vfb;
2681  double kt1;
2682  double arg1;
2683 
2686  kt1 = CONSTboltz * tnom;
2687  egfet1 = 1.16-(7.02e-4*tnom*tnom)/(tnom+1108);
2688  arg1 = -egfet1/(kt1+kt1)+1.1150877/(CONSTboltz*(CONSTREFTEMP+CONSTREFTEMP));
2689  pbfact1 = -2*vtnom *(1.5*log(fact1)+CONSTQ*arg1);
2690 #ifdef Xyce_DEBUG_DEVICE
2691  if (getDeviceOptions().debugLevel > 0)
2692  {
2693  Xyce::dout() << " fact1 = " << fact1 << std::endl;
2694  Xyce::dout() << " vtnom = " << vtnom << std::endl;
2695  Xyce::dout() << " kt1 = " << kt1 << std::endl;
2696  Xyce::dout() << " egfet1 = " << egfet1 << std::endl;
2697  Xyce::dout() << " arg1 = " << arg1 << std::endl;
2698  Xyce::dout() << " pbfact1 = " << pbfact1 << std::endl;
2699  }
2700 #endif
2701 
2702 #if 0
2703  if(oxideThickness == 0)
2704  {
2705  UserError0(*this) << name << " has TOX=0";
2706  }
2707  else
2708  {
2709  oxideCapFactor = 3.9 * 8.854214871e-12/oxideThickness;
2710  }
2711  if(!given("U0") && !given("UO")) surfaceMobility=600;
2712  if(!given("KP"))
2713  transconductance = surfaceMobility * oxideCapFactor * 1e-4;
2714  if(given("NSUB"))
2715  {
2716  if(substrateDoping*1e6 >1.45e16)
2717  {
2718  if(!given("PHI"))
2719  {
2720  phi = 2*vtnom*
2721  log(substrateDoping*1e6/1.45e16);
2722  phi = Xycemax(0.1,phi);
2723  }
2724  fermis = dtype * .5 * phi;
2725  wkfng = 3.2;
2726  if(!given("TPG")) gateType=1;
2727  if(gateType != 0)
2728  {
2729  fermig = dtype *gateType*.5*egfet1;
2730  wkfng = 3.25 + .5 * egfet1 - fermig;
2731  }
2732  wkfngs = wkfng - (3.25 + .5 * egfet1 +fermis);
2733  if(!given("GAMMA"))
2734  {
2735  gamma = sqrt(2 * 11.70 * CONSTperm0 *
2736  CONSTQ * substrateDoping*1e6)/
2738  }
2739  if(!given("VTO"))
2740  {
2741  if(!given("NSS"))
2743  vfb = wkfngs - surfaceStateDensity*1e4*CONSTQ/oxideCapFactor;
2744  vt0 = vfb + dtype * (gamma * sqrt(phi)+ phi);
2745  }
2746  else
2747  {
2748  vfb = vt0 - dtype * (gamma*sqrt(phi)+phi);
2749  }
2750  alpha = ((11.7*CONSTperm0)+(11.7*CONSTperm0))/
2751  (CONSTQ*substrateDoping*1e6); //(cm**3/m**3)
2752  coeffDepLayWidth = sqrt(alpha);
2753  }
2754  else
2755  {
2756  UserError0(*this) << "Nsub < Ni";
2757  }
2758  }
2759 #else
2760 
2761  if(!given("TOX") || oxideThickness == 0)
2762  {
2763  oxideCapFactor = 0;
2764  }
2765  else
2766  {
2767  oxideCapFactor = 3.9 * 8.854214871e-12/oxideThickness;
2768 
2769  if(!given("KC"))
2770  {
2771  //if(!surfaceMobilityGiven)
2772  //{
2773  //surfaceMobility=600;
2774  //}
2775  kc = 0.5 * surfaceMobility * oxideCapFactor * 1e-4; //(m**2/cm**2)
2776  }
2777 
2778  if(given("NSUB"))
2779  {
2780  if(substrateDoping*1e6 >1.45e16)
2781  {
2782  if(!given("PHI"))
2783  {
2784  phi = 2*vtnom* log(substrateDoping*1e6/1.45e16);
2785  phi = Xycemax(0.1,phi);
2786  }
2787  fermis = dtype * 0.5 * phi;
2788  wkfng = 3.2;
2789 
2790  if(!given("TPG"))
2791  {
2792  gateType=1;
2793  }
2794 
2795  if(gateType != 0)
2796  {
2797  fermig = dtype *gateType*.5*egfet1;
2798  wkfng = 3.25 + .5 * egfet1 - fermig;
2799  }
2800  wkfngs = wkfng - (3.25 + .5 * egfet1 +fermis);
2801 
2802  if(!given("GAMMA"))
2803  {
2804  gamma = sqrt(2 * 11.70 * CONSTperm0 *
2805  CONSTQ * substrateDoping*1e6)/
2807  }
2808 
2809  if(!given("GAMMA1"))
2810  {
2811  gamma1 = 0.0;
2812  }
2813 
2814  if(!given("VTO"))
2815  {
2816  if(!given("NSS"))
2817  {
2819  }
2820  vfb = wkfngs - surfaceStateDensity*1e4*CONSTQ/oxideCapFactor;
2821  vt0 = vfb + dtype * (gamma * sqrt(phi)+ phi);
2822  }
2823  }
2824  else
2825  {
2826  UserError0(*this) << "Nsub < Ni";
2827  }
2828  }
2829  }
2830 
2831 #endif
2832 
2833  return true;
2834 }
2835 
2836 //----------------------------------------------------------------------------
2837 // Function : Model::processInstanceParams
2838 // Purpose :
2839 // Special Notes :
2840 // Scope : public
2841 // Creator : Dave Shirely, PSSI
2842 // Creation Date : 03/23/06
2843 //----------------------------------------------------------------------------
2845 {
2846 
2847  std::vector<Instance*>::iterator iter;
2848  std::vector<Instance*>::iterator first = instanceContainer.begin();
2849  std::vector<Instance*>::iterator last = instanceContainer.end();
2850 
2851  for (iter=first; iter!=last; ++iter)
2852  {
2853  (*iter)->processParams();
2854  }
2855 
2856  return true;
2857 }
2858 
2859 //-----------------------------------------------------------------------------
2860 // Function : Model::Model
2861 // Purpose :
2862 // Special Notes :
2863 // Scope : public
2864 // Creator : Tom Russo, Component Information and Models
2865 // Creation Date : 2/26/01
2866 //-----------------------------------------------------------------------------
2868  const Configuration & configuration,
2869  const ModelBlock & MB,
2870  const FactoryBlock & factory_block)
2871  : DeviceModel(MB, configuration.getModelParameters(), factory_block),
2872  dtype(CONSTNMOS),
2873  tnom(getDeviceOptions().tnom),
2874  latDiff(0.0),
2875  jctSatCurDensity(0.0),
2876  jctSatCur(0.0),
2877  drainResistance(0.0),
2878  sourceResistance(0.0),
2879  sheetResistance(0.0),
2880  kv(0.0),
2881  nv(0.0),
2882  kc(0.0),
2883  nc(0.0),
2884  nvth(0.0),
2885  ps(0.0),
2886  gateSourceOverlapCapFactor(0.0),
2887  gateDrainOverlapCapFactor(0.0),
2888  gateBulkOverlapCapFactor(0.0),
2889  oxideCapFactor(0.0),
2890  vt0(0.0),
2891  capBD(0.0),
2892  capBS(0.0),
2893  bulkCapFactor(0.0),
2894  sideWallCapFactor(0.0),
2895  bulkJctPotential(0.0),
2896  bulkJctBotGradingCoeff(0.0),
2897  bulkJctSideGradingCoeff(0.0),
2898  fwdCapDepCoeff(0.0),
2899  phi(0.0),
2900  gamma(0.0),
2901  gamma1(0.0),
2902  sigma(0.0),
2903  lambda(0.0),
2904  lambda0(0.0),
2905  lambda1(0.0),
2906  substrateDoping(0.0),
2907  gateType(0),
2908  surfaceStateDensity(0.0),
2909  oxideThickness(0.0),
2910  surfaceMobility(0.0),
2911  lambdaGiven (false),
2912  lambda0Given (false),
2913  lambda1Given (false),
2914  capBDGiven(false),
2915  capBSGiven(false),
2916  bulkCapFactorGiven(false),
2917  sideWallCapFactorGiven(false)
2918 {
2919 
2920  if (getType() != "")
2921  {
2922  if (getType() == "NMOS") {
2923  dtype = CONSTNMOS;
2924  }
2925  else if (getType() == "PMOS") {
2926  dtype = CONSTPMOS;
2927  }
2928  else
2929  {
2930  UserError0(*this) << "Could not recognize the type for model " << getName();
2931  }
2932  }
2933 
2934 
2935  // Set params to constant default values:
2936  setDefaultParams ();
2937 
2938  // Set params according to .model line and constant defaults from metadata:
2939  setModParams (MB.params);
2940 
2941  // Set any non-constant parameter defaults:
2942  if (!given("TNOM"))
2944  if (capBD != 0)
2945  capBDGiven = true;
2946  if (capBS != 0)
2947  capBSGiven = true;
2948 
2949  if(lambda0Given)
2950  {
2951  lambda0 = 0.0;
2952  if(lambdaGiven)
2953  {
2954  lambda0 = lambda;
2955  }
2956  }
2957 
2958  // Calculate any parameters specified as expressions:
2959 
2961 
2962  // calculate dependent (ie computed) params and check for errors:
2963 
2964  if (given("U0"))
2965  {
2966  if (given("UO"))
2967  UserError0(*this) << "You have specified both uo and u0, which is not allowed.";
2968 
2969  UserWarning0(*this) << "You have specified the surface mobility as u0 instead of uo. This is supported, but ill-advised.";
2970 
2972  }
2973 
2974  processParams ();
2975 }
2976 
2977 //-----------------------------------------------------------------------------
2978 // Function : Model::~Model
2979 // Purpose : destructor
2980 // Special Notes :
2981 // Scope : public
2982 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
2983 // Creation Date : 3/16/00
2984 //-----------------------------------------------------------------------------
2986 {
2987  std::vector<Instance*>::iterator iter;
2988  std::vector<Instance*>::iterator first = instanceContainer.begin();
2989  std::vector<Instance*>::iterator last = instanceContainer.end();
2990 
2991  for (iter=first; iter!=last; ++iter)
2992  {
2993  delete (*iter);
2994  }
2995 
2996 }
2997 
2998 //-----------------------------------------------------------------------------
2999 // Function : Model::printOutInstances
3000 // Purpose : debugging tool.
3001 // Special Notes :
3002 // Scope : public
3003 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
3004 // Creation Date : 4/03/00
3005 //-----------------------------------------------------------------------------
3006 std::ostream &Model::printOutInstances(std::ostream &os) const
3007 {
3008  std::vector<Instance*>::const_iterator iter;
3009  std::vector<Instance*>::const_iterator first = instanceContainer.begin();
3010  std::vector<Instance*>::const_iterator last = instanceContainer.end();
3011 
3012  int i;
3013  os << std::endl;
3014  os << " name model name Parameters" << std::endl;
3015  for (i=0, iter=first; iter!=last; ++iter, ++i)
3016  {
3017  os << " " << i << ": " << (*iter)->getName() << "\t";
3018  os << getName();
3019  os << std::endl;
3020  }
3021  os << std::endl;
3022 
3023  return os;
3024 }
3025 
3026 //-----------------------------------------------------------------------------
3027 // Function : Model::forEachInstance
3028 // Purpose :
3029 // Special Notes :
3030 // Scope : public
3031 // Creator : David Baur
3032 // Creation Date : 2/4/2014
3033 //-----------------------------------------------------------------------------
3034 /// Apply a device instance "op" to all instances associated with this
3035 /// model
3036 ///
3037 /// @param[in] op Operator to apply to all instances.
3038 ///
3039 ///
3040 void Model::forEachInstance(DeviceInstanceOp &op) const /* override */
3041 {
3042  for (std::vector<Instance *>::const_iterator it = instanceContainer.begin(); it != instanceContainer.end(); ++it)
3043  op(*it);
3044 }
3045 
3046 
3047 //-----------------------------------------------------------------------------
3048 // MOSFET6 Master functions:
3049 //-----------------------------------------------------------------------------
3050 
3051 //-----------------------------------------------------------------------------
3052 // Function : Master::updateState
3053 // Purpose :
3054 // Special Notes :
3055 // Scope : public
3056 // Creator : Eric Keiter, SNL
3057 // Creation Date : 11/26/08
3058 //-----------------------------------------------------------------------------
3059 bool Master::updateState (double * solVec, double * staVec, double * stoVec)
3060 {
3061  bool bsuccess = true;
3062 
3063  for (InstanceVector::const_iterator it = getInstanceBegin(); it != getInstanceEnd(); ++it)
3064  {
3065  Instance & mi = *(*it);
3066  double * oldstaVec = mi.extData.currStaVectorRawPtr;
3067  double * stoVec = mi.extData.nextStoVectorRawPtr;
3068  double * oldstoVec = mi.extData.currStoVectorRawPtr;
3069 
3070  double vgs1(0.0), vgd1(0.0), vbs1(0.0),vgb1(0.0), vds1(0.0);
3071 
3072  bool btmp = mi.updateIntermediateVars ();
3073  bsuccess = bsuccess && btmp;
3074 
3075  // voltage drops:
3076  stoVec[mi.li_store_vbd] = mi.vbd;
3077  stoVec[mi.li_store_vbs] = mi.vbs;
3078  stoVec[mi.li_store_vgs] = mi.vgs;
3079  stoVec[mi.li_store_vds] = mi.vds;
3080  stoVec[mi.li_store_von] = mi.von;
3081 
3082  // now the meyer capacitances
3083  // we didn't calculate these charges in update IntermediateVars
3084  // but we did calculate the voltage drops and capacitances.
3085  // first store the capacitances themselves:
3086  staVec[mi.li_state_capgs] = mi.capgs;
3087  staVec[mi.li_state_capgd] = mi.capgd;
3088  staVec[mi.li_state_capgb] = mi.capgb;
3089 
3090  // now the charges
3091  // BE CAREFUL! We can only do Q=CV for DCOP! Otherwise it's
3092  // supposed to be *INTEGRATED*:
3093  // Q = int(t0,t1)C(V)*dV --- and we approximate that by
3094  // Q(t1)-Q(t0) = CBar*(V(t1)-V(t0)) where CBar is the average.
3095  // Now with Meyer back averaging, Capxx is the average between the last
3096  // time step and this one. So we gotta do the right thing for non-DCOP
3097  // when backaverage is on.
3098 
3099  if((getSolverState().dcopFlag))
3100  {
3101  mi.qgs = mi.Capgs*mi.vgs;
3102  mi.qgd = mi.Capgd*mi.vgd;
3103  mi.qgb = mi.Capgb*mi.Vgb;
3104  }
3105  else
3106  {
3107  // get the ones from last time step
3108  mi.qgs = oldstaVec[mi.li_state_qgs];
3109  mi.qgd = oldstaVec[mi.li_state_qgd];
3110  mi.qgb = oldstaVec[mi.li_state_qgb];
3111  // get the voltage drops, too
3112  vgs1 = oldstoVec[mi.li_store_vgs];
3113  vbs1 = oldstoVec[mi.li_store_vbs];
3114  vds1 = oldstoVec[mi.li_store_vds];
3115 
3116  vgb1 = vgs1-vbs1;
3117  vgd1 = vgs1-vds1;
3118 
3119  // NOW we can calculate the charge update
3120  mi.qgs += mi.Capgs*(mi.vgs-vgs1);
3121  mi.qgd += mi.Capgd*(mi.vgd-vgd1);
3122  mi.qgb += mi.Capgb*((mi.vgs-mi.vbs)-vgb1);
3123  }
3124 
3125  staVec[mi.li_state_qgs] = mi.qgs;
3126  staVec[mi.li_state_qgd] = mi.qgd;
3127  staVec[mi.li_state_qgb] = mi.qgb;
3128 
3129  // and the diode parasitic capacitors
3130  // these charges were set in updateIntermediateVars
3131  staVec[mi.li_state_qbd] = mi.qbd;
3132  staVec[mi.li_state_qbs] = mi.qbs;
3133  }
3134 
3135  return bsuccess;
3136 }
3137 
3138 //-----------------------------------------------------------------------------
3139 // Function : Master::loadDAEVectors
3140 // Purpose :
3141 // Special Notes :
3142 // Scope : public
3143 // Creator : Eric Keiter, SNL
3144 // Creation Date : 11/26/08
3145 //-----------------------------------------------------------------------------
3146 bool Master::loadDAEVectors (double * solVec, double * fVec, double *qVec, double * storeLeadF, double * storeLeadQ)
3147 {
3148  double gmin1 = getDeviceOptions().gmin;
3149 
3150  for (InstanceVector::const_iterator it = getInstanceBegin(); it != getInstanceEnd(); ++it)
3151  {
3152  Instance & mi = *(*it);
3153 
3154  int Dtype=mi.getModel().dtype;
3155  double ceqbs(0.0),ceqbd(0.0),ceqgb(0.0), ceqgs(0.0), ceqgd(0.0);
3156  double Qeqbs(0.0),Qeqbd(0.0),Qeqgb(0.0), Qeqgs(0.0), Qeqgd(0.0);
3157  double coef(0.0);
3158  // F-Vector:
3159  ceqbs = Dtype*(mi.cbs);
3160  ceqbd = Dtype*(mi.cbd);
3161  // These need "Dtype" here because we use them later *without*
3162  // Dtype, where SPICE uses it *with*
3163  ceqgb = 0.0;
3164  ceqgs = 0.0;
3165  ceqgd = 0.0;
3166 
3167  if (mi.drainConductance != 0.0)
3168  {
3169  fVec[mi.li_Drain] += mi.Idrain*mi.numberParallel;
3170  }
3171 
3172  coef = (ceqgs+ceqgd+ceqgb);
3173  fVec[mi.li_Gate] += coef*mi.numberParallel;
3174 
3175  if (mi.sourceConductance != 0.0)
3176  {
3177  fVec[mi.li_Source] += mi.Isource*mi.numberParallel;
3178  }
3179 
3180  coef = ceqbs + ceqbd - ceqgb;
3181  fVec[mi.li_Bulk] += coef*mi.numberParallel;
3182 
3183  coef = -mi.Idrain-(ceqbd - mi.cdreq + ceqgd);
3184  fVec[mi.li_DrainPrime] += coef*mi.numberParallel;
3185 
3186  coef = -mi.Isource-(ceqbs + mi.cdreq + ceqgs);
3187  fVec[mi.li_SourcePrime] += coef*mi.numberParallel;
3188 
3189  // Q-Vector:
3190  Qeqbs = Dtype*(mi.qbs);
3191  Qeqbd = Dtype*(mi.qbd);
3192  // These need "Dtype" here because we use them later *without*
3193  // Dtype, where SPICE uses it *with*
3194  Qeqgb = Dtype*(mi.qgb);
3195  Qeqgs = Dtype*(mi.qgs);
3196  Qeqgd = Dtype*(mi.qgd);
3197 
3198  coef = (Qeqgs+Qeqgd+Qeqgb);
3199  qVec[mi.li_Gate] += coef*mi.numberParallel;
3200 
3201  coef = Qeqbs + Qeqbd - Qeqgb;
3202  qVec[mi.li_Bulk] += coef*mi.numberParallel;
3203 
3204  coef = -(Qeqbd + Qeqgd);
3205  qVec[mi.li_DrainPrime] += coef*mi.numberParallel;
3206 
3207  coef = -(Qeqbs + Qeqgs);
3208  qVec[mi.li_SourcePrime] += coef*mi.numberParallel;
3209 
3210  // voltage limiters:
3211  if (!mi.origFlag)
3212  {
3213  // F-limiters:
3214  double coef_Jdxp4 = Dtype*(
3215  + ((mi.gbd-gmin1))*(mi.vbd-mi.vbd_orig)
3216  + ((mi.gbs-gmin1))*(mi.vbs-mi.vbs_orig));
3217 
3218  double coef_Jdxp5 = Dtype*(
3219  -((mi.gbd-gmin1))*(mi.vbd-mi.vbd_orig)
3220  +mi.gds*(mi.vds-mi.vds_orig)
3221  +mi.Gm*((mi.mode>0)?(mi.vgs-mi.vgs_orig):(mi.vgd-mi.vgd_orig))
3222  +mi.Gmbs*((mi.mode>0)?(mi.vbs-mi.vbs_orig):(mi.vbd-mi.vbd_orig)));
3223 
3224  double coef_Jdxp6 = Dtype*(
3225  -((mi.gbs-gmin1))*(mi.vbs-mi.vbs_orig)
3226  -mi.gds*(mi.vds-mi.vds_orig)
3227  -mi.Gm*((mi.mode>0)?(mi.vgs-mi.vgs_orig):(mi.vgd-mi.vgd_orig))
3228  -mi.Gmbs*((mi.mode>0)?(mi.vbs-mi.vbs_orig):(mi.vbd-mi.vbd_orig)));
3229 
3230  double * dFdxdVp = mi.extData.dFdxdVpVectorRawPtr;
3231 
3232  dFdxdVp[mi.li_Bulk ] += coef_Jdxp4*mi.numberParallel;
3233 
3234  dFdxdVp[mi.li_DrainPrime ] += coef_Jdxp5*mi.numberParallel;
3235 
3236  dFdxdVp[mi.li_SourcePrime] += coef_Jdxp6*mi.numberParallel;
3237 
3238  // Q-limiters:
3239  {
3240  double gcgd(0.0), gcgs(0.0), gcgb(0.0), gcbs(0.0), gcbd(0.0);
3241  if (getSolverState().tranopFlag || getSolverState().acopFlag || getSolverState().transientFlag)
3242  {
3243  gcgd = mi.Capgd;
3244  gcgs = mi.Capgs;
3245  gcgb = mi.Capgb;
3246  // get at the two parasitic caps the same way
3247  gcbs = mi.capbs;
3248  gcbd = mi.capbd;
3249  }
3250  else
3251  {
3252  gcgd = 0.0; gcgs = 0.0; gcgb = 0.0; gcbs = 0.0; gcbd = 0.0;
3253  }
3254 
3255  double coef_Jdxp2 =
3256  Dtype*(gcgd*(mi.vgd-mi.vgd_orig)+gcgs*(mi.vgs-mi.vgs_orig)+
3257  gcgb*(mi.vgs-mi.vgs_orig-mi.vbs+mi.vbs_orig));
3258 
3259  double coef_Jdxp4 = Dtype*(
3260  - (gcgb)*(mi.vgs-mi.vgs_orig-mi.vbs+mi.vbs_orig)
3261  + (gcgb)*(mi.vbd-mi.vbd_orig)
3262  + (gcbs)*(mi.vbs-mi.vbs_orig));
3263 
3264  double coef_Jdxp5 = Dtype*(
3265  -(gcgd)*(mi.vgd-mi.vgd_orig)
3266  -(gcbd)*(mi.vbd-mi.vbd_orig));
3267 
3268  // 6 KCL for source' node
3269  double coef_Jdxp6 = Dtype*
3270  (-gcgs*(mi.vgs-mi.vgs_orig)-(gcbs)*(mi.vbs-mi.vbs_orig));
3271 
3272  double * dQdxdVp = mi.extData.dQdxdVpVectorRawPtr;
3273 
3274  dQdxdVp[mi.li_Gate ] += coef_Jdxp2*mi.numberParallel;
3275 
3276  dQdxdVp[mi.li_Bulk ] += coef_Jdxp4*mi.numberParallel;
3277 
3278  dQdxdVp[mi.li_DrainPrime ] += coef_Jdxp5*mi.numberParallel;
3279 
3280  dQdxdVp[mi.li_SourcePrime] += coef_Jdxp6*mi.numberParallel;
3281  }
3282  }
3283 
3284  if( mi.loadLeadCurrent )
3285  {
3286  if (mi.drainConductance != 0.0)
3287  {
3288  storeLeadF[mi.li_store_dev_id] = mi.Idrain*mi.numberParallel;
3289  }
3290  else
3291  {
3292  storeLeadF[mi.li_store_dev_id] = (-mi.Idrain-(ceqbd - mi.cdreq + ceqgd))*mi.numberParallel;
3293  storeLeadQ[mi.li_store_dev_id] = (-(Qeqbd + Qeqgd))*mi.numberParallel;
3294  }
3295  if (mi.sourceConductance != 0.0)
3296  {
3297  storeLeadF[mi.li_store_dev_is] = mi.Isource*mi.numberParallel;
3298  }
3299  else
3300  {
3301  storeLeadF[mi.li_store_dev_is] = (-mi.Isource-(ceqbs + mi.cdreq + ceqgs))*mi.numberParallel;
3302  storeLeadQ[mi.li_store_dev_is] = (-(Qeqbs + Qeqgs))*mi.numberParallel;
3303  }
3304  storeLeadF[mi.li_store_dev_ig] = (ceqgs+ceqgd+ceqgb)*mi.numberParallel;
3305  storeLeadQ[mi.li_store_dev_ig] = (Qeqgs+Qeqgd+Qeqgb)*mi.numberParallel;
3306  storeLeadF[mi.li_store_dev_ib] = (ceqbs + ceqbd - ceqgb)*mi.numberParallel;
3307  storeLeadQ[mi.li_store_dev_ib] = (Qeqbs + Qeqbd - Qeqgb)*mi.numberParallel;
3308  }
3309  }
3310 
3311  return true;
3312 }
3313 
3314 #ifndef Xyce_NONPOINTER_MATRIX_LOAD
3315 //-----------------------------------------------------------------------------
3316 // Function : Master::loadDAEMatrices
3317 // Purpose :
3318 // Special Notes :
3319 // Scope : public
3320 // Creator : Eric Keiter, SNL
3321 // Creation Date : 11/26/08
3322 //-----------------------------------------------------------------------------
3323 bool Master::loadDAEMatrices (N_LAS_Matrix & dFdx, N_LAS_Matrix & dQdx)
3324 {
3325  for (InstanceVector::const_iterator it = getInstanceBegin(); it != getInstanceEnd(); ++it)
3326  {
3327  Instance & mi = *(*it);
3328 
3329  // F-matrix:
3330 
3331  *mi.f_DrainEquDrainNodePtr +=
3333 
3336 
3337 
3340 
3343 
3344 
3345  *mi.f_BulkEquBulkNodePtr +=
3346  (mi.gbs+mi.gbd)*mi.numberParallel;
3347 
3349 
3351 
3352 
3355 
3357  mi.Gm*mi.numberParallel;
3358 
3360  (-mi.gbd+mi.Gmbs)*mi.numberParallel;
3361 
3363  (mi.drainConductance+mi.gds+mi.gbd+mi.revsum)*mi.numberParallel;
3364 
3366  (-mi.gds-mi.nrmsum)*mi.numberParallel;
3367 
3368 
3370  mi.Gm*mi.numberParallel;
3371 
3374 
3376  (mi.gbs+mi.Gmbs)*mi.numberParallel;
3377 
3379  (mi.gds+mi.revsum)*mi.numberParallel;
3380 
3382  (mi.sourceConductance+mi.gds+mi.gbs+mi.nrmsum)*mi.numberParallel;
3383 
3384  // Q-matrix:
3385  double gcgd(0.0); // d(cqgd)/dVgd
3386  double gcgs(0.0); // d(cqgs)/dVgs
3387  double gcgb(0.0); // d(cqgb)/dVgb
3388  double gcbs(0.0); // d(cqbs)/dVbs
3389  double gcbd(0.0); // d(cqbd)/dVbd
3390 
3391  // get at the "conductances" for the gate capacitors with this trick
3392  // gcgd = model_.dtype*Capgd;
3393  // gcgs = model_.dtype*Capgs;
3394  // gcgb = model_.dtype*Capgb;
3395  //
3396  // In the loadRHS function, these would all be multiplied by
3397  // getSolverState().pdt. Here, for *mi.q_, the pdt term is left out.
3398  if (getSolverState().tranopFlag || getSolverState().acopFlag || getSolverState().transientFlag)
3399  {
3400  gcgd = mi.Capgd;
3401  gcgs = mi.Capgs;
3402  gcgb = mi.Capgb;
3403  // get at the two parasitic caps the same way
3404  gcbs = mi.capbs;
3405  gcbd = mi.capbd;
3406  }
3407 
3408 
3409  *mi.q_GateEquGateNodePtr +=
3410  (gcgd+gcgs+gcgb)*mi.numberParallel;
3411 
3412  *mi.q_GateEquBulkNodePtr -= gcgb*mi.numberParallel;
3413 
3415 
3417 
3418 
3419  *mi.q_BulkEquGateNodePtr -= gcgb*mi.numberParallel;
3420 
3421  *mi.q_BulkEquBulkNodePtr +=
3422  (+gcbs+gcbd+gcgb)*mi.numberParallel;
3423 
3425 
3427  +gcbs*mi.numberParallel;
3428 
3429 
3431  -gcgd*mi.numberParallel;
3432 
3434  -gcbd*mi.numberParallel;
3435 
3437  (+gcbd+gcgd)*mi.numberParallel;
3438 
3439 
3441  gcgs*mi.numberParallel;
3442 
3444  +gcbs*mi.numberParallel;
3445 
3447  (+gcbs+gcgs)*mi.numberParallel;
3448  }
3449 
3450  return true;
3451 }
3452 #else
3453 //-----------------------------------------------------------------------------
3454 // Function : Master::loadDAEMatrices
3455 // Purpose :
3456 // Special Notes :
3457 // Scope : public
3458 // Creator : Eric Keiter, SNL
3459 // Creation Date : 11/26/08
3460 //-----------------------------------------------------------------------------
3461 bool Master::loadDAEMatrices (N_LAS_Matrix & dFdx, N_LAS_Matrix & dQdx)
3462 {
3463  bool bsuccess = true;
3464 
3465  for (InstanceVector::const_iterator it = instanceContainer.begin(); it != instanceContainer.end(); ++it)
3466  {
3467  Instance & mi = *(*it);
3468 
3469  // F-matrix:
3470 
3471  dFdx[mi.li_Drain][mi.ADrainEquDrainNodeOffset] +=
3473 
3474  dFdx[mi.li_Drain][mi.ADrainEquDrainPrimeNodeOffset] -=
3476 
3477 
3478  dFdx[mi.li_Source][mi.ASourceEquSourceNodeOffset] +=
3480 
3483 
3484 
3485  dFdx[mi.li_Bulk][mi.ABulkEquBulkNodeOffset] +=
3486  (mi.gbs+mi.gbd)*mi.numberParallel;
3487 
3489 
3491 
3492 
3495 
3497  mi.Gm*mi.numberParallel;
3498 
3500  (-mi.gbd+mi.Gmbs)*mi.numberParallel;
3501 
3503  (mi.drainConductance+mi.gds+mi.gbd+mi.revsum)*mi.numberParallel;
3504 
3506  (-mi.gds-mi.nrmsum)*mi.numberParallel;
3507 
3508 
3510  mi.Gm*mi.numberParallel;
3511 
3514 
3516  (mi.gbs+mi.Gmbs)*mi.numberParallel;
3517 
3519  (mi.gds+mi.revsum)*mi.numberParallel;
3520 
3522  (mi.sourceConductance+mi.gds+mi.gbs+mi.nrmsum)*mi.numberParallel;
3523 
3524  // Q-matrix:
3525  double gcgd(0.0); // d(cqgd)/dVgd
3526  double gcgs(0.0); // d(cqgs)/dVgs
3527  double gcgb(0.0); // d(cqgb)/dVgb
3528  double gcbs(0.0); // d(cqbs)/dVbs
3529  double gcbd(0.0); // d(cqbd)/dVbd
3530 
3531  // get at the "conductances" for the gate capacitors with this trick
3532  // gcgd = model_.dtype*Capgd;
3533  // gcgs = model_.dtype*Capgs;
3534  // gcgb = model_.dtype*Capgb;
3535  //
3536  // In the loadRHS function, these would all be multiplied by
3537  // getSolverState().pdt. Here, for dQdx, the pdt term is left out.
3538  if (getSolverState().tranopFlag || getSolverState().acopFlag || getSolverState().transientFlag)
3539  {
3540  gcgd = mi.Capgd;
3541  gcgs = mi.Capgs;
3542  gcgb = mi.Capgb;
3543  // get at the two parasitic caps the same way
3544  gcbs = mi.capbs;
3545  gcbd = mi.capbd;
3546  }
3547 
3548 
3549  dQdx[mi.li_Gate][mi.AGateEquGateNodeOffset] +=
3550  (gcgd+gcgs+gcgb)*mi.numberParallel;
3551 
3552  dQdx[mi.li_Gate][mi.AGateEquBulkNodeOffset] -= gcgb*mi.numberParallel;
3553 
3554  dQdx[mi.li_Gate][mi.AGateEquDrainPrimeNodeOffset] -= gcgd*mi.numberParallel;
3555 
3556  dQdx[mi.li_Gate][mi.AGateEquSourcePrimeNodeOffset] -= gcgs*mi.numberParallel;
3557 
3558 
3559  dQdx[mi.li_Bulk][mi.ABulkEquGateNodeOffset] -= gcgb*mi.numberParallel;
3560 
3561  dQdx[mi.li_Bulk][mi.ABulkEquBulkNodeOffset] +=
3562  (+gcbs+gcbd+gcgb)*mi.numberParallel;
3563 
3564  dQdx[mi.li_Bulk][mi.ABulkEquDrainPrimeNodeOffset] -= +gcbd*mi.numberParallel;
3565 
3566  dQdx[mi.li_Bulk][mi.ABulkEquSourcePrimeNodeOffset] -=
3567  +gcbs*mi.numberParallel;
3568 
3569 
3571  -gcgd*mi.numberParallel;
3572 
3574  -gcbd*mi.numberParallel;
3575 
3577  (+gcbd+gcgd)*mi.numberParallel;
3578 
3579 
3581  gcgs*mi.numberParallel;
3582 
3584  +gcbs*mi.numberParallel;
3585 
3587  (+gcbs+gcgs)*mi.numberParallel;
3588  }
3589  return true;
3590 }
3591 #endif
3592 
3593 Device *Traits::factory(const Configuration &configuration, const FactoryBlock &factory_block)
3594 {
3595 
3596  return new Master(configuration, factory_block, factory_block.solverState_, factory_block.deviceOptions_);
3597 }
3598 
3600 {
3602  .registerDevice("m", 6)
3603  .registerModelType("pmos", 6)
3604  .registerModelType("nmos", 6);
3605 }
3606 
3607 } // namespace MOSFET6
3608 } // namespace Device
3609 } // namespace Xyce