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