Xyce  6.1
N_DEV_Digital.C
Go to the documentation of this file.
1 //-----------------------------------------------------------------------------
2 // Copyright Notice
3 //
4 // Copyright 2002 Sandia Corporation. Under the terms
5 // of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S.
6 // Government retains certain rights in this software.
7 //
8 // Xyce(TM) Parallel Electrical Simulator
9 // Copyright (C) 2002-2015 Sandia Corporation
10 //
11 // This program is free software: you can redistribute it and/or modify
12 // it under the terms of the GNU General Public License as published by
13 // the Free Software Foundation, either version 3 of the License, or
14 // (at your option) any later version.
15 //
16 // This program is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 // GNU General Public License for more details.
20 //
21 // You should have received a copy of the GNU General Public License
22 // along with this program. If not, see <http://www.gnu.org/licenses/>.
23 //-----------------------------------------------------------------------------
24 
25 //-------------------------------------------------------------------------
26 // Filename : $RCSfile: N_DEV_Digital.C,v $
27 //
28 // Purpose :
29 //
30 // Special Notes :
31 //
32 // Creator : Dave Shirley, PSSI
33 //
34 // Creation Date : 01/05/06
35 //
36 // Revision Information:
37 // ---------------------
38 //
39 // Revision Number: $Revision: 1.110.2.1 $
40 //
41 // Revision Date : $Date: 2015/04/02 18:20:11 $
42 //
43 // Current Owner : $Author: tvrusso $
44 //-------------------------------------------------------------------------
45 #include <Xyce_config.h>
46 
47 // ---------- Standard Includes ----------
48 #include <N_UTL_Math.h>
49 #include <iostream>
50 #include <sstream>
51 
52 #include <N_DEV_Const.h>
53 #include <N_DEV_DeviceMaster.h>
54 #include <N_DEV_DeviceOptions.h>
55 #include <N_DEV_Digital.h>
56 #include <N_DEV_ExternData.h>
57 #include <N_DEV_MatrixLoadData.h>
58 #include <N_DEV_Message.h>
59 #include <N_DEV_SolverState.h>
60 #include <N_ERH_ErrorMgr.h>
61 #include <N_LAS_Matrix.h>
62 #include <N_LAS_Vector.h>
63 #include <N_UTL_BreakPoint.h>
64 #include <N_UTL_FeatureTest.h>
65 
66 namespace Xyce {
67 namespace Device {
68 namespace Digital {
69 
70 // enables debug output for just the digital devices
71 //static const int DEBUG_DEVICE = 1;
72 
74 {
75 // Set up double precision variables:
76 
77  // Set up non-double precision variables:
78  p.addPar ("IC1", false, &Digital::Instance::ic1)
79  .setUnit(U_LOGIC)
80  .setDescription("Vector of initial values for output(s)");
81  p.addPar ("IC2", false, &Digital::Instance::ic2);
82 
83  p.makeVector ("IC", 2);
84 }
85 
87 {
88  // Set up double precision variables:
89  p.addPar ("VLO", 0., &Digital::Model::vlo)
90  .setUnit(U_VOLT)
91  .setDescription("Internal low state supply voltage");
92 
93  p.addPar ("VHI", 0., &Digital::Model::vhi)
94  .setUnit(U_VOLT)
95  .setDescription("Internal high state supply voltage");
96 
97  p.addPar ("VREF", 0., &Digital::Model::vref)
98  .setUnit(U_VOLT)
99  .setDescription("Internal reference voltage for inputs");
100 
101  p.addPar ("CLO", 1.e-6, &Digital::Model::clo)
102  .setUnit(U_FARAD)
103  .setDescription("Capacitance between output node and low reference");
104 
105  p.addPar ("CHI", 1.e-6, &Digital::Model::chi)
106  .setUnit(U_FARAD)
107  .setDescription("Capacitance between output node and high reference");
108 
109  p.addPar ("CLOAD", 1.e-6, &Digital::Model::cload)
110  .setUnit(U_FARAD)
111  .setDescription("Capacitance between input node and input reference");
112 
113  p.addPar ("RLOAD", 1000., &Digital::Model::rload)
114  .setUnit(U_OHM)
115  .setDescription("Resistance between input node and input reference");
116 
117  p.addPar ("S0RLO", 100., &Digital::Model::s0rlo)
118  .setUnit(U_OHM)
119  .setDescription("Low state resistance between output node and low reference");
120 
121  p.addPar ("S0RHI", 100., &Digital::Model::s0rhi)
122  .setUnit(U_OHM)
123  .setDescription("Low state resitance between output node and high reference");
124 
125  p.addPar ("S0TSW", 1.e-8, &Digital::Model::s0tsw)
126  .setUnit(U_SECOND)
127  .setDescription("Switching time transition to low state");
128 
129  p.addPar ("S0VLO", -1.5, &Digital::Model::s0vlo)
130  .setUnit(U_VOLT)
131  .setDescription("Minimum voltage to switch to low state");
132 
133  p.addPar ("S0VHI", 1.7, &Digital::Model::s0vhi)
134  .setUnit(U_VOLT)
135  .setDescription("Maximum voltage to switch to low state");
136 
137  p.addPar ("S1RLO", 100., &Digital::Model::s1rlo)
138  .setUnit(U_OHM)
139  .setDescription("High state resistance between output node and low reference");
140 
141  p.addPar ("S1RHI", 100., &Digital::Model::s1rhi)
142  .setUnit(U_OHM)
143  .setDescription("High state resistance between output node and high reference");
144 
145  p.addPar ("S1TSW", 1.e-8, &Digital::Model::s1tsw)
146  .setUnit(U_SECOND)
147  .setDescription("Switching time transition to high state");
148 
149  p.addPar ("S1VLO", 0.9, &Digital::Model::s1vlo)
150  .setUnit(U_VOLT)
151  .setDescription("Minimum voltage to switch to high state");
152 
153  p.addPar ("S1VHI", 7.0, &Digital::Model::s1vhi)
154  .setUnit(U_VOLT)
155  .setDescription("Maximum voltage to switch to high state");
156 
157  p.addPar ("DELAY", 1.e-8, &Digital::Model::delay)
158  .setUnit(U_SECOND)
159  .setDescription("Delay time of device");
160 }
161 
162 // Class Instance
163 //-----------------------------------------------------------------------------
164 // Function : Instance::processParams
165 // Purpose :
166 // Special Notes :
167 // Scope : public
168 // Creator : Dave Shirley, PSSI
169 // Creation Date : 01/05/06
170 //-----------------------------------------------------------------------------
172 {
173 
174  // If there are any time dependent parameters, set their values for
175  // the current time.
176 
177  return true;
178 }
179 
180 //-----------------------------------------------------------------------------
181 // Function : Instance::Instance
182 // Purpose : instance block constructor
183 // Special Notes :
184 // Scope : public
185 // Creator : Dave Shirley, PSSI
186 // Creation Date : 01/05/06
187 //-----------------------------------------------------------------------------
189  const Configuration & configuration,
190  const InstanceBlock & instance_block,
191  Model & model,
192  const FactoryBlock & factory_block)
193  : DeviceInstance(instance_block, configuration.getInstanceParameters(), factory_block),
194  model_(model),
195  li_Lo(-1),
196  li_Hi(-1),
197  li_Ref(-1),
198  row_Lo(-1),
199  row_Hi(-1),
200  row_Ref(-1),
201  breakTime(0.)
202 {
203  // added for debug purposes for tracking input/output state changes
204  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
205  {
207  inputStateChange_ = false;
208  }
209 
210  int dev_numInputs = 0;
211 
212  char dev_letter = getName().getDeviceLetter();
213 
214  numExtVars = 0;
215  // Code required to support both Y-style and U-style digital devices.
216  // Y digital devices are now deprecated.
217  if (dev_letter == 'U') {
218  dev_numInputs = getName().getNumInputs();
219 
220  // For U devices, DPWR and DGND are always specified on the instance line.
221  // Warning message if VHI, VLO or VREF are in the model card.
222  li_Lo = 0;
223  li_Hi = 0;
224  li_Ref = 0;
225  numExtVars += 2;
226  if (model_.given("VLO"))
227  {
228  UserWarning(*this)<< "VLO model parameter ignored for U digital device";
229  }
230  if (model_.given("VHI"))
231  {
232  UserWarning(*this)<< "VHI model parameter ignored for U digital device";
233  }
234  if (model_.given("VREF"))
235  {
236  UserWarning(*this)<< "VREF model parameter ignored for U digital device";
237  }
238  }
239  else if (dev_letter == 'Y')
240  {
241  // legacy code required to support VLO, VHI and VREF variables
242  // being on the instance line rather than in model card in Y devices
243  UserWarning(*this)<< "Y digital device (" << getName() << ") is deprecated. Consider using U device instead.";
244  if (!model_.given("VLO"))
245  {
246  li_Lo = 0;
247  ++numExtVars;
248  }
249  if (!model_.given("VHI"))
250  {
251  li_Hi = 0;
252  ++numExtVars;
253  }
254  if (!model_.given("VREF"))
255  {
256  li_Ref = 0;
257  ++numExtVars;
258  }
259  }
260  else
261  {
262  UserError0(*this) << "Digital device letter must be Y or U: " << getName();
263  return;
264  }
265 
266  // Configure number of inputs/outputs for each device
267  // Y devices are limited to 2 inputs.
268  std::string dev_type = getName().getDeviceType();
269 
270  if (dev_type == "NOT" || dev_type == "INV")
271  {
272  if (dev_type == "NOT")
273  {
274  UserWarning(*this)<< "NOT gate type (" << getName() << ") is deprecated. Consider using INV instead.";
275  }
276  numInput = 1;
277  numOutput = 1;
278  gate = INV;
279  }
280  else if (dev_type == "AND")
281  {
282  numInput = (dev_letter == 'Y') ? 2 : dev_numInputs;
283  numOutput = 1;
284  gate = AND;
285  }
286  else if (dev_type == "NAND")
287  {
288  numInput = (dev_letter == 'Y') ? 2 : dev_numInputs;
289  numOutput = 1;
290  gate = NAND;
291  }
292  else if (dev_type == "OR")
293  {
294  numInput = (dev_letter == 'Y') ? 2 : dev_numInputs;
295  numOutput = 1;
296  gate = OR;
297  }
298  else if (dev_type == "NOR")
299  {
300  numInput = (dev_letter == 'Y') ? 2 : dev_numInputs;
301  numOutput = 1;
302  gate = NOR;
303  }
304  else if (dev_type == "ADD")
305  {
306  numInput = 3;
307  numOutput = 2;
308  gate = ADD;
309  }
310  else if (dev_type == "XOR")
311  {
312  numInput = 2;
313  numOutput = 1;
314  gate = XOR;
315  }
316  else if (dev_type == "NXOR")
317  {
318  numInput = 2;
319  numOutput = 1;
320  gate = NXOR;
321  }
322  else if (dev_type == "DFF")
323  {
324  numInput = 4; //PREB, CLRB, clock, data
325  numOutput = 2; //Q, Q_bar
326  gate = DFF;
327  }
328  else if (dev_type == "DLTCH")
329  {
330  numInput = 4; // PREB, CLRB, Enable, Data
331  numOutput = 2; // Q, Q_bar
332  gate = DLTCH;
333  }
334  else if (dev_type == "BUF")
335  {
336  numInput = 1;
337  numOutput = 1;
338  gate = BUF;
339  }
340  else
341  {
342  UserError0(*this) << "Unknown digital device type " << dev_type;
343  return;
344  }
345 
346  int iBase = numExtVars;
347  int oBase = numExtVars + numInput;
348  numExtVars += numInput + numOutput;
349 
350  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
351  {
352  Xyce::dout() << "Digital Device " << getName() << " has iBase = " <<
353  iBase << ", oBase = " << oBase << ", numExtVars = " <<
354  numExtVars << std::endl;
355  }
356 
357  // catch cases of AND, NAND, OR or NOR gate with only one input specified
358  // or the number of nodes on the instance line does not match the
359  // (N) value specified as part of the gate type (e.g, AND(4))
360  if ((gate == AND) || (gate == NAND) || (gate == OR) || (gate == NOR))
361  {
362  if (numInput == 1)
363  {
364  UserError0(*this) << "this device must have more than one input.";
365  }
366  if ( (dev_numInputs != 0) && (instance_block.numExtVars - iBase - numOutput != dev_numInputs) )
367  {
368  std::cout << instance_block.numExtVars << " " << dev_numInputs << " " << numExtVars << std::endl;
369  UserError0(*this) << "too few I/O nodes on instance line.";
370  }
371  }
372  // catch case where gates with a fixed number of inputs have
373  // wrong number of inputs
374  if (numExtVars != instance_block.numExtVars)
375  {
376  UserError0(*this) << "Incorrect number of nodes in digital device "
377  << ". Found " << instance_block.numExtVars << ", should be " << numExtVars;
378  }
379 
380  numIntVars = 0;
381  numStateVars = 4*numInput + 6*numOutput;
382 
383  li_Inp.resize(numInput);
384  li_currentStateInp.resize(numInput);
385  li_transitionTimeInp.resize(numInput);
386  li_QinpState.resize(numInput);
387  li_IinpState.resize(numInput);
388  li_Out.resize(numOutput);
389  li_currentStateOut.resize(numOutput);
390  li_transitionTimeOut.resize(numOutput);
391  li_QloState.resize(numOutput);
392  li_IloState.resize(numOutput);
393  li_QhiState.resize(numOutput);
394  li_IhiState.resize(numOutput);
395 
396  qlo.resize(numOutput);
397  ilo.resize(numOutput);
398  vcaplo.resize(numOutput);
399  qhi.resize(numOutput);
400  ihi.resize(numOutput);
401  vcaphi.resize(numOutput);
402  qref.resize(numInput);
403  iref.resize(numInput);
404  vcapref.resize(numInput);
405  rilo.resize(numOutput);
406  rihi.resize(numOutput);
407  riref.resize(numInput);
408  currentOut.resize(numOutput);
409  currentIn.resize(numInput);
410  glo.resize(numOutput);
411  ghi.resize(numOutput);
412 
413  qInp.resize(numInput);
414  iInp.resize(numInput);
415  vcapInp.resize(numInput);
416  currentInp.resize(numInput);
417 
418  inpL.resize(numInput);
419  iTime.resize(numInput);
420  outL.resize(numOutput);
421  oTime.resize(numOutput);
422 
423  // These are to store the indicies into the jacobian for the four element
424  // stamps for the capacitor/resistors connected to the input/outputs. The
425  // format is to have 6 int vectors for each stamp with format:
426  // (row 1, col 1, col 2, row 2, col 1, col 2). These will be replaced in
427  // registerJacLIDs with the indicies into the actual jacobian matrix.
428 
429  li_jac_Ref.resize(numInput);
430  li_jac_Hi.resize(numOutput);
431  li_jac_Lo.resize(numOutput);
432 
433  devConMap.resize(numExtVars);
434  for (int i=0 ; i<numExtVars ; ++i)
435  devConMap[i] = 1;
436 
437  jacStamp.resize(numExtVars);
438  int row = 0;
439  // Code required to support both Y-style and U-style digital devices.
440  // Y digital devices are now deprecated.
441  if (dev_letter == 'U')
442  {
443  // digital power and digital ground node are always on
444  // the instance line for a U device. The low reference
445  // voltage for inputs is assumed to be the same as the
446  // digital ground node.
447  row_Hi = row;
448  jacStamp[row].push_back(row);
449  for (int i=0 ; i<numOutput ; ++i)
450  {
451  li_jac_Hi[i].push_back(row);
452  li_jac_Hi[i].push_back(0);
453  li_jac_Hi[i].push_back(jacStamp[row].size());
454  li_jac_Hi[i].push_back(oBase+i);
455  li_jac_Hi[i].push_back(jacStamp[oBase+i].size());
456  jacStamp[row].push_back(oBase+i);
457  jacStamp[oBase+i].push_back(row);
458  }
459  ++row;
460 
461  row_Lo = row;
462  jacStamp[row].push_back(row);
463  for (int i=0 ; i<numOutput ; ++i)
464  {
465  li_jac_Lo[i].push_back(row);
466  li_jac_Lo[i].push_back(0);
467  li_jac_Lo[i].push_back(jacStamp[row].size());
468  li_jac_Lo[i].push_back(oBase+i);
469  li_jac_Lo[i].push_back(jacStamp[oBase+i].size());
470  jacStamp[row].push_back(oBase+i);
471  jacStamp[oBase+i].push_back(row);
472  }
473 
474  row_Ref = row;
475  for (int i=0 ; i<numInput ; ++i)
476  {
477  li_jac_Ref[i].push_back(row);
478  li_jac_Ref[i].push_back(0);
479  li_jac_Ref[i].push_back(1);
480  li_jac_Ref[i].push_back(iBase+i);
481  li_jac_Ref[i].push_back(jacStamp[iBase+i].size());
482  jacStamp[row].push_back(iBase+i);
483  jacStamp[iBase+i].push_back(row);
484  }
485  }
486  else if (dev_letter == 'Y')
487  {
488  // output low and output high reference voltages and input
489  // low reference voltage are optionally on the instance line
490  // for Y devices.
491  if (li_Lo == 0)
492  {
493  row_Lo = row;
494  jacStamp[row].push_back(row);
495  for (int i=0 ; i<numOutput ; ++i)
496  {
497  li_jac_Lo[i].push_back(row);
498  li_jac_Lo[i].push_back(0);
499  li_jac_Lo[i].push_back(jacStamp[row].size());
500  li_jac_Lo[i].push_back(oBase+i);
501  li_jac_Lo[i].push_back(jacStamp[oBase+i].size());
502  jacStamp[row].push_back(oBase+i);
503  jacStamp[oBase+i].push_back(row);
504  }
505  ++row;
506  }
507  if (li_Hi == 0)
508  {
509  row_Hi = row;
510  jacStamp[row].push_back(row);
511  for (int i=0 ; i<numOutput ; ++i)
512  {
513  li_jac_Hi[i].push_back(row);
514  li_jac_Hi[i].push_back(0);
515  li_jac_Hi[i].push_back(jacStamp[row].size());
516  li_jac_Hi[i].push_back(oBase+i);
517  li_jac_Hi[i].push_back(jacStamp[oBase+i].size());
518  jacStamp[row].push_back(oBase+i);
519  jacStamp[oBase+i].push_back(row);
520  }
521  ++row;
522  }
523  if (li_Ref == 0)
524  {
525  row_Ref = row;
526  jacStamp[row].push_back(row);
527  for (int i=0 ; i<numInput ; ++i)
528  {
529  li_jac_Ref[i].push_back(row);
530  li_jac_Ref[i].push_back(0);
531  li_jac_Ref[i].push_back(jacStamp[row].size());
532  li_jac_Ref[i].push_back(iBase+i);
533  li_jac_Ref[i].push_back(jacStamp[iBase+i].size());
534  jacStamp[row].push_back(iBase+i);
535  jacStamp[iBase+i].push_back(row);
536  }
537  ++row;
538  }
539  }
540  else
541  {
542  UserError0(*this) << "Digital device letter must be Y or U: " << getName();
543  return;
544  }
545 
546  for (int i=0 ; i<numInput ; ++i)
547  {
548  if (li_Ref == 0)
549  {
550  li_jac_Ref[i].push_back(jacStamp[iBase+i].size());
551  }
552  else
553  {
554  li_jac_Ref[i].push_back(iBase+i);
555  }
556  jacStamp[iBase+i].push_back(iBase+i);
557  }
558  for (int i=0 ; i<numOutput ; ++i)
559  {
560  if (li_Lo == 0)
561  {
562  li_jac_Lo[i].push_back(jacStamp[oBase+i].size());
563  }
564  else
565  {
566  li_jac_Lo[i].push_back(oBase+i);
567  }
568  if (li_Hi == 0)
569  {
570  li_jac_Hi[i].push_back(jacStamp[oBase+i].size());
571  }
572  else
573  {
574  li_jac_Hi[i].push_back(oBase+i);
575  }
576  jacStamp[oBase+i].push_back(oBase+i);
577  }
578 
579  // Set params to constant default values:
580  setDefaultParams ();
581 
582  // Set params according to instance line and constant defaults from metadata:
583  setParams (instance_block.params);
584 
585  // Set any non-constant parameter defaults:
586 
587  // Calculate any parameters specified as expressions:
589 
590  // calculate dependent (ie computed) params:
591  processParams ();
592 }
593 
594 //-----------------------------------------------------------------------------
595 // Function : Instance::~Instance
596 // Purpose : destructor
597 // Special Notes :
598 // Scope : public
599 // Creator : Dave Shirley, PSSI
600 // Creation Date : 01/05/06
601 //-----------------------------------------------------------------------------
603 {}
604 
605 // Additional Declarations
606 
607 //-----------------------------------------------------------------------------
608 // Function : Instance::registerLIDs
609 // Purpose :
610 // Special Notes :
611 // Scope : public
612 // Creator : Dave Shirley, PSSI
613 // Creation Date : 01/05/06
614 //-----------------------------------------------------------------------------
615 void Instance::registerLIDs( const std::vector<int> & intLIDVecRef,
616  const std::vector<int> & extLIDVecRef)
617 
618 {
619  std::string msg;
620 
621  // Check if the size of the ID lists corresponds to the proper number of
622  // internal and external variables.
623  int numInt = intLIDVecRef.size();
624  int numExt = extLIDVecRef.size();
625 
626  if (numInt != numIntVars)
627  {
628  msg = "Instance::registerLIDs:";
629  msg += "numInt != numIntVars";
630  N_ERH_ErrorMgr::report( N_ERH_ErrorMgr::DEV_FATAL,msg);
631  }
632 
633  if (numExt != numExtVars)
634  {
635  msg = "Instance::registerLIDs:";
636  msg += "numExt != numExtVars";
637  N_ERH_ErrorMgr::report(N_ERH_ErrorMgr::DEV_FATAL, msg);
638  }
639 
640  // Copy over the local ID lists:
641  intLIDVec = intLIDVecRef;
642  extLIDVec = extLIDVecRef;
643 
644  // Now use these lists to obtain the indices into the linear algebra
645  // entities. This assumes an order. For the matrix indices, first do the
646  // rows.
647 
648  int i=0, j;
649  // Code required to support both Y-style and U-style digital devices.
650  // Y digital devices are now deprecated
651  char dev_letter = getName().getDeviceLetter();
652  if (dev_letter == 'U')
653  {
654  // ordering on U-device instance line is dig_power_node (DPWR) then
655  // dig_ground_node (DGND). Assume that input low-reference
656  // voltage (VREF in Y devices) is equal to DGND.
657  li_Hi = extLIDVec[i++];
658  li_Lo = extLIDVec[i++];
659  li_Ref = li_Lo;
660  }
661  else if (dev_letter == 'Y')
662  {
663  // for Y devices, ordering of output high/low reference nodes (VHI/VLO)
664  // on instance line is reversed. Input low-reference voltage (VREF),
665  // VHI and VLO can either be on the instance line or in the model card.
666  if (li_Lo == 0)
667  li_Lo = extLIDVec[i++];
668  if (li_Hi == 0)
669  li_Hi = extLIDVec[i++];
670  if (li_Ref == 0)
671  li_Ref = extLIDVec[i++];
672  }
673  else
674  {
675  UserError0(*this) << "Digital device letter must be Y or U: " << getName();
676  }
677 
678  for (j=0 ; j<numInput ; ++j)
679  li_Inp[j] = extLIDVec[i++];
680  for (j=0 ; j<numOutput ; ++j)
681  li_Out[j] = extLIDVec[i++];
682 }
683 
684 //-----------------------------------------------------------------------------
685 // Function : Instance::registerStateLIDs
686 // Purpose :
687 // Special Notes :
688 // Scope : public
689 // Creator : Dave Shirley, PSSI
690 // Creation Date : 01/05/06
691 //-----------------------------------------------------------------------------
692 void Instance::registerStateLIDs( const std::vector<int> & staLIDVecRef)
693 {
694  std::string msg;
695 
696  // Check if the size of the ID lists corresponds to the proper number of
697  // internal and external variables.
698  int numSta = staLIDVecRef.size();
699 
700  if (numSta != numStateVars)
701  {
702  msg = "Instance::registerStateLIDs:";
703  msg += "numSta != numStateVars";
704  N_ERH_ErrorMgr::report(N_ERH_ErrorMgr::DEV_FATAL, msg);
705  }
706 
707  // Copy over the global ID lists:
708  staLIDVec = staLIDVecRef;
709 
710  int j=0;
711 
712  for (int i=0 ; i<numInput ; ++i)
713  {
714  li_currentStateInp[i] = staLIDVec[j++];
716  li_QinpState[i] = staLIDVec[j++];
717  li_IinpState[i] = staLIDVec[j++];
718  }
719 
720  for (int i=0 ; i<numOutput ; ++i)
721  {
722  li_currentStateOut[i] = staLIDVec[j++];
724  li_QloState[i] = staLIDVec[j++];
725  li_IloState[i] = staLIDVec[j++];
726  li_QhiState[i] = staLIDVec[j++];
727  li_IhiState[i] = staLIDVec[j++];
728  }
729 }
730 
731 //-----------------------------------------------------------------------------
732 // Function : Instance::loadNodeSymbols
733 // Purpose :
734 // Special Notes :
735 // Scope : public
736 // Creator : Eric R. Keiter, SNL, Parallel Computational Sciences
737 // Creation Date : 05/13/05
738 //-----------------------------------------------------------------------------
739 void Instance::loadNodeSymbols(Util::SymbolTable &symbol_table) const
740 {
741 }
742 
743 //-----------------------------------------------------------------------------
744 // Function : Instance::jacobianStamp
745 // Purpose :
746 // Special Notes :
747 // Scope : public
748 // Creator : Dave Shirley, PSSI
749 // Creation Date : 01/05/06
750 //-----------------------------------------------------------------------------
751 const std::vector< std::vector<int> > & Instance::jacobianStamp() const
752 {
753  return jacStamp;
754 }
755 
756 //-----------------------------------------------------------------------------
757 // Function : Instance::registerJacLIDs
758 // Purpose :
759 // Special Notes :
760 // Scope : public
761 // Creator : Dave Shirley, PSSI
762 // Creation Date : 01/05/06
763 //-----------------------------------------------------------------------------
764 void Instance::registerJacLIDs( const std::vector< std::vector<int> > & jacLIDVec )
765 {
766  DeviceInstance::registerJacLIDs( jacLIDVec );
767  int iBase = numExtVars - numInput - numOutput;
768  int oBase = iBase + numInput;
769  int lo_present, hi_present;
770 
771  (row_Lo < 0) ? (lo_present = 0) : (lo_present = 1);
772  (row_Hi < 0) ? (hi_present = 0) : (hi_present = 1);
773 
774  // Code required to support both Y-style and U-style digital devices.
775  // Y digital devices are now deprecated.
776  char dev_letter = getName().getDeviceLetter();
777 
778  if (dev_letter == 'U')
779  {
780  if ( (row_Lo == -1) || (row_Hi == -1) || (row_Ref == -1) )
781  {
782  UserError0(*this) << "Internal error in Instance::registerJacLIDs() for " << getName();
783  }
784  else
785  {
786  for (int i=0 ; i<numInput ; ++i)
787  {
788  li_jac_Ref[i][1] = jacLIDVec[li_jac_Ref[i][0]][li_jac_Ref[i][1]];
789  li_jac_Ref[i][2] = jacLIDVec[li_jac_Ref[i][0]][li_jac_Ref[i][2]];
790  li_jac_Ref[i][4] = jacLIDVec[li_jac_Ref[i][3]][li_jac_Ref[i][4]];
791  li_jac_Ref[i][5] = jacLIDVec[li_jac_Ref[i][3]][li_jac_Ref[i][5]];
792  }
793 
794  for (int i=0 ; i<numOutput ; ++i)
795  {
796  li_jac_Lo[i][1] = jacLIDVec[li_jac_Lo[i][0]][li_jac_Lo[i][1]];
797  li_jac_Lo[i][2] = jacLIDVec[li_jac_Lo[i][0]][li_jac_Lo[i][2]];
798  li_jac_Lo[i][4] = jacLIDVec[li_jac_Lo[i][3]][li_jac_Lo[i][4]];
799  li_jac_Lo[i][5] = jacLIDVec[li_jac_Lo[i][3]][li_jac_Lo[i][5]];
800  }
801 
802  for (int i=0 ; i<numOutput ; ++i)
803  {
804  li_jac_Hi[i][1] = jacLIDVec[li_jac_Hi[i][0]][li_jac_Hi[i][1]];
805  li_jac_Hi[i][2] = jacLIDVec[li_jac_Hi[i][0]][li_jac_Hi[i][2]];
806  li_jac_Hi[i][4] = jacLIDVec[li_jac_Hi[i][3]][li_jac_Hi[i][4]];
807  li_jac_Hi[i][5] = jacLIDVec[li_jac_Hi[i][3]][li_jac_Hi[i][5]];
808  }
809  }
810  }
811  else if (dev_letter == 'Y')
812  {
813  // row_Ref == -1 means that VREF is in the model card
814  if (row_Ref == -1)
815  {
816  for (int i=0 ; i<numInput ; ++i)
817  {
818  li_jac_Ref[i].push_back(jacLIDVec[li_jac_Ref[i][0]][0]);
819  }
820  }
821  else
822  {
823  // this for loop is identical for both U and Y devices
824  for (int i=0 ; i<numInput ; ++i)
825  {
826  li_jac_Ref[i][1] = jacLIDVec[li_jac_Ref[i][0]][li_jac_Ref[i][1]];
827  li_jac_Ref[i][2] = jacLIDVec[li_jac_Ref[i][0]][li_jac_Ref[i][2]];
828  li_jac_Ref[i][4] = jacLIDVec[li_jac_Ref[i][3]][li_jac_Ref[i][4]];
829  li_jac_Ref[i][5] = jacLIDVec[li_jac_Ref[i][3]][li_jac_Ref[i][5]];
830  }
831  }
832 
833  // row_Lo == -1 means that VLO is in the model card
834  if (row_Lo == -1)
835  {
836  for (int i=0 ; i<numOutput ; ++i)
837  {
838  li_jac_Lo[i].push_back(jacLIDVec[li_jac_Lo[i][0]][hi_present]);
839  }
840  }
841  else
842  {
843  // this for loop is identical for both U and Y devices
844  for (int i=0 ; i<numOutput ; ++i)
845  {
846  li_jac_Lo[i][1] = jacLIDVec[li_jac_Lo[i][0]][li_jac_Lo[i][1]];
847  li_jac_Lo[i][2] = jacLIDVec[li_jac_Lo[i][0]][li_jac_Lo[i][2]];
848  li_jac_Lo[i][4] = jacLIDVec[li_jac_Lo[i][3]][li_jac_Lo[i][4]];
849  li_jac_Lo[i][5] = jacLIDVec[li_jac_Lo[i][3]][li_jac_Lo[i][5]];
850  }
851  }
852 
853  // row_Hi == -1 means that VHI is in the model card
854  if (row_Hi == -1)
855  {
856  for (int i=0 ; i<numOutput ; ++i)
857  {
858  li_jac_Hi[i].push_back(jacLIDVec[li_jac_Hi[i][0]][lo_present]);
859  }
860  }
861  else
862  {
863  // this for loop is identical for both U and Y devices
864  for (int i=0 ; i<numOutput ; ++i)
865  {
866  li_jac_Hi[i][1] = jacLIDVec[li_jac_Hi[i][0]][li_jac_Hi[i][1]];
867  li_jac_Hi[i][2] = jacLIDVec[li_jac_Hi[i][0]][li_jac_Hi[i][2]];
868  li_jac_Hi[i][4] = jacLIDVec[li_jac_Hi[i][3]][li_jac_Hi[i][4]];
869  li_jac_Hi[i][5] = jacLIDVec[li_jac_Hi[i][3]][li_jac_Hi[i][5]];
870  }
871  }
872  }
873  else
874  {
875  UserError0(*this) << "Digital device letter must be Y or U: " << getName();
876  }
877 }
878 
879 //-----------------------------------------------------------------------------
880 // Function : Instance::updatePrimaryState
881 // Purpose :
882 // Special Notes :
883 // Scope : public
884 // Creator : Dave Shirley, PSSI
885 // Creation Date : 01/05/06
886 //-----------------------------------------------------------------------------
888 {
889  //added for debug purposes, for tracking input state changes
890  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
891  {
892  inputStateChange_ = false;
893  }
894 
895  bool bsuccess = true;
896  double v_poslo, v_poshi, v_posref, v_neg;
897  double elapsed, time, frac, lastT;
898  int currentState;
899  double transitionTime;
900  bool changeState = false; //Genie 110812
901  bool clocking = false; //Genie 111212
902  //std::vector<bool> changeState; //Genie 110812
903  bool toPrint = false; //Genie 022713
904 
905  Linear::Vector & solVector = *(extData.nextSolVectorPtr);
906  Linear::Vector & staVector = *(extData.nextStaVectorPtr);
907  Linear::Vector & oldStaVector = *(extData.currStaVectorPtr);
908  Linear::Vector & oldSolVector = *(extData.currSolVectorPtr);
909 
910  // The convention in this device is to consider the 'positive' side of the
911  // capacitors as the Vsrc or node that supplies the voltage, or for the
912  // output, vref. The 'positive' voltages are thus the same for all
913  // input/outputs
914  (li_Lo >= 0) ? (v_poslo = solVector[li_Lo]) : (v_poslo = model_.vlo);
915 
916  // If VHI is not specified, li_Hi >=0 and v_poshi is derived from
917  // CLOAD/RLOAD by solVector. If VHI is specified, li_Hi == -1 and
918  // v_poshi is specified by the netlist model card.
919  (li_Hi >= 0) ? (v_poshi = solVector[li_Hi]) : (v_poshi = model_.vhi);
920  (li_Ref >= 0) ? (v_posref = solVector[li_Ref]) : (v_posref = model_.vref);
921 
922  lastT = 0;
923 
924  for (int i=0 ; i<numInput ; ++i)
925  {
926  //initialize
927  currentState = static_cast <int> (oldStaVector[li_currentStateInp[i]]);
928  transitionTime = oldStaVector[li_transitionTimeInp[i]];
929  changeState = false; //Genie 022013 Clear the memory of changeState.
930 
931  // obtain voltage drop accross the capacitor:
932  v_neg = solVector[li_Inp[i]];
933 
934  time = getSolverState().currTime;
935  elapsed = time - transitionTime;
936 
937  vcapref[i] = v_posref-v_neg;
938  riref[i] = model_.gload*(vcapref[i]);
939 
940  // Obtain the "current" value for the charge stored in the capacitors.
941  qref[i] = model_.cload*vcapref[i];
942 
943  if (getSolverState().dcopFlag)
944  {
945  transitionTime = 0;
946  (-vcapref[i] < model_.s0vhi) ? (currentState = 0) : (currentState = 1);
947 
948  oldStaVector[li_currentStateInp[i]] = currentState;
949  oldStaVector[li_transitionTimeInp[i]] = transitionTime;
950  }
951 
952  iTime[i] = transitionTime;
953 
954  staVector[li_transitionTimeInp[i]] = transitionTime;
955 
956  if (currentState == 0)
957  {
958  inpL[i] = false;
959  if ((-vcapref[i] > model_.s0vhi) && (-vcapref[i] > model_.s1vlo))
960  {
961  currentState = 1;
962  changeState = true;
963  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
964  {
965  Xyce::dout() << "Device " << getName() << " changed state from 1 to 0 at time " << getSolverState().currTime << std::endl;
966  }
967  if (gate == DFF && i == 2) // i==2 -> clk
968  {
969  clocking = true; // clock of DFF changes state
970  }
971  }
972  }
973  else
974  {
975  inpL[i] = true;
976  if ((-vcapref[i] < model_.s1vlo) && (-vcapref[i] < model_.s0vhi))
977  {
978  currentState = 0;
979  changeState = true;
980  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
981  {
982  Xyce::dout() << "Device " << getName() << " changed state from 1 to 0 at time " << getSolverState().currTime << std::endl;
983  }
984 
985  if (gate == DFF && i == 2) //Genie 111212
986  {
987  clocking = true; // clock of DFF changes state
988  }
989  }
990  }
991 
992  if (changeState)
993  {
994  double vOld, del;
995 
996  inpL[i] = (currentState == 1);
997  (li_Ref >= 0) ? (vOld = oldSolVector[li_Ref]) : (vOld = model_.vref);
998  vOld = oldSolVector[li_Inp[i]] - vOld;
999  if (fabs(vcapref[i]+vOld) < 1.e-12)
1000  del = 0;
1001  else
1002  {
1003  if (inpL[i])
1004  {
1005  del = getSolverState().currTimeStep * (-vcapref[i] - model_.s0vhi)/(-vcapref[i] - vOld);
1006  }
1007  else
1008  {
1009  del = getSolverState().currTimeStep * (vcapref[i] + model_.s1vlo)/(vcapref[i] + vOld);
1010  }
1011  }
1012  staVector[li_transitionTimeInp[i]] = time - del;
1013  iTime[i] = time;
1014  }
1015 
1016  staVector[li_currentStateInp[i]] = currentState;
1017  staVector[li_QinpState[i]] = qref[i];
1018 
1019  if (iTime[i] > lastT)
1020  lastT = iTime[i];
1021 
1022  // added for debug, for tracking input state changes
1023  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
1024  {
1025  if (changeState == true && inputStateChange_ == false)
1026  {
1027  inputStateChange_ = true;
1028  }
1029  }
1030  } // end for loop numInput i
1031 
1032  if (gate == INV)
1033  {
1034  outL[0] = !inpL[0];
1035  oTime[0] = lastT+model_.delay;
1036  }
1037  else if (gate == AND)
1038  {
1039  outL[0] = !(count(inpL.begin(),inpL.end(),false) > 0);
1040  oTime[0] = lastT+model_.delay;
1041  }
1042  else if (gate == NAND)
1043  {
1044  outL[0] = (count(inpL.begin(),inpL.end(),false) > 0);
1045  oTime[0] = lastT+model_.delay;
1046  }
1047  else if (gate == OR)
1048  {
1049  outL[0] = (count(inpL.begin(),inpL.end(),true) > 0);
1050  oTime[0] = lastT+model_.delay;
1051  }
1052  else if (gate == NOR)
1053  {
1054  outL[0] = !(count(inpL.begin(),inpL.end(),true) > 0);
1055  oTime[0] = lastT+model_.delay;
1056  }
1057  else if (gate == ADD)
1058  {
1059  outL[0] = inpL[0] ^ inpL[1] ^ inpL[2];
1060  // carry-out sum
1061  outL[1] = (inpL[0] & inpL[1]) | (inpL[1] & inpL[2]) | (inpL[0] & inpL[2]);
1062 
1063  oTime[0] = lastT+model_.delay;
1064  oTime[1] = lastT+model_.delay;
1065  }
1066  else if (gate == XOR)
1067  {
1068  outL[0] = inpL[0] ^ inpL[1];
1069  oTime[0] = lastT+model_.delay;
1070  }
1071  else if (gate == NXOR)
1072  {
1073  outL[0] = !(inpL[0] ^ inpL[1]);
1074  oTime[0] = lastT+model_.delay;
1075  }
1076  else if (gate == BUF)
1077  {
1078  outL[0] = inpL[0];
1079  oTime[0] = lastT+model_.delay;
1080  }
1081  else if (gate == DLTCH)
1082  { // DLTCH: in0: PREB, in1: CLRB, in2: enable, in3: data
1083  // DLTCH: out0: Q, out1: Q_bar
1084  if ((inpL[0] == 1) && (inpL[1] == 0))
1085  {
1086  outL[0] = 0;
1087  outL[1] = 1;
1088  oTime[0] = lastT+model_.delay;
1089  oTime[1] = lastT+model_.delay;
1090  }
1091  else if ((inpL[0] == 0) && (inpL[1] == 1))
1092  {
1093  outL[0] = 1;
1094  outL[1] = 0;
1095  oTime[0] = lastT+model_.delay;
1096  oTime[1] = lastT+model_.delay;
1097  }
1098  else if ((inpL[0] == 0) && (inpL[1] == 0))
1099  { // this state is unstable. The transition out of this state is handled by the
1100  // else if (outL[1] == outL[0]) block below
1101  outL[0] = 1;
1102  outL[1] = 1;
1103  oTime[0] = lastT+model_.delay;
1104  oTime[1] = lastT+model_.delay;
1105  }
1106  else if (inpL[2] == 1)
1107  { // enable line, PREB and CLRB are TRUE
1108  outL[0] = inpL[3];
1109  outL[1] = !inpL[3];
1110  oTime[0] = lastT+model_.delay;
1111  oTime[1] = lastT+model_.delay;
1112  }
1113  else if (getSolverState().dcopFlag)
1114  { // Handle dcop calculation when enable is low. This forces Q and Qbar to be
1115  // different at DCOP. This behavior differs from PSpice, where Q and Qbar
1116  // would be in an indeterminate state that is about halfway between V_LO and V_HI.
1117  outL[0] = inpL[3];
1118  outL[1] = !inpL[3];
1119  }
1120  else if (outL[1] == outL[0])
1121  { // handles unstable state after PREB/CLRB = 0 state
1122  outL[1] = !outL[0];
1123  oTime[1] = lastT+model_.delay;
1124  }
1125  else
1126  {
1127  // no op. Keep outputs latched in current state
1128  }
1129  }
1130  else if (gate == DFF)
1131  { // DFF: in0: PREB, in1: CLRB, in2: clock, in3: data
1132  // DFF: out0: Q, out1: Q_bar
1133  // CD4013B: set = !PREB, reset = !CLRB
1134  // CD4013B: in0: set, in1: reset, in2: clock, in3: data
1135  // CD4013B: out0: Q, out1: Q_bar
1136  if (clocking && inpL[2] ==1) //clock rising edge 0->1
1137  {
1138  if (inpL[0] == 1 && inpL[1] == 1) //PREB = CLRB = 1
1139  {
1140  outL[0] = inpL[3]; //Q = D
1141  outL[1] = !(inpL[3]); //Q_bar = !D
1142  }
1143  }
1144  else if (clocking && inpL[2] ==0) //clock falling edge 1->0
1145  {
1146  if (inpL[0] == 1 && inpL[1] == 1) //PREB = CLRB = 1
1147  {
1148  outL[0] = oldStaVector[li_currentStateOut[0]]; //no change
1149  outL[1] = oldStaVector[li_currentStateOut[1]]; //no change
1150  }
1151  }
1152  else // no clock change
1153  {
1154  if (inpL[0] == 1 && inpL[1] == 0) //PREB=1, CLRB = 0
1155  {
1156  outL[0] = 0;
1157  outL[1] = 1;
1158  }
1159  else if (inpL[0] == 0 && inpL[1] == 1) //PREB = 0, CLRB = 1
1160  {
1161  outL[0] = 1;
1162  outL[1] = 0;
1163  }
1164  else if (inpL[0] == 0 && inpL[1] == 0) //PREB = CLRB = 0
1165  {
1166  outL[0] = 1;
1167  outL[1] = 1;
1168  }
1169  }
1170  oTime[0] = lastT+model_.delay;
1171  oTime[1] = lastT+model_.delay;
1172  }
1173 
1174  bool curr;
1175  breakTime = 0;
1176  for (int i=0 ; i<numOutput ; ++i)
1177  {
1178  time = getSolverState().currTime;
1179  if (getSolverState().dcopFlag)
1180  {
1181  if (i == 0)
1182  {
1183  if (given("IC1"))
1184  outL[i] = ic1;
1185  }
1186  else if (i == 1)
1187  {
1188  if (given("IC2"))
1189  outL[i] = ic2;
1190  }
1191  else
1192  {
1193  std::string msg("Insufficient initial conditions supported in digital device");
1194  N_ERH_ErrorMgr::report(N_ERH_ErrorMgr::DEV_FATAL, msg);
1195  }
1196 
1197  oldStaVector[li_currentStateOut[i]] = outL[i]?1:0;
1198  oldStaVector[li_transitionTimeOut[i]] = time;
1199  }
1200 
1201  //current logic state of output nodes
1202  currentState = static_cast <int> (oldStaVector[li_currentStateOut[i]]);
1203  transitionTime = oldStaVector[li_transitionTimeOut[i]];
1204 
1205  if (currentState == 1)
1206  curr = true;
1207  else
1208  curr = false;
1209 
1210  if (curr != outL[i]) // This is executed when scopFlag is false
1211  {
1212  if (oTime[i] <= time)
1213  {
1214  currentState = 1-currentState;
1215  transitionTime = oTime[i];
1216  }
1217  else
1218  {
1219  if (breakTime == 0 || (breakTime > 0 && breakTime > oTime[i]))
1220  {
1221  breakTime = oTime[i];
1222  }
1223  }
1224  }
1225 
1226  staVector[li_currentStateOut[i]] = currentState;
1227  staVector[li_transitionTimeOut[i]] = transitionTime;
1228 
1229  // obtain voltage drop accross the capacitors:
1230  v_neg = solVector[li_Out[i]];
1231 
1232  elapsed = time - transitionTime;
1233 
1234  if (currentState == 0)
1235  elapsed /= model_.s0tsw;
1236  else if (currentState == 1)
1237  elapsed /= model_.s1tsw;
1238  else
1239  {
1240  std::string msg("Instance::updateSecondaryState: unrecognized state");
1241  N_ERH_ErrorMgr::report(N_ERH_ErrorMgr::DEV_FATAL, msg);
1242  }
1243 
1244  frac = exp(-elapsed); //Genie 112812. This line can be omitted.
1245  if (transitionTime == 0)
1246  frac = 0;
1247  else
1248  {
1249  if (elapsed > 1)
1250  frac = 0;
1251  else
1252  {
1253  // This is a simple linear transition. Since there is a
1254  // breakpoint at the start of the transition it is OK to
1255  // have a discontinuity there.
1256  frac = 1-elapsed;
1257  }
1258  }
1259 
1260  if (currentState == 0)
1261  {
1262  glo[i] = 1/(frac*model_.s1rlo + (1-frac)*model_.s0rlo);
1263  ghi[i] = 1/(frac*model_.s1rhi + (1-frac)*model_.s0rhi);
1264  }
1265  else
1266  {
1267  glo[i] = 1/(frac*model_.s0rlo + (1-frac)*model_.s1rlo);
1268  ghi[i] = 1/(frac*model_.s0rhi + (1-frac)*model_.s1rhi);
1269  }
1270 
1271  rilo[i] = glo[i]*(v_poslo-v_neg);
1272  rihi[i] = ghi[i]*(v_poshi-v_neg);
1273 
1274  vcaplo[i] = v_poslo-v_neg;
1275  vcaphi[i] = v_poshi-v_neg;
1276 
1277  // Obtain the "current" value for the charge stored in the capacitors.
1278  qlo[i] = model_.clo*vcaplo[i];
1279  qhi[i] = model_.chi*vcaphi[i];
1280 
1281  staVector[li_QloState[i]] = qlo[i];
1282  staVector[li_QhiState[i]] = qhi[i];
1283 
1284  }// end for loop numOutput i
1285 
1286  return bsuccess;
1287 }
1288 
1289 //-----------------------------------------------------------------------------
1290 // Function : Instance::updateSecondaryState
1291 // Purpose :
1292 // Special Notes :
1293 // Scope : public
1294 // Creator : Dave Shirley, PSSI
1295 // Creation Date : 01/05/06
1296 //-----------------------------------------------------------------------------
1298 {
1299  bool bsuccess = true;
1300 
1301  Linear::Vector * staVectorPtr = extData.nextStaVectorPtr;
1302 
1303  // Now that the state vector for time=0 is up-to-date, get the
1304  // derivative with respect to time of the charge, to obtain the
1305  // best estimate for the current in the capacitors.
1306 
1307  for (int i=0 ; i<numOutput ; ++i)
1308  {
1311 
1312  currentOut[i] = ilo[i] + ihi[i] + rilo[i] + rihi[i];
1313 
1314  (*staVectorPtr)[li_IloState[i]] = ilo[i];
1315  (*staVectorPtr)[li_IhiState[i]] = ihi[i];
1316  }
1317 
1318  for (int i=0 ; i<numInput ; ++i)
1319  {
1321 
1322  currentIn[i] = iref[i] + riref[i];
1323 
1324  (*staVectorPtr)[li_IinpState[i]] = iref[i];
1325  }
1326 
1327 
1328  return bsuccess;
1329 }
1330 
1331 //-----------------------------------------------------------------------------
1332 // Function : Instance::getInstanceBreakPoints
1333 // Purpose : Add break point for anticipated digital output transition
1334 // Special Notes :
1335 // Scope : public
1336 // Creator : Dave Shirley, PSSI
1337 // Creation Date : 02/07/06
1338 //-----------------------------------------------------------------------------
1340  std::vector<Util::BreakPoint> & breakPointTimes)
1341 {
1342  if (breakTime > getSolverState().currTime)
1343  {
1344  breakPointTimes.push_back(breakTime);
1345  }
1346  return true;
1347 }
1348 
1349 //-----------------------------------------------------------------------------
1350 // Function : Instance::acceptStep
1351 // Purpose : This function is to be called ONLY at the point
1352 // when the time integrator has determined we've got a
1353 // converged, acceptable solution and is accepting it,
1354 // but before it's updated its times and rotated vectors.
1355 // It is used for debugging purpose
1356 //
1357 // Special Notes : In SPICE this same stuff was done in the "TRAaccept" function.
1358 //
1359 // Scope : public
1360 // Creator : Pete Sholander, SNL
1361 // Creation Date : 06/30/14
1362 //-----------------------------------------------------------------------------
1364 {
1365  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
1366  {
1367  // this debugging code prints out cases where the input changes occur within the
1368  // the model delay, which may cause incorrect output states in some cases
1369  if (inputStateChange_)
1370  {
1372  if (delta <= model_.delay)
1373  {
1374  Xyce::dout() << "Device " << getName() << " changed state & accepted time step at "
1375  << getSolverState().currTime << ". Previous state" << std::endl
1376  << "change at Device " << getName() << " at time "
1377  << prevInputStateChangeTime_ << " was shorted-spaced. Delta= "
1378  << delta << std::endl << std::endl;
1379  }
1381  }
1382  }
1383 }
1384 
1385 //-----------------------------------------------------------------------------
1386 // Function : Instance::loadDAEQVector
1387 //
1388 // Purpose : Loads the Q-vector contributions for a single
1389 // digital instance.
1390 //
1391 // Special Notes : The "Q" vector is part of a standard DAE formalism in
1392 // which the system of equations is represented as:
1393 //
1394 // f(x) = dQ(x)/dt + F(x) - B(t) = 0
1395 //
1396 // Scope : public
1397 // Creator : Dave Shirley, PSSI
1398 // Creation Date : 01/05/06
1399 //-----------------------------------------------------------------------------
1401 {
1402  bool bsuccess = true;
1403 
1404  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
1405  {
1406  Xyce::dout() << subsection_divider << std::endl;
1407  Xyce::dout() << " Instance::loadDAEQVector" << std::endl;
1408  Xyce::dout() << " name = " << getName() <<std::endl;
1409  }
1410 
1411  for (int i=0 ; i<numOutput ; ++i)
1412  {
1413  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
1414  {
1415  Xyce::dout() << " qlo[" << i << "] = " << qlo[i] << std::endl;
1416  Xyce::dout() << " qhi[" << i << "] = " << qhi[i] << std::endl;
1417  }
1418 
1419  if (li_Lo >= 0)
1420  {
1421 
1422  (*extData.daeQVectorPtr)[li_Lo] += qlo[i];
1423  }
1424  if (li_Hi >= 0)
1425  {
1426 
1427  (*extData.daeQVectorPtr)[li_Hi] += qhi[i];
1428  }
1429 
1430 
1431  (*extData.daeQVectorPtr)[li_Out[i]] -= qlo[i];
1432 
1433  (*extData.daeQVectorPtr)[li_Out[i]] -= qhi[i];
1434  }
1435 
1436  for (int i=0 ; i<numInput ; ++i)
1437  {
1438  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
1439  {
1440  Xyce::dout() << " qref[" << i << "] = " << qref[i] << std::endl;
1441  }
1442 
1443  if (li_Ref >= 0)
1444  {
1445 
1446  (*extData.daeQVectorPtr)[li_Ref] += qref[i];
1447  }
1448 
1449 
1450  (*extData.daeQVectorPtr)[li_Inp[i]] -= qref[i];
1451  }
1452 
1453  return bsuccess;
1454 }
1455 
1456 //-----------------------------------------------------------------------------
1457 // Function : Instance::loadDAEFVector
1458 //
1459 // Purpose : Loads the F-vector contributions for a single
1460 // digital instance.
1461 //
1462 // Special Notes :
1463 //
1464 // Scope : public
1465 // Creator : Dave Shirley, PSSI
1466 // Creation Date : 01/05/06
1467 //-----------------------------------------------------------------------------
1469 {
1470  bool bsuccess = true;
1471  double coef = 0.0;
1472  double Vpos = 0.0;
1473  double Vneg = 0.0;
1474  double v_tmp = 0.0;
1475 
1476  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
1477  {
1478  Xyce::dout() << subsection_divider << std::endl;
1479  Xyce::dout() << " Instance::loadDAEFVector" << std::endl;
1480  Xyce::dout() << " name = " << getName() <<std::endl;
1481  }
1482 
1483  for (int i=0 ; i<numOutput ; ++i)
1484  {
1485  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
1486  {
1487  Xyce::dout() << " rilo[" << i << "] = " << rilo[i] << std::endl;
1488  Xyce::dout() << " rihi[" << i << "] = " << rihi[i] << std::endl;
1489  }
1490 
1491  if (li_Lo >= 0)
1492  {
1493 
1494  (*extData.daeFVectorPtr)[li_Lo] += rilo[i];
1495  }
1496  if (li_Hi >= 0)
1497  {
1498 
1499  (*extData.daeFVectorPtr)[li_Hi] += rihi[i];
1500  }
1501 
1502 
1503  (*extData.daeFVectorPtr)[li_Out[i]] -= rilo[i];
1504 
1505  (*extData.daeFVectorPtr)[li_Out[i]] -= rihi[i];
1506  }
1507 
1508  for (int i=0 ; i<numInput ; ++i)
1509  {
1510  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
1511  {
1512  Xyce::dout() << " riref[" << i << "] = " << riref[i] << std::endl;
1513  }
1514 
1515  if (li_Ref >= 0)
1516  {
1517 
1518  (*extData.daeFVectorPtr)[li_Ref] += riref[i];
1519  }
1520 
1521 
1522  (*extData.daeFVectorPtr)[li_Inp[i]] -= riref[i];
1523  }
1524 
1525  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
1526  {
1527  Xyce::dout() << subsection_divider << std::endl;
1528  }
1529 
1530  return bsuccess;
1531 }
1532 
1533 //-----------------------------------------------------------------------------
1534 // Function : Instance::loadDAEdQdx
1535 //
1536 // Purpose : Loads the dQdx-matrix contributions for a single
1537 // digital instance.
1538 //
1539 // Special Notes : The "Q" vector is part of a standard DAE formalism in
1540 // which the system of equations is represented as:
1541 //
1542 // f(x) = dQ(x)/dt + F(x) - B(t) = 0
1543 //
1544 // Scope : public
1545 // Creator : Dave Shirley, PSSI
1546 // Creation Date : 01/05/06
1547 //-----------------------------------------------------------------------------
1549 {
1550  bool bsuccess = true;
1551 
1552  Linear::Matrix * dQdxMatPtr = extData.dQdxMatrixPtr;
1553 
1554  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
1555  {
1556  Xyce::dout() << subsection_divider <<std::endl;
1557  Xyce::dout() << " Instance::loadDAEdQdx" << std::endl;
1558  Xyce::dout() << " name = " << getName() << std::endl;
1559  }
1560 
1561  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
1562  {
1563  Xyce::dout() << "\nLoading DIGITAL dQdx matrix\n";
1564  Xyce::dout() << "Capacitance lo: " << model_.clo << std::endl;
1565  Xyce::dout() << "Capacitance hi: " << model_.chi << std::endl;
1566  Xyce::dout() << "Capacitance load: " << model_.cload << std::endl;
1567  Xyce::dout() << "DONE DIGITAL dQdx matrix LOAD\n";
1568  }
1569 
1570  for (int i=0 ; i<numInput ; ++i)
1571  {
1572  if (row_Ref >= 0)
1573  {
1574 
1575  (*dQdxMatPtr)[li_Ref][li_jac_Ref[i][1]] += model_.cload;
1576 
1577  (*dQdxMatPtr)[li_Ref][li_jac_Ref[i][2]] -= model_.cload;
1578 
1579  (*dQdxMatPtr)[li_Inp[i]][li_jac_Ref[i][4]] -= model_.cload;
1580 
1581  (*dQdxMatPtr)[li_Inp[i]][li_jac_Ref[i][5]] += model_.cload;
1582  }
1583  else
1584  {
1585 
1586  (*dQdxMatPtr)[li_Inp[i]][li_jac_Ref[i][1]] += model_.cload;
1587  }
1588  }
1589 
1590  for (int i=0 ; i<numOutput ; ++i)
1591  {
1592  if (row_Lo >= 0)
1593  {
1594 
1595  (*dQdxMatPtr)[li_Lo][li_jac_Lo[i][1]] += model_.clo;
1596 
1597  (*dQdxMatPtr)[li_Lo][li_jac_Lo[i][2]] -= model_.clo;
1598 
1599  (*dQdxMatPtr)[li_Out[i]][li_jac_Lo[i][4]] -= model_.clo;
1600 
1601  (*dQdxMatPtr)[li_Out[i]][li_jac_Lo[i][5]] += model_.clo;
1602  }
1603  else
1604  {
1605 
1606  (*dQdxMatPtr)[li_Out[i]][li_jac_Lo[i][1]] += model_.clo;
1607  }
1608  if (row_Hi >= 0)
1609  {
1610 
1611  (*dQdxMatPtr)[li_Hi][li_jac_Hi[i][1]] += model_.chi;
1612 
1613  (*dQdxMatPtr)[li_Hi][li_jac_Hi[i][2]] -= model_.chi;
1614 
1615  (*dQdxMatPtr)[li_Out[i]][li_jac_Hi[i][4]] -= model_.chi;
1616 
1617  (*dQdxMatPtr)[li_Out[i]][li_jac_Hi[i][5]] += model_.chi;
1618  }
1619  else
1620  {
1621 
1622  (*dQdxMatPtr)[li_Out[i]][li_jac_Hi[i][1]] += model_.chi;
1623  }
1624  }
1625 
1626  return bsuccess;
1627 }
1628 
1629 //-----------------------------------------------------------------------------
1630 // Function : Instance::loadDAEdFdx ()
1631 //
1632 // Purpose : Loads the F-vector contributions for a single
1633 // digital instance.
1634 //
1635 // Special Notes : See the special notes for loadDAEFVector.
1636 // For digital devices this is the contribution of the resistors
1637 //
1638 // Scope : public
1639 // Creator : Dave Shirley, PSSI
1640 // Creation Date : 01/05/06
1641 //-----------------------------------------------------------------------------
1643 {
1644  bool bsuccess = true;
1645  Linear::Matrix * dFdxMatPtr = extData.dFdxMatrixPtr;
1646 
1647  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
1648  {
1649  Xyce::dout() << subsection_divider <<std::endl;
1650  Xyce::dout() << " Instance::loadDAEdFdx" << std::endl;
1651  }
1652 
1653  for (int i=0 ; i<numInput ; ++i)
1654  {
1655  if (row_Ref >= 0)
1656  {
1657 
1658  (*dFdxMatPtr)[li_Ref][li_jac_Ref[i][1]] += model_.gload;
1659 
1660  (*dFdxMatPtr)[li_Ref][li_jac_Ref[i][2]] -= model_.gload;
1661 
1662  (*dFdxMatPtr)[li_Inp[i]][li_jac_Ref[i][4]] -= model_.gload;
1663 
1664  (*dFdxMatPtr)[li_Inp[i]][li_jac_Ref[i][5]] += model_.gload;
1665  }
1666  else
1667  {
1668 
1669  (*dFdxMatPtr)[li_Inp[i]][li_jac_Ref[i][1]] += model_.gload;
1670  }
1671  }
1672 
1673  for (int i=0 ; i<numOutput ; ++i)
1674  {
1675  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
1676  {
1677  Xyce::dout() << " glo[" << i << "] = " << glo[i] << std::endl;
1678  Xyce::dout() << " ghi[" << i << "] = " << ghi[i] << std::endl;
1679  }
1680 
1681  if (row_Lo >= 0)
1682  {
1683 
1684  (*dFdxMatPtr)[li_Lo][li_jac_Lo[i][1]] += glo[i];
1685 
1686  (*dFdxMatPtr)[li_Lo][li_jac_Lo[i][2]] -= glo[i];
1687 
1688  (*dFdxMatPtr)[li_Out[i]][li_jac_Lo[i][4]] -= glo[i];
1689 
1690  (*dFdxMatPtr)[li_Out[i]][li_jac_Lo[i][5]] += glo[i];
1691  }
1692  else
1693  {
1694 
1695  (*dFdxMatPtr)[li_Out[i]][li_jac_Lo[i][1]] += glo[i];
1696  }
1697  if (row_Hi >= 0)
1698  {
1699 
1700  (*dFdxMatPtr)[li_Hi][li_jac_Hi[i][1]] += ghi[i];
1701 
1702  (*dFdxMatPtr)[li_Hi][li_jac_Hi[i][2]] -= ghi[i];
1703 
1704  (*dFdxMatPtr)[li_Out[i]][li_jac_Hi[i][4]] -= ghi[i];
1705 
1706  (*dFdxMatPtr)[li_Out[i]][li_jac_Hi[i][5]] += ghi[i];
1707  }
1708  else
1709  {
1710 
1711  (*dFdxMatPtr)[li_Out[i]][li_jac_Hi[i][1]] += ghi[i];
1712  }
1713  }
1714 
1715  return bsuccess;
1716 }
1717 
1718 // Class Model
1719 //-----------------------------------------------------------------------------
1720 // Function : Model::processParams
1721 // Purpose :
1722 // Special Notes :
1723 // Scope : public
1724 // Creator : Dave Shirley, PSSI
1725 // Creation Date : 01/05/06
1726 //-----------------------------------------------------------------------------
1728 {
1729 
1730  // If there are any time dependent parameters, set their values for
1731  // the current time.
1732 
1733  return true;
1734 }
1735 
1736 //----------------------------------------------------------------------------
1737 // Function : Model::processInstanceParams
1738 // Purpose :
1739 // Special Notes :
1740 // Scope : public
1741 // Creator : Dave Shirely, PSSI
1742 // Creation Date : 03/23/06
1743 //----------------------------------------------------------------------------
1745 {
1746 
1747  std::vector<Instance*>::iterator iter;
1748  std::vector<Instance*>::iterator first = instanceContainer.begin();
1749  std::vector<Instance*>::iterator last = instanceContainer.end();
1750 
1751  for (iter=first; iter!=last; ++iter)
1752  {
1753  (*iter)->processParams();
1754  }
1755 
1756  return true;
1757 }
1758 
1759 //-----------------------------------------------------------------------------
1760 // Function : Model::Model
1761 // Purpose : block constructor
1762 // Special Notes :
1763 // Scope : public
1764 // Creator : Dave Shirley, PSSI
1765 // Creation Date : 01/05/06
1766 //-----------------------------------------------------------------------------
1767 
1769  const Configuration & configuration,
1770  const ModelBlock & MB,
1771  const FactoryBlock & factory_block)
1772  : DeviceModel(MB, configuration.getModelParameters(), factory_block)
1773 
1774 {
1775 
1776  // Set params to constant default values:
1777  setDefaultParams ();
1778 
1779  // Set params according to .model line and constant defaults from metadata:
1780  setModParams (MB.params);
1781 
1782  // Set any non-constant parameter defaults:
1783 
1784  // Calculate any parameters specified as expressions:
1786 
1787  // calculate dependent (ie computed) params and check for errors:
1788  if (rload == 0)
1789  {
1790  UserError0(*this) << "Zero load resistance in inputs";
1791  }
1792  gload = 1/rload;
1793 
1794  processParams ();
1795 }
1796 
1797 //-----------------------------------------------------------------------------
1798 // Function : Model::Model
1799 // Purpose : destructor
1800 // Special Notes :
1801 // Scope : public
1802 // Creator : Dave Shirley, PSSI
1803 // Creation Date : 01/05/06
1804 //-----------------------------------------------------------------------------
1805 
1807 {
1808  std::vector<Instance*>::iterator iter;
1809  std::vector<Instance*>::iterator first = instanceContainer.begin();
1810  std::vector<Instance*>::iterator last = instanceContainer.end();
1811 
1812  for (iter=first; iter!=last; ++iter)
1813  {
1814  delete (*iter);
1815  }
1816 
1817 }
1818 
1819 //-----------------------------------------------------------------------------
1820 // Function : Model::printOutInstances
1821 // Purpose : debugging tool.
1822 // Special Notes :
1823 // Scope : public
1824 // Creator : Dave Shirley, PSSI
1825 // Creation Date : 01/05/06
1826 //-----------------------------------------------------------------------------
1827 
1828 std::ostream &Model::printOutInstances(std::ostream &os) const
1829 {
1830  std::vector<Instance*>::const_iterator iter;
1831  std::vector<Instance*>::const_iterator first = instanceContainer.begin();
1832  std::vector<Instance*>::const_iterator last = instanceContainer.end();
1833 
1834  int i,isize;
1835 
1836  isize = instanceContainer.size();
1837  os << std::endl;
1838  os << "Number of digital instances: " << isize << std::endl;
1839  os << " name\t\tmodelName\tParameters" << std::endl;
1840 
1841  for (i = 0, iter = first; iter != last; ++iter, ++i)
1842  {
1843  os << " " << i << ": " << (*iter)->getName() << "\t";
1844  os << getName();
1845  os << std::endl;
1846  }
1847 
1848  os << std::endl;
1849 
1850  return os;
1851 }
1852 
1853 //-----------------------------------------------------------------------------
1854 // Function : Model::forEachInstance
1855 // Purpose :
1856 // Special Notes :
1857 // Scope : public
1858 // Creator : David Baur
1859 // Creation Date : 2/4/2014
1860 //-----------------------------------------------------------------------------
1861 /// Apply a device instance "op" to all instances associated with this
1862 /// model
1863 ///
1864 /// @param[in] op Operator to apply to all instances.
1865 ///
1866 ///
1867 void Model::forEachInstance(DeviceInstanceOp &op) const /* override */
1868 {
1869  for (std::vector<Instance *>::const_iterator it = instanceContainer.begin(); it != instanceContainer.end(); ++it)
1870  op(*it);
1871 }
1872 
1873 
1874 Device *Traits::factory(const Configuration &configuration, const FactoryBlock &factory_block)
1875 {
1876 
1877  return new DeviceMaster<Traits>(configuration, factory_block, factory_block.solverState_, factory_block.deviceOptions_);
1878 }
1879 
1881 {
1882  // NOT device is deprecated now
1884  .registerDevice("inv", 1)
1885  .registerDevice("not",1)
1886  .registerDevice("and", 1)
1887  .registerDevice("nand", 1)
1888  .registerDevice("or", 1)
1889  .registerDevice("nor", 1)
1890  .registerDevice("add", 1)
1891  .registerDevice("xor", 1)
1892  .registerDevice("nxor", 1)
1893  .registerDevice("dff", 1)
1894  .registerDevice("buf", 1)
1895  .registerDevice("dltch", 1)
1896  .registerModelType("dig", 1);
1897 }
1898 
1899 } // namespace Digital
1900 } // namespace Device
1901 } // namespace Xyce
const InstanceName & getName() const
std::vector< int > li_QinpState
std::vector< double > vcaplo
std::vector< double > iref
std::vector< double > rihi
std::vector< double > currentInp
const SolverState & solverState_
Descriptor & addPar(const char *parName, T default_value, T U::*varPtr)
Adds the parameter description to the parameter map.
Definition: N_DEV_Pars.h:1429
std::vector< int > li_IhiState
Linear::Vector * currSolVectorPtr
Linear::Vector * nextSolVectorPtr
std::vector< Instance * > instanceContainer
std::vector< int > li_QloState
bool given(const std::string &parameter_name) const
void registerJacLIDs(const std::vector< std::vector< int > > &jacLIDVec)
Linear::Vector * daeQVectorPtr
Pure virtual class to augment a linear system.
void makeVector(const std::string &cname, int len)
Allows the parameter to be specified as a vector.
Definition: N_DEV_Pars.h:1597
std::vector< std::vector< int > > jacStamp
virtual void registerJacLIDs(const JacobianStamp &jacLIDVec)
std::vector< double > vcaphi
std::vector< double > qlo
const std::vector< std::vector< int > > & jacobianStamp() const
std::vector< double > qInp
std::vector< double > ihi
std::vector< int > li_IloState
std::vector< Param > params
Parameters from the line.
std::vector< int > li_IinpState
void setParams(const std::vector< Param > &params)
std::vector< double > qref
const std::string & getName() const
bool getInstanceBreakPoints(std::vector< Util::BreakPoint > &)
virtual std::ostream & printOutInstances(std::ostream &os) const
static void loadModelParameters(ParametricData< Model > &model_parameters)
Definition: N_DEV_Digital.C:86
The FactoryBlock contains parameters needed by the device, instance and model creation functions...
std::vector< double > iInp
std::vector< double > oTime
std::vector< double > vcapInp
std::vector< int > li_transitionTimeOut
const DeviceOptions & deviceOptions_
std::vector< double > currentOut
std::vector< double > ilo
Linear::Vector * nextStaVectorPtr
std::vector< double > riref
Instance(const Configuration &configuration, const InstanceBlock &instance_block, Model &model, const FactoryBlock &factory_block)
std::vector< double > qhi
static Config< T > & addConfiguration()
Adds the device to the Xyce device configuration.
std::vector< double > rilo
Linear::Matrix * dFdxMatrixPtr
The Device class is an interface for device implementations.
Definition: N_DEV_Device.h:101
std::vector< double > glo
static Device * factory(const Configuration &configuration, const FactoryBlock &factory_block)
char getDeviceLetter() const
Return the first letter of the device specification after the subcircuit.
Class Configuration contains device configuration data.
std::vector< double > iTime
std::vector< std::vector< int > > li_jac_Ref
virtual void forEachInstance(DeviceInstanceOp &op) const
Apply a device instance "op" to all instances associated with this model.
std::vector< double > ghi
bool processParams()
processParams
const SolverState & getSolverState() const
static void loadInstanceParameters(ParametricData< Instance > &instance_parameters)
Definition: N_DEV_Digital.C:73
void registerStateLIDs(const std::vector< int > &staLIDVecRef)
Linear::Vector * currStaVectorPtr
std::vector< int > li_QhiState
Linear::Vector * daeFVectorPtr
std::vector< double > vcapref
std::vector< std::vector< int > > li_jac_Hi
std::vector< int > li_currentStateInp
ModelBlock represents a .MODEL line from the netlist.
Manages parameter binding for class C.
Definition: N_DEV_Pars.h:214
void loadNodeSymbols(Util::SymbolTable &symbol_table) const
Populates and returns the store name map.
InstanceBlock represent a device instance line from the netlist.
std::vector< Param > params
int getNumInputs() const
For the U device, return the number of inputs which have been encoded into the device name...
const std::string & getDeviceType() const
Decodes the device type.
Linear::Matrix * dQdxMatrixPtr
std::vector< int > li_currentStateOut
std::vector< double > currentIn
void registerLIDs(const std::vector< int > &intLIDVecRef, const std::vector< int > &extLIDVecRef)
std::vector< int > li_transitionTimeInp
Linear::Vector * nextStaDerivVectorPtr
void setModParams(const std::vector< Param > &params)
bool processInstanceParams()
processInstanceParams
std::vector< std::vector< int > > li_jac_Lo