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