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