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