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