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