1 /*
2  * CCvcDb.cc
3  *
4  * Copyright 2014-2020 D. Mitch Bailey  cvc at shuharisystem dot com
5  *
6  * This file is part of cvc.
7  *
8  * cvc is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * cvc is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with cvc.  If not, see <http://www.gnu.org/licenses/>.
20  *
21  * You can download cvc from https://github.com/d-m-bailey/cvc.git
22  */
23 
24 #include "CCvcDb.hh"
25 
26 #include "CCircuit.hh"
27 #include "CModel.hh"
28 #include "CDevice.hh"
29 #include "CPower.hh"
30 #include "CInstance.hh"
31 #include "CEventQueue.hh"
32 #include "CVirtualNet.hh"
33 #include "CConnection.hh"
34 
35 extern set<modelType_t> FUSE_MODELS;
36 char RESISTOR_TEXT[] = " resistor";  // leading space to differentiate from normal signals
37 
38 /**
39  * \brief Report shorts during logic simulation propagation that involve limited voltages.
40  *
41  * A limited voltage is an unknown simulation voltage with a known min/max value that indicates a current leak (short).
42  * For example, a 1.2V power signal propagated to a net that has a max voltage of 1.0V would be flagged as a leak.
43  * Note: if the propagated voltage and limited voltage differ by exactly Vth, the short is ignored. This is the expected result of mos diodes.
44  */
ReportSimShort(deviceId_t theDeviceId,voltage_t theMainVoltage,voltage_t theShortVoltage,string theCalculation)45 void CCvcDb::ReportSimShort(deviceId_t theDeviceId, voltage_t theMainVoltage, voltage_t theShortVoltage, string theCalculation) {
46 	static CFullConnection myConnections;
47 	MapDeviceNets(theDeviceId, myConnections);
48 	voltage_t myMaxVoltage = max(theMainVoltage, theShortVoltage);
49 	voltage_t myMinVoltage = min(theMainVoltage, theShortVoltage);
50 	if ( abs(theMainVoltage - theShortVoltage) != abs(myConnections.device_p->model_p->Vth) &&
51 			abs(theMainVoltage - theShortVoltage) > cvcParameters.cvcShortErrorThreshold ) {
52 		if ( IncrementDeviceError(theDeviceId, LEAK) < cvcParameters.cvcCircuitErrorLimit || cvcParameters.cvcCircuitErrorLimit == 0 ) {
53 			errorFile << "! Short Detected: " << PrintVoltage(myMaxVoltage) << " to " << PrintVoltage(myMinVoltage) << theCalculation << endl;
54 			PrintDeviceWithAllConnections(deviceParent_v[theDeviceId], myConnections, errorFile);
55 			errorFile << endl;
56 		}
57 	}
58 }
59 
60 /**
61  * \brief Report shorts during logic simulation propagation.
62  *
63  * Variables controlling short error detection:
64  * cvcShortErrorThreshold: only report errors between voltages exceeding threshold.
65  * cvcLeakLimit: minimum leak current for short detection.
66  * myVthFlag: true if gate-source voltage difference is exactly Vth.
67  * myLeakCurrent: rough estimate of leak current.
68  * myUnrelatedFlag: true if leaks between shorted nets are prohibited.
69  * Note: leaks between external power are always errors if threshold = 0.
70  */
ReportShort(deviceId_t theDeviceId)71 void CCvcDb::ReportShort(deviceId_t theDeviceId) {
72 	static CFullConnection myConnections;
73 	MapDeviceNets(theDeviceId, myConnections);
74 	voltage_t myMaxVoltage = max(myConnections.simSourceVoltage, myConnections.simDrainVoltage);
75 	voltage_t myMinVoltage = min(myConnections.simSourceVoltage, myConnections.simDrainVoltage);
76 	float myLeakCurrent;
77 	bool myVthFlag;
78 	if ( myConnections.simSourcePower_p->type[HIZ_BIT]
79 		&& myConnections.simSourcePower_p->IsRelatedPower(myConnections.simDrainPower_p, netVoltagePtr_v, simNet_v, simNet_v, false) ) return;
80 		// no shorts from Hi-Z to expected leak path
81 	if ( myConnections.simDrainPower_p->type[HIZ_BIT]
82 		&& myConnections.simDrainPower_p->IsRelatedPower(myConnections.simSourcePower_p, netVoltagePtr_v, simNet_v, simNet_v, false) ) return;
83 		// no shorts from Hi-Z to expected leak path
84 	if ( myMaxVoltage == UNKNOWN_VOLTAGE || myMinVoltage == UNKNOWN_VOLTAGE ) {
85 		myLeakCurrent = 0;
86 		myVthFlag = false;
87 	} else {
88 		myVthFlag = (IsNmos_(deviceType_v[theDeviceId]) && myConnections.simGateVoltage - myMinVoltage == myConnections.device_p->model_p->Vth) ||
89 			(IsPmos_(deviceType_v[theDeviceId]) && myConnections.simGateVoltage - myMaxVoltage == myConnections.device_p->model_p->Vth);
90 		myLeakCurrent = myConnections.EstimatedCurrent(myVthFlag);
91 	}
92 	bool myUnrelatedFlag = cvcParameters.cvcShortErrorThreshold == 0
93 			&& ! myConnections.simSourcePower_p->IsRelatedPower(myConnections.simDrainPower_p, netVoltagePtr_v, simNet_v, simNet_v, true);  // no unrelated checks for real sim checks
94 	if ( ( myMaxVoltage - myMinVoltage > cvcParameters.cvcShortErrorThreshold && ExceedsLeakLimit_(myLeakCurrent) )  // flag leaks with large current
95 			|| myUnrelatedFlag  // flag leaks between unrelated power
96 			|| ( myMaxVoltage != myMinVoltage && ! myVthFlag  // ignore leaks between same voltages or at Vth
97 				&& ( ( IsExternalPower_(myConnections.simSourcePower_p)
98 						&& IsExternalPower_(myConnections.simDrainPower_p)
99 						&& cvcParameters.cvcShortErrorThreshold == 0 )  // flag all leaks between power nets if threshold = 0
100 					|| myConnections.simSourcePower_p->flagAllShorts || myConnections.simDrainPower_p->flagAllShorts ) ) ) {  // flag nets for calculated logic levels
101 		if ( IncrementDeviceError(theDeviceId, LEAK) < cvcParameters.cvcCircuitErrorLimit || cvcParameters.cvcCircuitErrorLimit == 0 ) {
102 			errorFile << "! Short Detected: " << PrintVoltage(myMaxVoltage) << " to " << PrintVoltage(myMinVoltage);
103 			if ( myVthFlag ) errorFile << " at Vth ";
104 			errorFile << " Estimated current: " << AddSiSuffix(myLeakCurrent) << "A" << endl;
105 			if ( myUnrelatedFlag ) {
106 				errorFile << "Unrelated power error" << endl;
107 			}
108 			PrintDeviceWithAllConnections(deviceParent_v[theDeviceId], myConnections, errorFile);
109 			errorFile << endl;
110 		}
111 	}
112 }
113 
114 /**
115  * \brief Check virtual net connection to see if reroute is necessary.
116  *
117  * When the source and drain final virtual net connections both point to the same net,
118  * this routine determines whether or not to change the drain connection
119  * by comparing the source connection to the next drain connection.
120  * NOTE: this calculation is NOT propagated to subsequent devices in the voltage path.
121  * Require:
122  *   source net is defined terminal net
123  *   drain net is not terminal net
124  *   drain final net is defined net
125  */
CheckConnectionReroute(CEventQueue & theEventQueue,CConnection & theConnections,shortDirection_t theDirection)126 bool CCvcDb::CheckConnectionReroute(CEventQueue & theEventQueue, CConnection& theConnections, shortDirection_t theDirection) {
127 	// return true if connection should be rerouted
128 	netId_t myNextDrainNet;
129 	CPower * mySourcePower_p;
130 	resistance_t myDrainResistance;
131 	if ( theDirection == DRAIN_TO_MASTER_SOURCE ) {
132 		myNextDrainNet = theEventQueue.virtualNet_v[theConnections.drainId].nextNetId;
133 		mySourcePower_p = netVoltagePtr_v[theConnections.sourceId].full;
134 		myDrainResistance = theConnections.masterDrainNet.finalResistance;
135 	} else {  // swap source and drain
136 		assert(theDirection == SOURCE_TO_MASTER_DRAIN);
137 		myNextDrainNet = theEventQueue.virtualNet_v[theConnections.sourceId].nextNetId;
138 		mySourcePower_p = netVoltagePtr_v[theConnections.drainId].full;
139 		myDrainResistance = theConnections.masterSourceNet.finalResistance;
140 	}
141 	CPower * myNextDrainPower_p = netVoltagePtr_v[myNextDrainNet].full;
142 	if ( ! theEventQueue.virtualNet_v.IsTerminal(myNextDrainNet) ) return true;  // reroute if source is terminal, next drain not terminal
143 	// both terminal
144 	if ( myNextDrainPower_p->type[POWER_BIT] ) {
145 		if ( ! mySourcePower_p->type[POWER_BIT] ) return false;  // do not reroute if next drain is power, source not power
146 		// both power. reroute if less resistance.
147 		return (theConnections.resistance < myDrainResistance);
148 	}
149 	// next drain not power
150 	if ( mySourcePower_p->type[POWER_BIT] ) return true;  // reroute if source is power, next drain not power
151 	// both not power. reroute if drain is calculated, source not calculated.
152 	return (myNextDrainPower_p->type[theEventQueue.virtualNet_v.calculatedBit] && ! mySourcePower_p->type[theEventQueue.virtualNet_v.calculatedBit]);
153 }
154 
IsPriorityDevice(CEventQueue & theEventQueue,modelType_t theModel)155 bool CCvcDb::IsPriorityDevice(CEventQueue& theEventQueue, modelType_t theModel) {
156 	if ( theEventQueue.queueType == MIN_QUEUE && ! IsNmos_(theModel) ) return false;
157 	if ( theEventQueue.queueType == MAX_QUEUE && ! IsPmos_(theModel) ) return false;
158 	return true;
159 }
160 
AlreadyShorted(CEventQueue & theEventQueue,deviceId_t theDeviceId,CConnection & theConnections)161 void CCvcDb::AlreadyShorted(CEventQueue& theEventQueue, deviceId_t theDeviceId, CConnection& theConnections) {
162 	// add logic for equivalent voltage shorts.
163 	static CVirtualNet myLastVirtualNet;
164 	if ( theConnections.masterSourceNet.finalNetId == theConnections.masterDrainNet.finalNetId ) {
165 		// no shifting on second pass causes looping. Only reroute direct connections.
166 		if ( IsPriorityDevice(theEventQueue, deviceType_v[theConnections.deviceId]) ) {
167 			if ( leakVoltageSet ) {  // second pass. Only reroute direct connections
168 				if ( ! theEventQueue.virtualNet_v.IsTerminal(theConnections.drainId)
169 						&& theEventQueue.virtualNet_v.IsTerminal(theConnections.sourceId)
170 						&& CheckConnectionReroute(theEventQueue, theConnections, DRAIN_TO_MASTER_SOURCE) ) {  // direct connections have precedence
171 					// lastUpdate changed due to virtual net rerouting
172 					theEventQueue.virtualNet_v.lastUpdate++;
173 					ShortNets(theEventQueue, theDeviceId, theConnections, DRAIN_TO_MASTER_SOURCE);
174 				} else if ( ! theEventQueue.virtualNet_v.IsTerminal(theConnections.sourceId)
175 						&& theEventQueue.virtualNet_v.IsTerminal(theConnections.drainId)
176 						&& CheckConnectionReroute(theEventQueue, theConnections, SOURCE_TO_MASTER_DRAIN) ) {  // direct connections have precedence
177 					// lastUpdate changed due to virtual net rerouting
178 					theEventQueue.virtualNet_v.lastUpdate++;
179 					ShortNets(theEventQueue, theDeviceId, theConnections, SOURCE_TO_MASTER_DRAIN);
180 				}
181 			} else if ( ! theEventQueue.virtualNet_v.IsTerminal(theConnections.drainId)
182 					&& ( theEventQueue.virtualNet_v.IsTerminal(theConnections.sourceId)  // direct connections have precedence
183 						|| theConnections.masterSourceNet.finalResistance + theConnections.resistance < theConnections.masterDrainNet.finalResistance ) ) {
184 				myLastVirtualNet = theEventQueue.virtualNet_v[theConnections.drainId];
185 				// lastUpdate changed due to virtual net rerouting
186 				theEventQueue.virtualNet_v.lastUpdate++;
187 				ShortNets(theEventQueue, theDeviceId, theConnections, DRAIN_TO_MASTER_SOURCE);
188 				ShiftVirtualNets(theEventQueue, theConnections.drainId, myLastVirtualNet,
189 					theConnections.masterSourceNet.finalResistance + theConnections.resistance, theConnections.masterDrainNet.finalResistance);
190 			} else if ( ! theEventQueue.virtualNet_v.IsTerminal(theConnections.sourceId)
191 					&& ( theEventQueue.virtualNet_v.IsTerminal(theConnections.drainId)  // direct connections have precedence
192 						|| theConnections.masterDrainNet.finalResistance + theConnections.resistance < theConnections.masterSourceNet.finalResistance ) ) {
193 				myLastVirtualNet = theEventQueue.virtualNet_v[theConnections.sourceId];
194 				// lastUpdate changed due to virtual net rerouting
195 				theEventQueue.virtualNet_v.lastUpdate++;
196 				ShortNets(theEventQueue, theDeviceId, theConnections, SOURCE_TO_MASTER_DRAIN);
197 				ShiftVirtualNets(theEventQueue, theConnections.sourceId, myLastVirtualNet,
198 					theConnections.masterDrainNet.finalResistance + theConnections.resistance, theConnections.masterSourceNet.finalResistance);
199 			}
200 		}
201 	} else {
202 		if ( theEventQueue.queueType == SIM_QUEUE ) {
203 			if ( deviceType_v[theDeviceId] != FUSE_OFF ) {
204 				// TODO: should do relative check and/or alias check
205 				if ( theConnections.sourcePower_p->type[HIZ_BIT] && theConnections.sourcePower_p->relativeFriendly
206 					&& theConnections.sourcePower_p->family() == theConnections.drainPower_p->powerSignal() ) return;
207 				if ( theConnections.drainPower_p->type[HIZ_BIT] && theConnections.drainPower_p->relativeFriendly
208 					&& theConnections.drainPower_p->family() == theConnections.sourcePower_p->powerSignal() ) return;
209 				ReportShort(theDeviceId);
210 			}
211 		} else {
212 			if ( theEventQueue.queueType == MIN_QUEUE ) {
213 				// TODO: IsUnknown check may not be needed. Checked in calling function
214 				if ( netStatus_v[theConnections.sourceId][NEEDS_MIN_CONNECTION] && IsKnownVoltage_(theConnections.drainVoltage)
215 						&& IsVerifiedPower(theConnections.masterDrainNet.finalNetId) ) {
216 					voltage_t myMaxVoltage = MaxVoltage(theConnections.sourceId);
217 					assert(netVoltagePtr_v[theConnections.sourceId].full);
218 					CPower * myPower_p = netVoltagePtr_v[theConnections.sourceId].full;
219 					if ( theConnections.sourceVoltage > theConnections.drainVoltage && ! ( leakVoltageSet && theConnections.drainPower_p->type[HIZ_BIT] ) ) {
220 						// ignore pull downs to HI-Z power in second pass
221 						if ( ! myPower_p->extraData ) myPower_p->extraData = new CExtraPowerData;
222 						myPower_p->extraData->pullDownVoltage = theConnections.drainVoltage;
223 						netStatus_v[theConnections.sourceId][NEEDS_MIN_CONNECTION] = false;
224 						if ( gDebug_cvc ) cout << "DEBUG: removed min connection check for net: " << theConnections.sourceId << " "
225 							<< theConnections.sourceVoltage << ">" << theConnections.drainVoltage << endl;
226 					} else if ( theConnections.sourceVoltage == theConnections.drainVoltage
227 							&& theConnections.drainVoltage == myMaxVoltage && ! netStatus_v[theConnections.drainId][NEEDS_MIN_CONNECTION] ) {
228 						// handles propagation through mos switch that might get deleted in second pass for HiZ power. (needs verification)
229 						if ( ! myPower_p->extraData ) myPower_p->extraData = new CExtraPowerData;
230 						myPower_p->extraData->pullDownVoltage = theConnections.drainVoltage;
231 						netStatus_v[theConnections.sourceId][NEEDS_MIN_CONNECTION] = false;
232 						if ( gDebug_cvc ) cout << "DEBUG: removed matching min connection check for net: " << theConnections.sourceId << " "
233 							<< theConnections.sourceVoltage << endl;
234 					} else if ( ! leakVoltageSet
235 							&& ( ( IsNmos_(deviceType_v[theDeviceId]) && LastNmosConnection(MIN_PENDING, theConnections.sourceId) )
236 									|| theConnections.device_p->IsResistor() ) ) {
237 						// remove calculated net and reroute to drain. only for initial power prop.
238 						if ( ! myPower_p->extraData ) myPower_p->extraData = new CExtraPowerData;
239 						myPower_p->extraData->pullDownVoltage = theConnections.drainVoltage;
240 						theEventQueue.virtualNet_v.Set(theConnections.sourceId, theConnections.drainId, theConnections.resistance, ++theEventQueue.virtualNet_v.lastUpdate);
241 						CheckResistorOverflow_(theEventQueue.virtualNet_v[theConnections.sourceId].finalResistance, theConnections.sourceId, logFile);
242 						if ( theConnections.sourceVoltage > theConnections.drainVoltage ) {
243 							netStatus_v[theConnections.sourceId][NEEDS_MIN_CONNECTION] = false;
244 							if ( gDebug_cvc ) cout << "DEBUG: rerouted min connection check for net: " <<  theConnections.sourceId << endl;
245 						}
246 					}
247 				}
248 				if ( netStatus_v[theConnections.drainId][NEEDS_MIN_CONNECTION] && IsKnownVoltage_(theConnections.sourceVoltage)
249 						&& IsVerifiedPower(theConnections.masterSourceNet.finalNetId) ) {
250 					voltage_t myMaxVoltage = MaxVoltage(theConnections.drainId);
251 					assert(netVoltagePtr_v[theConnections.drainId].full);
252 					CPower * myPower_p = netVoltagePtr_v[theConnections.drainId].full;
253 					if ( theConnections.drainVoltage > theConnections.sourceVoltage && ! ( leakVoltageSet && theConnections.sourcePower_p->type[HIZ_BIT] ) ) {
254 						// ignore pull downs to HI-Z power in second pass
255 						if ( ! myPower_p->extraData ) myPower_p->extraData = new CExtraPowerData;
256 						myPower_p->extraData->pullDownVoltage = theConnections.sourceVoltage;
257 						netStatus_v[theConnections.drainId][NEEDS_MIN_CONNECTION] = false;
258 						if ( gDebug_cvc ) cout << "DEBUG: removed min connection check for net: " << theConnections.drainId << " "
259 							<< theConnections.drainVoltage << ">" << theConnections.sourceVoltage << endl;
260 					} else if ( theConnections.sourceVoltage == theConnections.drainVoltage
261 							&& theConnections.sourceVoltage == myMaxVoltage && ! netStatus_v[theConnections.sourceId][NEEDS_MIN_CONNECTION] ) {
262 						// handles propagation through mos switch that might get deleted in second pass for HiZ power. (needs verification)
263 						if ( ! myPower_p->extraData ) myPower_p->extraData = new CExtraPowerData;
264 						myPower_p->extraData->pullDownVoltage = theConnections.sourceVoltage;
265 						netStatus_v[theConnections.drainId][NEEDS_MIN_CONNECTION] = false;
266 						if ( gDebug_cvc ) cout << "DEBUG: removed matching min connection check for net: " << theConnections.drainId << " "
267 							<< theConnections.drainVoltage << endl;
268 					} else if ( ! leakVoltageSet
269 							 && ( ( IsNmos_(deviceType_v[theDeviceId]) && LastNmosConnection(MIN_PENDING, theConnections.drainId) )
270 									 || theConnections.device_p->IsResistor() ) ) {
271 						// remove calculated net and reroute to drain. only for initial power prop.
272 						if ( ! myPower_p->extraData ) myPower_p->extraData = new CExtraPowerData;
273 						myPower_p->extraData->pullDownVoltage = theConnections.sourceVoltage;
274 						theEventQueue.virtualNet_v.Set(theConnections.drainId, theConnections.sourceId, theConnections.resistance, ++theEventQueue.virtualNet_v.lastUpdate);
275 						CheckResistorOverflow_(theEventQueue.virtualNet_v[theConnections.drainId].finalResistance, theConnections.drainId, logFile);
276 						if ( theConnections.drainVoltage > theConnections.sourceVoltage ) {
277 							netStatus_v[theConnections.drainId][NEEDS_MIN_CONNECTION] = false;
278 							if ( gDebug_cvc ) cout << "DEBUG: rerouted min connection check for net: " <<  theConnections.drainId << endl;
279 						}
280 					}
281 
282 				}
283 			}
284 			if ( theEventQueue.queueType == MAX_QUEUE ) {
285 				if ( netStatus_v[theConnections.sourceId][NEEDS_MAX_CONNECTION] && IsKnownVoltage_(theConnections.drainVoltage)
286 						&& IsVerifiedPower(theConnections.masterDrainNet.finalNetId) ) {
287 					voltage_t myMinVoltage = MinVoltage(theConnections.sourceId);
288 					assert(netVoltagePtr_v[theConnections.sourceId].full);
289 					CPower * myPower_p = netVoltagePtr_v[theConnections.sourceId].full;
290 					if ( theConnections.sourceVoltage < theConnections.drainVoltage && ! ( leakVoltageSet && theConnections.drainPower_p->type[HIZ_BIT] ) ) {
291 						// ignore pull ups to HI-Z power in second pass
292 						if ( ! myPower_p->extraData ) myPower_p->extraData = new CExtraPowerData;
293 						myPower_p->extraData->pullUpVoltage = theConnections.drainVoltage;
294 						netStatus_v[theConnections.sourceId][NEEDS_MAX_CONNECTION] = false;
295 						if ( gDebug_cvc ) cout << "DEBUG: removed max connection check for net: " << theConnections.sourceId << " "
296 							<< theConnections.sourceVoltage << "<" << theConnections.drainVoltage << endl;
297 					} else if ( theConnections.sourceVoltage == theConnections.drainVoltage
298 							&& theConnections.drainVoltage == myMinVoltage && ! netStatus_v[theConnections.drainId][NEEDS_MAX_CONNECTION] ) {
299 						// handles propagation through mos switch that might get deleted in second pass for HiZ power. (needs verification)
300 						if ( ! myPower_p->extraData ) myPower_p->extraData = new CExtraPowerData;
301 						myPower_p->extraData->pullUpVoltage = theConnections.drainVoltage;
302 						netStatus_v[theConnections.sourceId][NEEDS_MAX_CONNECTION] = false;
303 						if ( gDebug_cvc ) cout << "DEBUG: removed matching max connection check for net: " << theConnections.sourceId << " "
304 							<< theConnections.sourceVoltage << endl;
305 					} else if ( ! leakVoltageSet
306 							&& ( ( IsPmos_(deviceType_v[theDeviceId]) && LastPmosConnection(MAX_PENDING, theConnections.sourceId) )
307 									|| theConnections.device_p->IsResistor() ) ) {
308 						// remove calculated net and reroute to drain. only for initial power prop.
309 						if ( ! myPower_p->extraData ) myPower_p->extraData = new CExtraPowerData;
310 						myPower_p->extraData->pullUpVoltage = theConnections.drainVoltage;
311 						theEventQueue.virtualNet_v.Set(theConnections.sourceId, theConnections.drainId, theConnections.resistance, ++theEventQueue.virtualNet_v.lastUpdate);
312 						CheckResistorOverflow_(theEventQueue.virtualNet_v[theConnections.sourceId].finalResistance, theConnections.sourceId, logFile);
313 						if ( theConnections.sourceVoltage < theConnections.drainVoltage ) {
314 							netStatus_v[theConnections.sourceId][NEEDS_MAX_CONNECTION] = false;
315 							if ( gDebug_cvc ) cout << "DEBUG: rerouted max connection check for net: " <<  theConnections.sourceId << endl;
316 						}
317 					}
318 				}
319 				if ( netStatus_v[theConnections.drainId][NEEDS_MAX_CONNECTION] && IsKnownVoltage_(theConnections.sourceVoltage)
320 						&& IsVerifiedPower(theConnections.masterSourceNet.finalNetId) ) {
321 					voltage_t myMinVoltage = MinVoltage(theConnections.drainId);
322 					assert(netVoltagePtr_v[theConnections.drainId].full);
323 					CPower * myPower_p = netVoltagePtr_v[theConnections.drainId].full;
324 					if ( theConnections.drainVoltage < theConnections.sourceVoltage && ! ( leakVoltageSet && theConnections.sourcePower_p->type[HIZ_BIT] ) ) {
325 						// ignore pull ups to HI-Z power in second pass
326 						if ( ! myPower_p->extraData ) myPower_p->extraData = new CExtraPowerData;
327 						myPower_p->extraData->pullUpVoltage = theConnections.sourceVoltage;
328 						netStatus_v[theConnections.drainId][NEEDS_MAX_CONNECTION] = false;
329 						if ( gDebug_cvc ) cout << "DEBUG: removed max connection check for net: " << theConnections.drainId << " "
330 							<< theConnections.drainVoltage << "<" << theConnections.sourceVoltage << endl;
331 					} else if ( theConnections.sourceVoltage == theConnections.drainVoltage
332 							&& theConnections.drainVoltage == myMinVoltage && ! netStatus_v[theConnections.sourceId][NEEDS_MAX_CONNECTION] ) {
333 						// handles propagation through mos switch that might get deleted in second pass for HiZ power. (needs verification)
334 						if ( ! myPower_p->extraData ) myPower_p->extraData = new CExtraPowerData;
335 						myPower_p->extraData->pullUpVoltage = theConnections.sourceVoltage;
336 						netStatus_v[theConnections.drainId][NEEDS_MAX_CONNECTION] = false;
337 						if ( gDebug_cvc ) cout << "DEBUG: removed matching max connection check for net: " << theConnections.drainId << " "
338 							<< theConnections.drainVoltage << endl;
339 					} else if ( ! leakVoltageSet
340 							&& ( ( IsPmos_(deviceType_v[theDeviceId]) && LastPmosConnection(MAX_PENDING, theConnections.drainId) )
341 									|| theConnections.device_p->IsResistor() ) ) {
342 						// remove calculated net and reroute to drain. only for initial power prop.
343 						if ( ! myPower_p->extraData ) myPower_p->extraData = new CExtraPowerData;
344 						myPower_p->extraData->pullUpVoltage = theConnections.sourceVoltage;
345 						theEventQueue.virtualNet_v.Set(theConnections.drainId, theConnections.sourceId, theConnections.resistance, ++theEventQueue.virtualNet_v.lastUpdate);
346 						CheckResistorOverflow_(theEventQueue.virtualNet_v[theConnections.drainId].finalResistance, theConnections.drainId, logFile);
347 						if ( theConnections.drainVoltage < theConnections.sourceVoltage ) {
348 							netStatus_v[theConnections.drainId][NEEDS_MAX_CONNECTION] = false;
349 							if ( gDebug_cvc ) cout << "DEBUG: rerouted max connection check for net: " <<  theConnections.drainId << endl;
350 						}
351 					}
352 				}
353 			}
354 			// TODO: family check not correct. need to check for relatives
355 			if ( theConnections.sourcePower_p->family() != theConnections.drainPower_p->family() ) {
356 				if (gDebug_cvc) cout << "adding leak" << endl;
357 				theEventQueue.AddLeak(theDeviceId, theConnections);
358 			}
359 		}
360 	}
361 	deviceStatus_v[theDeviceId][theEventQueue.inactiveBit] = true;
362 }
363 
VoltageConflict(CEventQueue & theEventQueue,deviceId_t theDeviceId,CConnection & theConnections)364 bool CCvcDb::VoltageConflict(CEventQueue& theEventQueue, deviceId_t theDeviceId, CConnection& theConnections) {
365 	// first MIN/MAX pass propagate to unknown open nets. SIM and second MIN/MAX cause error.
366 	if ( ! leakVoltageSet && ( theConnections.sourceVoltage == UNKNOWN_VOLTAGE || theConnections.drainVoltage == UNKNOWN_VOLTAGE ) ) return false;
367 	if ( theConnections.IsUnknownSourceVoltage() || theConnections.IsUnknownDrainVoltage() ) return false;
368 	// check voltage family conflicts later
369 	if ( theEventQueue.queueType == SIM_QUEUE && IsMos_(deviceType_v[theDeviceId]) && theConnections.gateVoltage == UNKNOWN_VOLTAGE ) return false;
370 
371 	if (gDebug_cvc) cout << "already shorted VC " << gEventQueueTypeMap[theEventQueue.queueType] << " " << theDeviceId << endl;
372 	// activate voltages
373 	deviceStatus_v[theDeviceId][theEventQueue.pendingBit] = true;
374 	if ( theEventQueue.queueType == MIN_QUEUE ) {
375 		if ( theConnections.drainPower_p && theConnections.drainPower_p->minVoltage != UNKNOWN_VOLTAGE &&
376 				! theConnections.drainPower_p->active[MIN_ACTIVE] && ! theConnections.drainPower_p->active[MIN_IGNORE] ) {
377 			if ( theConnections.sourceVoltage <= theConnections.drainVoltage ) {
378 				theConnections.drainPower_p->active[MIN_ACTIVE] = true;
379 				EnqueueAttachedDevices(theEventQueue, theConnections.drainId, theConnections.drainVoltage);
380 			} else if ( IsGreaterVoltage_(MinLeakVoltage(theConnections.drainId), theConnections.drainVoltage) ) {
381 				reportFile << "WARNING: min voltage " << theConnections.drainPower_p->minVoltage << " ignored for " << NetName(theConnections.drainId, PRINT_CIRCUIT_OFF) \
382 						<< " at " << DeviceName(theDeviceId, PRINT_CIRCUIT_ON) << endl;
383 			}
384 		} else if ( theConnections.sourcePower_p && theConnections.sourcePower_p->minVoltage != UNKNOWN_VOLTAGE &&
385 				! theConnections.sourcePower_p->active[MIN_ACTIVE] && ! theConnections.sourcePower_p->active[MIN_IGNORE] ) {
386 			if ( theConnections.drainVoltage <= theConnections.sourceVoltage ) {
387 				theConnections.sourcePower_p->active[MIN_ACTIVE] = true;
388 				EnqueueAttachedDevices(theEventQueue, theConnections.sourceId, theConnections.sourceVoltage);
389 			} else if ( IsGreaterVoltage_(MinLeakVoltage(theConnections.sourceId), theConnections.sourceVoltage) ) {
390 				reportFile << "WARNING: min voltage " << theConnections.sourcePower_p->minVoltage << " ignored for " << NetName(theConnections.sourceId, PRINT_CIRCUIT_OFF) \
391 						<< " at " << DeviceName(theDeviceId, PRINT_CIRCUIT_ON) << endl;
392 			}
393 		}
394 		// Unset min checks
395 		CStatus & myDrainStatus = netStatus_v[theConnections.drainId];
396 		CStatus & mySourceStatus = netStatus_v[theConnections.sourceId];
397 		bool mySourceVerified = ! (mySourceStatus[NEEDS_MIN_CHECK] || mySourceStatus[NEEDS_MIN_CONNECTION]);
398 		bool myDrainVerified = ! (myDrainStatus[NEEDS_MIN_CHECK] || myDrainStatus[NEEDS_MIN_CONNECTION]);
399 		if ( ( myDrainStatus[NEEDS_MIN_CHECK] || myDrainStatus[NEEDS_MIN_CONNECTION] )
400 				&& theConnections.sourceVoltage != UNKNOWN_VOLTAGE && theConnections.drainVoltage != UNKNOWN_VOLTAGE
401 				&& mySourceVerified
402 				&& theConnections.drainVoltage > theConnections.sourceVoltage ) {
403 			if ( gDebug_cvc ) cout << "DEBUG: Removed min check for net " << theConnections.drainId
404 					<< "(" << theConnections.drainVoltage << ") from " << theConnections.sourceId << "(" << theConnections.sourceVoltage << ")" << endl;
405 			assert(netVoltagePtr_v[theConnections.drainId].full);
406 			CPower * myPower_p = netVoltagePtr_v[theConnections.drainId].full;
407 			if ( ! myPower_p->extraData ) myPower_p->extraData = new CExtraPowerData;
408 			myPower_p->extraData->pullDownVoltage = theConnections.sourceVoltage;
409 			myDrainStatus[NEEDS_MIN_CHECK] = myDrainStatus[NEEDS_MIN_CONNECTION] = false;
410 		}
411 		if ( ( mySourceStatus[NEEDS_MIN_CHECK] || mySourceStatus[NEEDS_MIN_CONNECTION] )
412 				&& theConnections.sourceVoltage != UNKNOWN_VOLTAGE && theConnections.drainVoltage != UNKNOWN_VOLTAGE
413 				&& myDrainVerified
414 				&& theConnections.sourceVoltage > theConnections.drainVoltage ) {
415 			if ( gDebug_cvc ) cout << "DEBUG: Removed min check for net " << theConnections.sourceId
416 					<< "(" << theConnections.sourceVoltage << ") from " << theConnections.drainId << "(" << theConnections.drainVoltage << ")" << endl;
417 			assert(netVoltagePtr_v[theConnections.sourceId].full);
418 			CPower * myPower_p = netVoltagePtr_v[theConnections.sourceId].full;
419 			if ( ! myPower_p->extraData ) myPower_p->extraData = new CExtraPowerData;
420 			myPower_p->extraData->pullDownVoltage = theConnections.drainVoltage;
421 			mySourceStatus[NEEDS_MIN_CHECK] = mySourceStatus[NEEDS_MIN_CONNECTION] = false;
422 		}
423 		// for mos connected as diode with source/drain known. Add max voltage propagation/check
424 		if ( IsMos_(deviceType_v[theDeviceId]) ) {
425 			voltage_t mySourceVoltage;
426 			netId_t myTargetNetId = UNKNOWN_NET;
427 			netId_t mySourceNetId;
428 			calculationType_t myCalculationType;
429 			if ( theConnections.sourceId == theConnections.gateId ) {
430 				myTargetNetId = theConnections.sourceId;
431 				mySourceNetId = theConnections.drainId;
432 				mySourceVoltage = theConnections.drainVoltage;
433 				myCalculationType = theConnections.drainPower_p->minCalculationType;
434 			} else if ( theConnections.drainId == theConnections.gateId ) {
435 				myTargetNetId = theConnections.drainId;
436 				mySourceNetId = theConnections.sourceId;
437 				mySourceVoltage = theConnections.sourceVoltage;
438 				myCalculationType = theConnections.sourcePower_p->minCalculationType;
439 			}
440 			if ( myTargetNetId != UNKNOWN_NET ) {
441 				voltage_t myExpectedVoltage = mySourceVoltage + theConnections.device_p->model_p->Vth;
442 				CConnection myMaxConnections;
443 				MapDeviceNets(theConnections.deviceId, maxEventQueue, myMaxConnections);
444 				if ( myCalculationType != DOWN_CALCULATION ) {  // do not cross propagate calculated voltages
445 					if ( myMaxConnections.gateVoltage == UNKNOWN_VOLTAGE ) {
446 						EnqueueAttachedDevices(maxEventQueue, myTargetNetId, myExpectedVoltage); // enqueue in opposite queue
447 					} else if ( ! myMaxConnections.gatePower_p->type[HIZ_BIT]
448 							&& ((myMaxConnections.gateVoltage > myExpectedVoltage && IsNmos_(deviceType_v[theConnections.deviceId]))
449 								|| (myMaxConnections.gateVoltage < myExpectedVoltage && IsPmos_(deviceType_v[theConnections.deviceId])) ) ) {
450 						float myLeakCurrent = myMaxConnections.EstimatedMosDiodeCurrent(mySourceVoltage, theConnections);
451 						bool myCheckLeakCurrent = cvcParameters.cvcMosDiodeErrorThreshold == 0
452 								|| abs(myMaxConnections.gateVoltage - myExpectedVoltage) > cvcParameters.cvcMosDiodeErrorThreshold;
453 						if ( myCheckLeakCurrent && ExceedsLeakLimit_(myLeakCurrent) && netVoltagePtr_v[mySourceNetId].full ) {  // no errors if not direct propagation
454 							PrintMaxVoltageConflict(myTargetNetId, myMaxConnections, myExpectedVoltage, myLeakCurrent);
455 						}
456 					}
457 				}
458 			}
459 		}
460 	} else if ( theEventQueue.queueType == MAX_QUEUE ) {
461 		if ( theConnections.drainPower_p && theConnections.drainPower_p->maxVoltage != UNKNOWN_VOLTAGE &&
462 				! theConnections.drainPower_p->active[MAX_ACTIVE] && ! theConnections.drainPower_p->active[MAX_IGNORE] ) {
463 			if ( theConnections.drainVoltage <= theConnections.sourceVoltage ) {
464 				theConnections.drainPower_p->active[MAX_ACTIVE] = true;
465 				EnqueueAttachedDevices(theEventQueue, theConnections.drainId, theConnections.drainVoltage);
466 			} else if ( IsLesserVoltage_(MaxLeakVoltage(theConnections.drainId), theConnections.drainVoltage) ) {
467 				reportFile << "WARNING: max voltage " << theConnections.drainPower_p->maxVoltage << " ignored for " << NetName(theConnections.drainId, PRINT_CIRCUIT_OFF, PRINT_HIERARCHY_OFF) \
468 						<< " at " << DeviceName(theDeviceId, PRINT_CIRCUIT_ON) << endl;
469 			}
470 		} else if ( theConnections.sourcePower_p && theConnections.sourcePower_p->maxVoltage != UNKNOWN_VOLTAGE &&
471 				! theConnections.sourcePower_p->active[MAX_ACTIVE] && ! theConnections.sourcePower_p->active[MAX_IGNORE] ) {
472 			if ( theConnections.sourceVoltage <= theConnections.drainVoltage ) {
473 				theConnections.sourcePower_p->active[MAX_ACTIVE] = true;
474 				EnqueueAttachedDevices(theEventQueue, theConnections.sourceId, theConnections.sourceVoltage);
475 			} else if ( IsLesserVoltage_(MaxLeakVoltage(theConnections.sourceId), theConnections.sourceVoltage) ) {
476 				reportFile << "WARNING: max voltage " << theConnections.sourcePower_p->maxVoltage << " ignored for " << NetName(theConnections.sourceId, PRINT_CIRCUIT_OFF, PRINT_HIERARCHY_OFF) \
477 						<< " at " << DeviceName(theDeviceId, PRINT_CIRCUIT_ON) << endl;
478 			}
479 		}
480 		// Unset max checks
481 		CStatus & myDrainStatus = netStatus_v[theConnections.drainId];
482 		CStatus & mySourceStatus = netStatus_v[theConnections.sourceId];
483 		bool mySourceVerified = ! (mySourceStatus[NEEDS_MAX_CHECK] || mySourceStatus[NEEDS_MAX_CONNECTION]);
484 		bool myDrainVerified = ! (myDrainStatus[NEEDS_MAX_CHECK] || myDrainStatus[NEEDS_MAX_CONNECTION]);
485 		if ( ( myDrainStatus[NEEDS_MAX_CHECK] || myDrainStatus[NEEDS_MAX_CONNECTION] )
486 				&& theConnections.sourceVoltage != UNKNOWN_VOLTAGE && theConnections.drainVoltage != UNKNOWN_VOLTAGE
487 				&& mySourceVerified
488 				&& theConnections.drainVoltage < theConnections.sourceVoltage ) {
489 			if ( gDebug_cvc ) cout << "DEBUG: Removed max check for net " << theConnections.drainId
490 					<< "(" << theConnections.drainVoltage << ") from " << theConnections.sourceId << "(" << theConnections.sourceVoltage << ")" << endl;
491 			assert(netVoltagePtr_v[theConnections.drainId].full);
492 			CPower * myPower_p = netVoltagePtr_v[theConnections.drainId].full;
493 			if ( ! myPower_p->extraData ) myPower_p->extraData = new CExtraPowerData;
494 			myPower_p->extraData->pullUpVoltage = theConnections.sourceVoltage;
495 			myDrainStatus[NEEDS_MAX_CHECK] = myDrainStatus[NEEDS_MAX_CONNECTION] = false;
496 		}
497 		if ( ( mySourceStatus[NEEDS_MAX_CHECK] || mySourceStatus[NEEDS_MAX_CONNECTION] )
498 				&& theConnections.sourceVoltage != UNKNOWN_VOLTAGE && theConnections.drainVoltage != UNKNOWN_VOLTAGE
499 				&& myDrainVerified
500 				&& theConnections.sourceVoltage < theConnections.drainVoltage ) {
501 			if ( gDebug_cvc ) cout << "DEBUG: Removed max check for net " << theConnections.sourceId
502 					<< "(" << theConnections.sourceVoltage << ") from " << theConnections.drainId << "(" << theConnections.drainVoltage << ")" << endl;
503 			assert(netVoltagePtr_v[theConnections.sourceId].full);
504 			CPower * myPower_p = netVoltagePtr_v[theConnections.sourceId].full;
505 			if ( ! myPower_p->extraData ) myPower_p->extraData = new CExtraPowerData;
506 			myPower_p->extraData->pullUpVoltage = theConnections.drainVoltage;
507 			mySourceStatus[NEEDS_MAX_CHECK] = mySourceStatus[NEEDS_MAX_CONNECTION] = false;
508 		}
509 
510 		// for mos connected as diode with source/drain known. Add min voltage propagation/check
511 		if ( IsMos_(deviceType_v[theDeviceId]) ) {
512 			voltage_t mySourceVoltage;
513 			netId_t myTargetNetId = UNKNOWN_NET;
514 			netId_t mySourceNetId;
515 			calculationType_t myCalculationType;
516 			if ( theConnections.sourceId == theConnections.gateId ) {
517 				myTargetNetId = theConnections.sourceId;
518 				mySourceNetId = theConnections.drainId;
519 				mySourceVoltage = theConnections.drainVoltage;
520 				myCalculationType = theConnections.drainPower_p->maxCalculationType;
521 			} else if ( theConnections.drainId == theConnections.gateId ) {
522 				myTargetNetId = theConnections.drainId;
523 				mySourceNetId = theConnections.sourceId;
524 				mySourceVoltage = theConnections.sourceVoltage;
525 				myCalculationType = theConnections.sourcePower_p->maxCalculationType;
526 			}
527 			if ( myTargetNetId != UNKNOWN_NET ) {
528 				voltage_t myExpectedVoltage = mySourceVoltage + theConnections.device_p->model_p->Vth;
529 				CConnection myMinConnections;
530 				MapDeviceNets(theConnections.deviceId, minEventQueue, myMinConnections);
531 				if ( myCalculationType != UP_CALCULATION ) {  // do not cross propagate calculated voltages
532 					if ( myMinConnections.gateVoltage == UNKNOWN_VOLTAGE ) {
533 						EnqueueAttachedDevices(minEventQueue, myTargetNetId, myExpectedVoltage); // enqueue in opposite queue
534 					} else if ( ! myMinConnections.gatePower_p->type[HIZ_BIT]
535 							&& ((myMinConnections.gateVoltage > myExpectedVoltage && IsNmos_(deviceType_v[theConnections.deviceId]))
536 								|| (myMinConnections.gateVoltage < myExpectedVoltage && IsPmos_(deviceType_v[theConnections.deviceId])) ) ) {
537 						float myLeakCurrent = myMinConnections.EstimatedMosDiodeCurrent(mySourceVoltage, theConnections);
538 						bool myCheckLeakCurrent = cvcParameters.cvcMosDiodeErrorThreshold == 0
539 							|| abs(myMinConnections.gateVoltage - myExpectedVoltage) > cvcParameters.cvcMosDiodeErrorThreshold;
540 						if ( myCheckLeakCurrent && ExceedsLeakLimit_(myLeakCurrent) && netVoltagePtr_v[mySourceNetId].full ) {  // no errors if not direct propagation
541 							PrintMinVoltageConflict(myTargetNetId, myMinConnections, myExpectedVoltage, myLeakCurrent);
542 						}
543 					}
544 				}
545 			}
546 		}
547 	}
548 	deviceStatus_v[theDeviceId][theEventQueue.pendingBit] = false;
549 	AlreadyShorted(theEventQueue, theDeviceId, theConnections);
550 
551 	return true;
552 }
553 
TopologicallyOffMos(eventQueue_t theQueueType,modelType_t theModelType,CConnection & theConnections)554 bool CCvcDb::TopologicallyOffMos(eventQueue_t theQueueType, modelType_t theModelType, CConnection& theConnections) {
555 	if ( (theQueueType == MAX_QUEUE && IsPmos_(theModelType)) || (theQueueType == MIN_QUEUE && IsNmos_(theModelType)) ) {
556 		if ( theConnections.drainVoltage == UNKNOWN_VOLTAGE ) return theConnections.gateId == theConnections.sourceId;
557 		if ( theConnections.sourceVoltage == UNKNOWN_VOLTAGE ) return theConnections.gateId == theConnections.drainId;
558 	} else if ( (theQueueType == MAX_QUEUE && IsNmos_(theModelType)) || (theQueueType == MIN_QUEUE && IsPmos_(theModelType)) ) {
559 		if ( theConnections.drainVoltage == UNKNOWN_VOLTAGE ) return theConnections.gateId == theConnections.drainId;
560 		if ( theConnections.sourceVoltage == UNKNOWN_VOLTAGE ) return theConnections.gateId == theConnections.sourceId;
561 	}
562 	return false;
563 }
564 
IsOffMos(eventQueue_t theQueueType,deviceId_t theDeviceId,CConnection & theConnections,voltage_t theVoltage)565 bool CCvcDb::IsOffMos(eventQueue_t theQueueType, deviceId_t theDeviceId, CConnection& theConnections, voltage_t theVoltage) {
566 	if ( TopologicallyOffMos(theQueueType, deviceType_v[theDeviceId], theConnections) ) {
567 		// TODO: possibly ignore for queue type
568 //		IgnoreDevice(theDeviceId);
569 		return true;
570 	}
571 	if ( theConnections.sourceVoltage == theVoltage || theConnections.drainVoltage == theVoltage ) {
572 		// TODO: Possible ordering problem. change to min/max Leak?
573 		if ( theQueueType == MAX_QUEUE && IsPmos_(deviceType_v[theDeviceId]) ) {
574 			voltage_t myMinGate = MinVoltage(theConnections.gateId);
575 			if ( myMinGate != UNKNOWN_VOLTAGE && myMinGate > theVoltage + theConnections.device_p->model_p->Vth ) return true;
576 		}
577 		if ( theQueueType == MIN_QUEUE && IsNmos_(deviceType_v[theDeviceId]) ) {
578 			voltage_t myMaxGate = MaxVoltage(theConnections.gateId);
579 			if ( myMaxGate != UNKNOWN_VOLTAGE && myMaxGate < theVoltage + theConnections.device_p->model_p->Vth ) return true;
580 		}
581 	}
582 	if ( theQueueType == SIM_QUEUE ) {
583 		if ( IsPmos_(deviceType_v[theDeviceId]) ) {
584 			voltage_t myGateVoltage = ( theConnections.gateVoltage == UNKNOWN_VOLTAGE ) ? MinVoltage(theConnections.gateId) : theConnections.gateVoltage;
585 			voltage_t mySourceVoltage = ( theConnections.sourceVoltage == UNKNOWN_VOLTAGE ) ? MaxLeakVoltage(theConnections.sourceId) : theConnections.sourceVoltage;
586 			voltage_t myDrainVoltage = ( theConnections.drainVoltage == UNKNOWN_VOLTAGE ) ? MaxLeakVoltage(theConnections.drainId) : theConnections.drainVoltage;
587 			if ( myGateVoltage == UNKNOWN_VOLTAGE || mySourceVoltage == UNKNOWN_VOLTAGE || myDrainVoltage == UNKNOWN_VOLTAGE ) return false;
588 			bool mySourceOff = myGateVoltage > mySourceVoltage + theConnections.device_p->model_p->Vth;
589 			bool myDrainOff = myGateVoltage > myDrainVoltage + theConnections.device_p->model_p->Vth;
590 			if ( theConnections.sourceVoltage == UNKNOWN_VOLTAGE && myDrainOff && ! mySourceOff && maxNet_v[theConnections.sourceId].nextNetId == theConnections.drainId ) return true;  // prevents vth drops back through mos.
591 			if ( theConnections.drainVoltage == UNKNOWN_VOLTAGE && ! myDrainOff && mySourceOff && maxNet_v[theConnections.drainId].nextNetId == theConnections.sourceId ) return true;  // prevents vth drops back through mos.
592 			if ( mySourceOff && myDrainOff ) return true;
593 		}
594 		if ( IsNmos_(deviceType_v[theDeviceId]) ) {
595 			voltage_t myGateVoltage = ( theConnections.gateVoltage == UNKNOWN_VOLTAGE ) ? MaxVoltage(theConnections.gateId) : theConnections.gateVoltage;
596 			voltage_t mySourceVoltage = ( theConnections.sourceVoltage == UNKNOWN_VOLTAGE ) ? MinLeakVoltage(theConnections.sourceId) : theConnections.sourceVoltage;
597 			voltage_t myDrainVoltage = ( theConnections.drainVoltage == UNKNOWN_VOLTAGE ) ? MinLeakVoltage(theConnections.drainId) : theConnections.drainVoltage;
598 			if ( myGateVoltage == UNKNOWN_VOLTAGE || mySourceVoltage == UNKNOWN_VOLTAGE || myDrainVoltage == UNKNOWN_VOLTAGE ) return false;
599 			bool mySourceOff = myGateVoltage < mySourceVoltage + theConnections.device_p->model_p->Vth;
600 			bool myDrainOff = myGateVoltage < myDrainVoltage + theConnections.device_p->model_p->Vth;
601 			if ( theConnections.sourceVoltage == UNKNOWN_VOLTAGE && myDrainOff && ! mySourceOff && minNet_v[theConnections.sourceId].nextNetId == theConnections.drainId ) return true;  // prevents vth drops back through mos.
602 			if ( theConnections.drainVoltage == UNKNOWN_VOLTAGE && ! myDrainOff && mySourceOff && minNet_v[theConnections.drainId].nextNetId == theConnections.sourceId ) return true;  // prevents vth drops back through mos.
603 			if ( mySourceOff && myDrainOff ) return true;		}
604 	}
605 	return false;
606 }
607 
LastNmosConnection(deviceStatus_t thePendingBit,netId_t theNetId)608 bool CCvcDb::LastNmosConnection(deviceStatus_t thePendingBit, netId_t theNetId) {
609 	int myConnectionCount = 0;
610 	for ( deviceId_t device_it = firstSource_v[theNetId]; device_it != UNKNOWN_DEVICE; device_it = nextSource_v[device_it] ) {
611 		if ( IsNmos_(deviceType_v[device_it]) && deviceStatus_v[device_it][thePendingBit] ) {
612 			if ( ++myConnectionCount > 1 ) return false;
613 		}
614 	}
615 	for ( deviceId_t device_it = firstDrain_v[theNetId]; device_it != UNKNOWN_DEVICE; device_it = nextDrain_v[device_it] ) {
616 		if ( IsNmos_(deviceType_v[device_it]) && deviceStatus_v[device_it][thePendingBit] ) {
617 			if ( ++myConnectionCount > 1 ) return false;
618 		}
619 	}
620 	return ( myConnectionCount < 2 );
621 }
622 
LastPmosConnection(deviceStatus_t thePendingBit,netId_t theNetId)623 bool CCvcDb::LastPmosConnection(deviceStatus_t thePendingBit, netId_t theNetId) {
624 	int myConnectionCount = 0;
625 	for ( deviceId_t device_it = firstSource_v[theNetId]; device_it != UNKNOWN_DEVICE; device_it = nextSource_v[device_it] ) {
626 		if ( IsPmos_(deviceType_v[device_it]) && deviceStatus_v[device_it][thePendingBit] ) {
627 			if ( ++myConnectionCount > 1 ) return false;
628 		}
629 	}
630 	for ( deviceId_t device_it = firstDrain_v[theNetId]; device_it != UNKNOWN_DEVICE; device_it = nextDrain_v[device_it] ) {
631 		if ( IsPmos_(deviceType_v[device_it]) && deviceStatus_v[device_it][thePendingBit] ) {
632 			if ( ++myConnectionCount > 1 ) return false;
633 		}
634 	}
635 	return ( myConnectionCount < 2 );
636 }
637 
IsIrrelevant(CEventQueue & theEventQueue,deviceId_t theDeviceId,CConnection & theConnections,voltage_t theVoltage,queueStatus_t theQueueStatus)638 bool CCvcDb::IsIrrelevant(CEventQueue& theEventQueue, deviceId_t theDeviceId, CConnection& theConnections, voltage_t theVoltage, queueStatus_t theQueueStatus) {
639 	// Already shorted nets are irrelevant
640 	if ( theConnections.masterSourceNet == theConnections.masterDrainNet) return true;
641 	// mos is off
642 	if ( theQueueStatus == ENQUEUE && theEventQueue.queueType != SIM_QUEUE ) return false; // MIN/MAX queues don't check for off mos because not in order
643 	if ( IsOffMos(theEventQueue.queueType, theDeviceId, theConnections, theVoltage) ) {
644 		if ( leakVoltageSet ) return true;
645 		// first time, propagate thru off mos if only chance
646 		netId_t myTargetNet;
647 		if ( theConnections.sourceVoltage == UNKNOWN_VOLTAGE ) {
648 			myTargetNet = theConnections.sourceId;
649 		} else if ( theConnections.drainVoltage == UNKNOWN_VOLTAGE ) {
650 			myTargetNet = theConnections.drainId;
651 		} else {
652 			// Voltage conflict with off mos
653 			if ( theEventQueue.queueType == MIN_QUEUE ) {
654 				if ( netStatus_v[theConnections.sourceId][NEEDS_MIN_CONNECTION] && theConnections.sourceVoltage > theConnections.drainVoltage ) {
655 					netStatus_v[theConnections.sourceId][NEEDS_MIN_CONNECTION] = false;
656 				} else if ( netStatus_v[theConnections.drainId][NEEDS_MIN_CONNECTION] && theConnections.drainVoltage > theConnections.sourceVoltage ) {
657 					netStatus_v[theConnections.drainId][NEEDS_MIN_CONNECTION] = false;
658 				}
659 			} else if  ( theEventQueue.queueType == MAX_QUEUE ) {
660 				if ( netStatus_v[theConnections.sourceId][NEEDS_MAX_CONNECTION] && theConnections.sourceVoltage < theConnections.drainVoltage ) {
661 					netStatus_v[theConnections.sourceId][NEEDS_MAX_CONNECTION] = false;
662 				} else if ( netStatus_v[theConnections.drainId][NEEDS_MAX_CONNECTION] && theConnections.drainVoltage < theConnections.sourceVoltage ) {
663 					netStatus_v[theConnections.drainId][NEEDS_MAX_CONNECTION] = false;
664 				}
665 			}
666 			return true;
667 		}
668 		// first time enqueue all off mos, subsequently only process last connections
669 		if ( theEventQueue.queueType == MIN_QUEUE && IsNmos_(deviceType_v[theDeviceId]) ) {
670 			if ( theEventQueue.dequeueCount > 0 && ! LastNmosConnection(MIN_PENDING, myTargetNet) ) return true; // LDDN is NMOS in connection count
671 		} else if ( theEventQueue.queueType == MAX_QUEUE && IsPmos_(deviceType_v[theDeviceId]) ) {
672 			if ( theEventQueue.dequeueCount > 0 && ! LastPmosConnection(MAX_PENDING, myTargetNet) ) return true; // LDDP is PMOS in connection count
673 		} else {
674 			return true;
675 		}
676 	}
677 	// devices connecting 2 powers to be handled later
678 
679 	// Skip short checks on enqueue (common for MIN/MAX/SIM).
680 	if ( theQueueStatus == DEQUEUE ) {
681 		if ( VoltageConflict(theEventQueue, theDeviceId, theConnections) ) {
682 			return true;
683 		}
684 	}
685 
686 	// wrong bias: delays, does not prevent
687 
688 	// other conditions
689 	return false;
690 }
691 
AdjustMaxPmosKey(CConnection & theConnections,netId_t theDrainId,voltage_t theMaxSource,eventKey_t & theEventKey,queuePosition_t & theQueuePosition)692 string CCvcDb::AdjustMaxPmosKey(CConnection& theConnections, netId_t theDrainId, voltage_t theMaxSource, eventKey_t& theEventKey, queuePosition_t& theQueuePosition) {
693 	string myAdjustment = "";
694 	if ( theConnections.gateId == theDrainId ) {
695 		if ( theConnections.device_p->model_p->Vth < 0 ) {
696 			myAdjustment = " PMOS Vth drop " + PrintParameter(theEventKey, VOLTAGE_SCALE) + PrintParameter(theConnections.device_p->model_p->Vth, VOLTAGE_SCALE);
697 			theEventKey = theEventKey + theConnections.device_p->model_p->Vth;
698 		}
699 		theQueuePosition = MOS_DIODE; // mos diode
700 	} else {
701 		if ( connectionCount_v[theDrainId].sourceDrainType[NMOS] ) {
702 			theQueuePosition = DELAY_FRONT; // front of delay queue
703 		}
704 		if ( theConnections.bulkVoltage == UNKNOWN_VOLTAGE ) {
705 			theQueuePosition = DELAY_BACK; // back of delay queue
706 		} else if ( theMaxSource > theConnections.bulkVoltage ) {
707 			theQueuePosition = DELAY_BACK; // back of delay queue
708 		}
709 	}
710 	return(myAdjustment);
711 }
712 
AdjustMaxNmosKey(CConnection & theConnections,voltage_t theSimGate,voltage_t theMaxSource,eventKey_t & theEventKey,queuePosition_t & theQueuePosition,bool theWarningFlag)713 string CCvcDb::AdjustMaxNmosKey(CConnection& theConnections, voltage_t theSimGate, voltage_t theMaxSource, eventKey_t& theEventKey, queuePosition_t& theQueuePosition,
714 		bool theWarningFlag) {
715 	theQueuePosition = DELAY_BACK; // default: back of delay queue
716 	string myAdjustment = "";
717 	// do not use sim on first pass
718 	voltage_t myGateVoltage = ( ! isFixedSimNet || theSimGate == UNKNOWN_VOLTAGE ) ? MaxVoltage(theConnections.gateId) : theSimGate;
719 	if ( myGateVoltage == UNKNOWN_VOLTAGE ) {
720 		if ( connectionCount_v[theConnections.gateId].SourceDrainCount() == 0 ) {
721 			if (theWarningFlag && ! (IsOneConnectionNet(theConnections.sourceId) || IsOneConnectionNet(theConnections.drainId)) ) {
722 				CInstance * myInstance_p = instancePtr_v[deviceParent_v[theConnections.deviceId]];
723 				string myUnknownKey = string(myInstance_p->master_p->name) + "/" + string(myInstance_p->master_p->devicePtr_v[theConnections.deviceId - myInstance_p->firstDeviceId]->name);
724 				if ( unknownGateSet.count(myUnknownKey) == 0 ) {
725 					reportFile << "WARNING: unknown max gate at net->device: " << NetName(theConnections.gateId) << " -> " <<
726 							HierarchyName(deviceParent_v[theConnections.deviceId], PRINT_CIRCUIT_ON) << "/" << theConnections.device_p->name << endl;
727 					unknownGateSet.insert(myUnknownKey);
728 				}
729 			}
730 			if ( theConnections.device_p->model_p->Vth > 0 ) {
731 				myAdjustment = " NMOS Vth drop " + PrintParameter(theEventKey, VOLTAGE_SCALE) + "-" + PrintParameter(theConnections.device_p->model_p->Vth, VOLTAGE_SCALE);
732 				theEventKey = theEventKey - theConnections.device_p->model_p->Vth;
733 			}
734 		} else {
735 			theQueuePosition = SKIP_QUEUE; // no enqueue with unknown gate in maxNmos
736 		}
737 	} else if ( myGateVoltage - theConnections.device_p->model_p->Vth <= theMaxSource ) {
738 		myAdjustment = " NMOS gate limited " + PrintParameter(myGateVoltage, VOLTAGE_SCALE) + "-" + PrintParameter(theConnections.device_p->model_p->Vth, VOLTAGE_SCALE);
739 		theEventKey = myGateVoltage - theConnections.device_p->model_p->Vth;
740 	} else if ( theEventKey != theMaxSource  ){
741 		myAdjustment = " NMOS limited to source " + PrintParameter(theMaxSource, VOLTAGE_SCALE);
742 		theEventKey = theMaxSource;
743 	}
744 	return(myAdjustment);
745 }
746 
AdjustMinNmosKey(CConnection & theConnections,netId_t theDrainId,voltage_t theMinSource,eventKey_t & theEventKey,queuePosition_t & theQueuePosition)747 string CCvcDb::AdjustMinNmosKey(CConnection& theConnections, netId_t theDrainId, voltage_t theMinSource, eventKey_t& theEventKey, queuePosition_t& theQueuePosition) {
748 	string myAdjustment = "";
749 	if ( theConnections.gateId == theDrainId ) {
750 		if ( theConnections.device_p->model_p->Vth > 0 ) {
751 			myAdjustment = " NMOS Vth drop " + PrintParameter(theEventKey, VOLTAGE_SCALE) + "+" + PrintParameter(theConnections.device_p->model_p->Vth, VOLTAGE_SCALE);
752 			theEventKey = theEventKey + theConnections.device_p->model_p->Vth;
753 		}
754 		theQueuePosition = MOS_DIODE; // mos diode
755 	} else {
756 		if ( connectionCount_v[theDrainId].sourceDrainType[PMOS] ) {
757 			theQueuePosition = DELAY_FRONT; // front of delay queue
758 		}
759 		if ( theConnections.bulkVoltage == UNKNOWN_VOLTAGE ) {
760 			theQueuePosition = DELAY_BACK; // back of delay queue
761 		} else if ( theMinSource < theConnections.bulkVoltage ) {
762 			theQueuePosition = DELAY_BACK; // back of delay queue
763 		}
764 	}
765 	return(myAdjustment);
766 }
767 
AdjustMinPmosKey(CConnection & theConnections,voltage_t theSimGate,voltage_t theMinSource,eventKey_t & theEventKey,queuePosition_t & theQueuePosition,bool theWarningFlag)768 string CCvcDb::AdjustMinPmosKey(CConnection& theConnections, voltage_t theSimGate, voltage_t theMinSource, eventKey_t& theEventKey, queuePosition_t& theQueuePosition,
769 		bool theWarningFlag) {
770 	theQueuePosition = DELAY_BACK; // default: back of delay queue
771 	string myAdjustment = "";
772 	// do not use sim on first pass
773 	voltage_t myGateVoltage = ( ! isFixedSimNet || theSimGate == UNKNOWN_VOLTAGE ) ? MinVoltage(theConnections.gateId) : theSimGate;
774 	if ( myGateVoltage == UNKNOWN_VOLTAGE ) {
775 		if ( connectionCount_v[theConnections.gateId].SourceDrainCount() == 0 ) {
776 			if (theWarningFlag && ! (IsOneConnectionNet(theConnections.sourceId) || IsOneConnectionNet(theConnections.drainId)) ) {
777 				CInstance * myInstance_p = instancePtr_v[deviceParent_v[theConnections.deviceId]];
778 				string myUnknownKey = string(myInstance_p->master_p->name) + "/" + string(myInstance_p->master_p->devicePtr_v[theConnections.deviceId - myInstance_p->firstDeviceId]->name);
779 				if ( unknownGateSet.count(myUnknownKey) == 0 ) {
780 					reportFile << "WARNING: unknown min gate at net->device: " << NetName(theConnections.gateId) << " -> " <<
781 							HierarchyName(deviceParent_v[theConnections.deviceId], PRINT_CIRCUIT_ON) << "/" << theConnections.device_p->name << endl;
782 					unknownGateSet.insert(myUnknownKey);
783 				}
784 			}
785 			if ( theConnections.device_p->model_p->Vth < 0 ) {
786 				myAdjustment = " PMOS Vth drop " + PrintParameter(theEventKey, VOLTAGE_SCALE) + "+" + PrintParameter(-theConnections.device_p->model_p->Vth, VOLTAGE_SCALE);
787 				theEventKey = theEventKey - theConnections.device_p->model_p->Vth;
788 			}
789 		} else {
790 			theQueuePosition = SKIP_QUEUE; // no enqueue with unknown gate in minPmos
791 		}
792 	} else if ( myGateVoltage - theConnections.device_p->model_p->Vth >= theMinSource ) {
793 		myAdjustment = " PMOS gate limited " + PrintParameter(myGateVoltage, VOLTAGE_SCALE) + "+" + PrintParameter(-theConnections.device_p->model_p->Vth, VOLTAGE_SCALE);
794 		theEventKey = myGateVoltage - theConnections.device_p->model_p->Vth;
795 	} else if ( theEventKey != theMinSource  ){
796 		myAdjustment = " PMOS limited to source " + PrintParameter(theMinSource, VOLTAGE_SCALE);
797 		theEventKey = theMinSource;
798 	}
799 	return(myAdjustment);
800 }
801 
AdjustKey(CEventQueue & theEventQueue,deviceId_t theDeviceId,CConnection & theConnections,eventKey_t & theEventKey,queuePosition_t & theQueuePosition,shortDirection_t theDirection,bool theWarningFlag)802 string CCvcDb::AdjustKey(CEventQueue& theEventQueue, deviceId_t theDeviceId, CConnection& theConnections, eventKey_t& theEventKey, queuePosition_t& theQueuePosition, shortDirection_t theDirection, bool theWarningFlag) {
803 	// MinMax queue Population+Propagation, Sim queue population only
804 	assert( (theConnections.sourceVoltage == UNKNOWN_VOLTAGE && theConnections.drainVoltage != UNKNOWN_VOLTAGE) \
805 			|| (theConnections.sourceVoltage != UNKNOWN_VOLTAGE && theConnections.drainVoltage == UNKNOWN_VOLTAGE) \
806 			|| (theEventQueue.queueType == SIM_QUEUE && theConnections.gateVoltage == UNKNOWN_VOLTAGE) );
807 	if ( deviceType_v[theDeviceId] == FUSE_ON || deviceType_v[theDeviceId] == FUSE_OFF ) {  // process fuses last
808 		theQueuePosition = DELAY_BACK;
809 	}
810 	if ( ! IsMos_(deviceType_v[theDeviceId]) ) return("");
811 	netId_t myLinkNetId;
812 	voltage_t myLinkVoltage;
813 	bool myIsCalculatedPower; // all SIM_QUEUE calculated power goes to delay queue
814 	bool myIsHiZPower;
815 	string myAdjustedVoltage = "";
816 	if ( theDirection == SOURCE_TO_MASTER_DRAIN ) { // propagate from drain
817 		myLinkNetId = theConnections.sourceId;
818 		myLinkVoltage = theConnections.drainVoltage;
819 		myIsCalculatedPower = theConnections.drainPower_p->type[SIM_CALCULATED_BIT];
820 		myIsHiZPower = theConnections.drainPower_p->type[HIZ_BIT];
821 		theQueuePosition = DefaultQueuePosition_(theConnections.drainPower_p->type[POWER_BIT], theEventQueue);
822 	} else {
823 		myLinkNetId = theConnections.drainId;
824 		myLinkVoltage = theConnections.sourceVoltage;
825 		myIsCalculatedPower = theConnections.sourcePower_p->type[SIM_CALCULATED_BIT];
826 		myIsHiZPower = theConnections.sourcePower_p->type[HIZ_BIT];
827 		theQueuePosition = DefaultQueuePosition_(theConnections.sourcePower_p->type[POWER_BIT], theEventQueue);
828 	}
829 	if ( theEventQueue.queueType == MAX_QUEUE ) {
830 		if ( IsPmos_(deviceType_v[theDeviceId]) ) {
831 			if ( leakVoltageSet && myIsHiZPower ) { // no voltage change for HiZ nets in second min/max, high priority
832 				theQueuePosition = QUEUE_HIZ;
833 			} else {
834 				myAdjustedVoltage = AdjustMaxPmosKey(theConnections, myLinkNetId, myLinkVoltage, theEventKey, theQueuePosition);
835 			}
836 		} else { // NMOS
837 			if ( leakVoltageSet && myIsHiZPower ) { // no voltage change for HiZ nets in second min/max
838 				theQueuePosition = DELAY_BACK;
839 			} else {
840 				myAdjustedVoltage = AdjustMaxNmosKey(theConnections, SimVoltage(theConnections.gateId), myLinkVoltage, theEventKey, theQueuePosition, theWarningFlag);
841 			}
842 		}
843 	} else if ( theEventQueue.queueType == MIN_QUEUE ) {
844 		if ( IsNmos_(deviceType_v[theDeviceId]) ) {
845 			if ( leakVoltageSet && myIsHiZPower ) { // no voltage change for HiZ nets in second min/max, high priority
846 				theQueuePosition = QUEUE_HIZ;
847 			} else {
848 				myAdjustedVoltage = AdjustMinNmosKey(theConnections, myLinkNetId, myLinkVoltage, theEventKey, theQueuePosition);
849 			}
850 		} else { // PMOS
851 			if ( leakVoltageSet && myIsHiZPower ) { // no voltage change for HiZ nets in second min/max
852 				theQueuePosition = DELAY_BACK;
853 			} else {
854 				myAdjustedVoltage = AdjustMinPmosKey(theConnections, SimVoltage(theConnections.gateId), myLinkVoltage, theEventKey, theQueuePosition, theWarningFlag);
855 			}
856 		}
857 	} else if ( theEventQueue.queueType == SIM_QUEUE ) {
858 		//theEventKey = SimKey(theEventQueue.QueueTime(), theConnections.resistance);  // Sim Key is adjusted in calling routine
859 		if ( theConnections.gateId == theConnections.sourceId || theConnections.gateId == theConnections.drainId ) {
860 			theQueuePosition = DELAY_FRONT;
861 		} else if ( theConnections.gateVoltage == UNKNOWN_VOLTAGE ) { // check always on
862 			voltage_t myMinGateVoltage = MinVoltage(theConnections.gateId);
863 			voltage_t myMaxGateVoltage = MaxVoltage(theConnections.gateId);
864 			if ( IsNmos_(deviceType_v[theDeviceId]) && myMinGateVoltage != UNKNOWN_VOLTAGE
865 					&& myMinGateVoltage > myLinkVoltage + theConnections.device_p->model_p->Vth ) {
866 				; // always on. default delay
867 			} else if ( IsPmos_(deviceType_v[theDeviceId]) && myMaxGateVoltage != UNKNOWN_VOLTAGE
868 					&& myMaxGateVoltage < myLinkVoltage + theConnections.device_p->model_p->Vth ) {
869 				; // always on. default delay
870 			} else { // skip
871 				theQueuePosition = SKIP_QUEUE;
872 			}
873 		} else if ( IsNmos_(deviceType_v[theDeviceId]) && theConnections.gateVoltage < myLinkVoltage + theConnections.device_p->model_p->Vth ) { // off devices delayed
874 			theQueuePosition = DELAY_FRONT;
875 		} else if ( IsPmos_(deviceType_v[theDeviceId]) && theConnections.gateVoltage > myLinkVoltage + theConnections.device_p->model_p->Vth ) { // off devices delayed
876 			theQueuePosition = DELAY_FRONT;
877 		} else if ( myIsCalculatedPower ) {
878 			theQueuePosition = DELAY_FRONT;
879 		}
880 	}
881 	return(myAdjustedVoltage);
882 }
883 
AdjustSimVoltage(CEventQueue & theEventQueue,deviceId_t theDeviceId,CConnection & theConnections,voltage_t & theVoltage,shortDirection_t theDirection,propagation_t thePropagationType)884 string CCvcDb::AdjustSimVoltage(CEventQueue& theEventQueue, deviceId_t theDeviceId, CConnection& theConnections, voltage_t& theVoltage, shortDirection_t theDirection,
885 		propagation_t thePropagationType) {
886 	assert( (theConnections.sourceVoltage == UNKNOWN_VOLTAGE && theConnections.drainVoltage != UNKNOWN_VOLTAGE)
887 			|| (theConnections.sourceVoltage != UNKNOWN_VOLTAGE && theConnections.drainVoltage == UNKNOWN_VOLTAGE) );
888 	CPower * myPower_p = ( theDirection == SOURCE_TO_MASTER_DRAIN ) ? theConnections.sourcePower_p : theConnections.drainPower_p;
889 	netId_t myTargetNet = ( theDirection == SOURCE_TO_MASTER_DRAIN ) ? theConnections.sourceId : theConnections.drainId;
890 	resistance_t mySourceResistance = ( theDirection == SOURCE_TO_MASTER_DRAIN ) ? theConnections.masterDrainNet.finalResistance : theConnections.masterSourceNet.finalResistance;
891 
892 	voltage_t myMinTargetVoltage = MinSimVoltage(myTargetNet);
893 	voltage_t myMaxTargetVoltage = MaxSimVoltage(myTargetNet);
894 	resistance_t myMinTargetResistance = MinResistance(myTargetNet);
895 	resistance_t myMaxTargetResistance = MaxResistance(myTargetNet);
896 	voltage_t myOriginalVoltage = theVoltage;
897 	if ( myMinTargetVoltage != UNKNOWN_VOLTAGE && myMinTargetVoltage > myMaxTargetVoltage) {
898 		voltage_t myTrueMinVoltage = myMaxTargetVoltage;
899 		resistance_t myTrueMinResistance = myMaxTargetResistance;
900 		myMaxTargetVoltage = myMinTargetVoltage;
901 		myMaxTargetResistance = myMinTargetResistance;
902 		myMinTargetVoltage = myTrueMinVoltage;
903 		myMinTargetResistance = myTrueMinResistance;
904 	}
905 	string myCalculation = "";
906 	if ( IsMos_(deviceType_v[theDeviceId]) ) {
907 		if ( theConnections.gateId == myTargetNet ) { // mos as diodes
908 			if ( myMinTargetVoltage == myMaxTargetVoltage && ( myPower_p && ! myPower_p->type[HIZ_BIT] ) ) { //may cause problem in nets not directly connected to power
909 				// only propagate if min = max
910 				myCalculation = " MOS sim drop " + PrintParameter(theVoltage, VOLTAGE_SCALE) + "V->" + PrintParameter(myMaxTargetVoltage, VOLTAGE_SCALE) + "V";
911 				theVoltage = myMaxTargetVoltage;
912 			} else {
913 				theVoltage = UNKNOWN_VOLTAGE;
914 			}
915 		} else {
916 			if ( theConnections.gateVoltage == UNKNOWN_VOLTAGE ) {
917 				voltage_t myMinGateVoltage = MinVoltage(theConnections.gateId);
918 				voltage_t myMaxGateVoltage = MaxVoltage(theConnections.gateId);
919 				if ( IsNmos_(deviceType_v[theDeviceId]) && myMinGateVoltage != UNKNOWN_VOLTAGE
920 						&& myMinGateVoltage > theVoltage + theConnections.device_p->model_p->Vth ) {
921 					theConnections.gateVoltage = myMinGateVoltage; // always on
922 				} else if ( IsPmos_(deviceType_v[theDeviceId]) && myMaxGateVoltage != UNKNOWN_VOLTAGE
923 						&& myMaxGateVoltage < theVoltage + theConnections.device_p->model_p->Vth ) {
924 					theConnections.gateVoltage = myMaxGateVoltage; // always on
925 				}
926 			}
927 			assert(theConnections.gateVoltage != UNKNOWN_VOLTAGE);
928 			if ( theConnections.gateVoltage == theVoltage + theConnections.device_p->model_p->Vth ) {
929 				theVoltage = UNKNOWN_VOLTAGE; // skip simulation propagation
930 			} else if ( IsNmos_(deviceType_v[theDeviceId]) && myMinTargetVoltage != UNKNOWN_VOLTAGE ) {
931 				voltage_t myGateStepDown = theConnections.gateVoltage - theConnections.device_p->model_p->Vth;
932 				if ( myPower_p && myPower_p->type[HIZ_BIT] ) {
933 					;  // Don't adjust open voltages
934 				} else if ( myGateStepDown < theVoltage ) {
935 					myCalculation = " NMOS sim Vth drop " + PrintParameter(theConnections.gateVoltage, VOLTAGE_SCALE) + "-" + PrintParameter(theConnections.device_p->model_p->Vth, VOLTAGE_SCALE);
936 					myCalculation += " limited by " + PrintParameter(myMinTargetVoltage, VOLTAGE_SCALE);
937 					theVoltage = max(myGateStepDown, myMinTargetVoltage);
938 				}
939 			} else if ( IsPmos_(deviceType_v[theDeviceId]) && myMaxTargetVoltage != UNKNOWN_VOLTAGE) {
940 				voltage_t myGateStepUp = theConnections.gateVoltage - theConnections.device_p->model_p->Vth;
941 				if ( myPower_p && myPower_p->type[HIZ_BIT] ) {
942 					;  // Don't adjust open voltages
943 				} else if ( myGateStepUp > theVoltage ) {
944 					myCalculation = " PMOS sim Vth drop " + PrintParameter(theConnections.gateVoltage, VOLTAGE_SCALE) + "+" + PrintParameter(-theConnections.device_p->model_p->Vth, VOLTAGE_SCALE);
945 					myCalculation += " limited by " + PrintParameter(myMaxTargetVoltage, VOLTAGE_SCALE);
946 					theVoltage = min(myGateStepUp, myMaxTargetVoltage);
947 				}
948 			}
949 		}
950 	}
951 	if ( theVoltage == UNKNOWN_VOLTAGE ) return("");
952 	if ( myMinTargetVoltage != UNKNOWN_VOLTAGE && theVoltage < myMinTargetVoltage ) {
953 		myCalculation = " Limited sim to min" + myCalculation;
954 		debugFile << myCalculation << " " << NetName(myTargetNet) << endl;
955 		if ( thePropagationType != POWER_NETS_ONLY && myOriginalVoltage < myMinTargetVoltage
956 				&& theConnections.EstimatedCurrent(theVoltage, myMinTargetVoltage, mySourceResistance, myMinTargetResistance) > cvcParameters.cvcLeakLimit ) {
957 			ReportSimShort(theDeviceId, theVoltage, myMinTargetVoltage, myCalculation);
958 		}
959 		// voltage drops in first pass are skipped, only report original voltage limits
960 		theVoltage = myMinTargetVoltage;
961 	}
962 	if ( myMaxTargetVoltage != UNKNOWN_VOLTAGE && theVoltage > myMaxTargetVoltage ) {
963 		myCalculation = " Limited sim to max" + myCalculation;
964 		debugFile << myCalculation << " " << NetName(myTargetNet) << endl;
965 		if ( thePropagationType != POWER_NETS_ONLY && myOriginalVoltage > myMaxTargetVoltage
966 				&& theConnections.EstimatedCurrent(theVoltage, myMaxTargetVoltage, mySourceResistance, myMaxTargetResistance) > cvcParameters.cvcLeakLimit ) {
967 			ReportSimShort(theDeviceId, theVoltage, myMaxTargetVoltage, myCalculation);
968 		}
969 		// voltage drops in first pass are skipped, only report original voltage limits
970 		theVoltage = myMaxTargetVoltage;
971 	}
972 	return(myCalculation);
973 }
974 
EnqueueAttachedDevicesByTerminal(CEventQueue & theEventQueue,netId_t theNetId,CDeviceIdVector & theFirstDevice_v,CDeviceIdVector & theNextDevice_v,eventKey_t theEventKey)975 void CCvcDb::EnqueueAttachedDevicesByTerminal(CEventQueue& theEventQueue, netId_t theNetId, CDeviceIdVector& theFirstDevice_v, CDeviceIdVector& theNextDevice_v, eventKey_t theEventKey) {
976 	// TODO: possibly remove inactive devices from connection lists
977 	if ( theFirstDevice_v[theNetId] == UNKNOWN_DEVICE ) return;
978 	static CConnection myConnections;
979 	queuePosition_t myQueuePosition;
980 	eventKey_t myEventKey;
981 	string myAdjustedCalculation;
982 	int myGateBiasCount = 0;
983 	calculationType_t myCalculationType = UNKNOWN_CALCULATION;
984 	for (deviceId_t device_it = theFirstDevice_v[theNetId]; device_it != UNKNOWN_DEVICE; device_it = theNextDevice_v[device_it]) {
985 		if ( deviceStatus_v[device_it][theEventQueue.inactiveBit] || deviceStatus_v[device_it][theEventQueue.pendingBit] ) {
986 			continue; // skip inactive and pending devices
987 		} else {
988 			MapDeviceNets(device_it, theEventQueue, myConnections);
989 			if ( IsIrrelevant(theEventQueue, device_it, myConnections, theEventKey, ENQUEUE) ) {
990 				deviceStatus_v[device_it][theEventQueue.inactiveBit] = true;
991 			} else if ( myConnections.sourceVoltage == UNKNOWN_VOLTAGE && myConnections.drainVoltage == UNKNOWN_VOLTAGE ) { // ignore bias/gate only changes
992 				myGateBiasCount++;
993 			} else {
994 				myEventKey = theEventKey;
995 				if ( myConnections.sourceVoltage == UNKNOWN_VOLTAGE || myConnections.drainVoltage == UNKNOWN_VOLTAGE ) { // Adjust key for non-shorts
996 					shortDirection_t myDirection;
997 					if ( myConnections.sourceVoltage == UNKNOWN_VOLTAGE ) {
998 						myDirection = SOURCE_TO_MASTER_DRAIN;
999 						myQueuePosition = DefaultQueuePosition_(myConnections.drainPower_p->type[POWER_BIT], theEventQueue);
1000 						myCalculationType = GetCalculationType(myConnections.drainPower_p, theEventQueue.queueType);
1001 					} else {
1002 						myDirection = DRAIN_TO_MASTER_SOURCE;
1003 						myQueuePosition = DefaultQueuePosition_(myConnections.sourcePower_p->type[POWER_BIT], theEventQueue);
1004 						myCalculationType = GetCalculationType(myConnections.sourcePower_p, theEventQueue.queueType);
1005 					}
1006 					myAdjustedCalculation = AdjustKey(theEventQueue, device_it, myConnections, myEventKey, myQueuePosition, myDirection, IGNORE_WARNINGS);
1007 					// sets myQueuePosition, myEventKey
1008 				} else {
1009 					myQueuePosition = DefaultQueuePosition_(myConnections.sourcePower_p->type[POWER_BIT] || myConnections.drainPower_p->type[POWER_BIT], theEventQueue);
1010 				}
1011 				if ( myQueuePosition == SKIP_QUEUE ) continue; // SIM queues/maxNmos/minPmos with unknown mos gate return SKIP_QUEUE, skip for now
1012 				if ( myEventKey < theEventKey && myCalculationType == UP_CALCULATION ) {
1013 					debugFile << "DEBUG: Skipped down propagation at " << DeviceName(myConnections.deviceId);
1014 					debugFile << " voltage " << PrintVoltage(myEventKey) << "(" << myAdjustedCalculation << ") from " << PrintVoltage(theEventKey) << endl;
1015 					continue;  // do not propagate opposite calculations
1016 				}
1017 				if ( myEventKey > theEventKey && myCalculationType == DOWN_CALCULATION ) {
1018 					debugFile << "DEBUG: Skipped up propagation at " << DeviceName(myConnections.deviceId);
1019 					debugFile << " voltage " << PrintVoltage(myEventKey) << "(" << myAdjustedCalculation << ") from " << PrintVoltage(theEventKey) << endl;
1020 					continue;  // do not propagate opposite calculations
1021 				}
1022 				if ( theEventQueue.queueType == SIM_QUEUE ) {
1023 					myEventKey = SimKey(theEventQueue.QueueTime(), myConnections.resistance);
1024 				}
1025 				theEventQueue.AddEvent(myEventKey, device_it, myQueuePosition);
1026 				deviceStatus_v[device_it][theEventQueue.pendingBit] = true;
1027 				if ( myQueuePosition == MOS_DIODE && theEventQueue.queueType != SIM_QUEUE
1028 						&& ! (myConnections.gatePower_p && myConnections.gatePower_p->type[HIZ_BIT]) ) { // mos diode connections in min/max queues
1029 					netId_t myDrainNetId, mySourceNetId;
1030 					voltage_t myMinSourceVoltage, myMaxSourceVoltage;
1031 					voltage_t myMinDrainVoltage, myMaxDrainVoltage;
1032 					if ( myConnections.sourceVoltage == UNKNOWN_VOLTAGE ) {
1033 						assert ( myConnections.drainVoltage != UNKNOWN_VOLTAGE );
1034 						myDrainNetId = myConnections.sourceId;
1035 						mySourceNetId = myConnections.drainId;
1036 					} else if ( myConnections.drainVoltage == UNKNOWN_VOLTAGE ) {
1037 						myDrainNetId = myConnections.drainId;
1038 						mySourceNetId = myConnections.sourceId;
1039 					} else {
1040 						throw EDatabaseError("EnqueueAttachedDevicesByTerminal: " + DeviceName(device_it));
1041 					}
1042 					myMinSourceVoltage = MinVoltage(mySourceNetId);
1043 					myMaxSourceVoltage = MaxVoltage(mySourceNetId);
1044 					myMinDrainVoltage = MinVoltage(myDrainNetId);
1045 					myMaxDrainVoltage = MaxVoltage(myDrainNetId);
1046 					if ( theEventQueue.queueType == MAX_QUEUE && myMinSourceVoltage == theEventKey ) { // set MIN voltage too
1047 						// theEventKey = before drop, myEventKey = after drop
1048 						voltage_t myMinLeakVoltage = MinLeakVoltage(myDrainNetId);
1049 						if ( myMinDrainVoltage == UNKNOWN_VOLTAGE ) {
1050 							netVoltagePtr_v.CalculatePower(minEventQueue, myEventKey, myDrainNetId, mySourceNetId, this, myAdjustedCalculation);
1051 							netVoltagePtr_v[myDrainNetId].full->type[ANALOG_BIT] = true;
1052 							if ( gDebug_cvc ) cout << "DEBUG: Calculated power at net: " << myDrainNetId << " MIN " << myEventKey << endl;
1053 							// do not increment lastUpdate
1054 							minNet_v.Set(myDrainNetId, myDrainNetId, parameterResistanceMap[myConnections.device_p->parameters] * 100, minNet_v.lastUpdate);
1055 							CheckResistorOverflow_(minNet_v[myDrainNetId].finalResistance, myDrainNetId, logFile);
1056 							if ( leakVoltageSet && myMinLeakVoltage != UNKNOWN_VOLTAGE && myMinLeakVoltage <= myEventKey ) continue;
1057 							assert(netVoltagePtr_v[myDrainNetId].full);
1058 							if ( netVoltagePtr_v[myDrainNetId].full->pullDownVoltage() != UNKNOWN_VOLTAGE && netVoltagePtr_v[myDrainNetId].full->pullDownVoltage() <= myEventKey ) continue;
1059 							// pull down not known
1060 							netStatus_v[myDrainNetId][NEEDS_MIN_CONNECTION] = true;
1061 							if ( gDebug_cvc ) cout << "DEBUG: min estimate net: " << myDrainNetId << endl;
1062 							if ( netStatus_v[mySourceNetId][NEEDS_MIN_CONNECTION] == true ) {
1063 								if ( gDebug_cvc ) cout << "DEBUG: min estimate dependency net: " << mySourceNetId << endl;
1064 								minConnectionDependencyMap[mySourceNetId].push_front(myDrainNetId);
1065 							}
1066 							// calculated power only
1067 						} else {
1068 							if ( myMinDrainVoltage < myEventKey ) {
1069 								reportFile << "WARNING: Min voltage already set for " << NetName(myDrainNetId, PRINT_CIRCUIT_ON, PRINT_HIERARCHY_OFF);
1070 								reportFile << " at " << DeviceName(myConnections.deviceId, PRINT_CIRCUIT_ON)  << " expected/found " << myEventKey << "/" << myMinDrainVoltage << endl;
1071 								netStatus_v[myDrainNetId][NEEDS_MIN_CONNECTION] = false;
1072 								netStatus_v[mySourceNetId][NEEDS_MIN_CONNECTION] = false; // reset parent also
1073 							}
1074 						}
1075 					} else if ( theEventQueue.queueType == MIN_QUEUE && myMaxSourceVoltage == theEventKey ) { // set MAX voltage too
1076 						voltage_t myMaxLeakVoltage = MaxLeakVoltage(myDrainNetId);
1077 						if ( myMaxDrainVoltage == UNKNOWN_VOLTAGE ) {
1078 							netVoltagePtr_v.CalculatePower(maxEventQueue, myEventKey, myDrainNetId, mySourceNetId, this, myAdjustedCalculation);
1079 							netVoltagePtr_v[myDrainNetId].full->type[ANALOG_BIT] = true;
1080 							if ( gDebug_cvc ) cout << "DEBUG: Calculated power at net: " << myDrainNetId << " MAX " << myEventKey << endl;
1081 							// do not increment lastUpdate
1082 							maxNet_v.Set(myDrainNetId, myDrainNetId, parameterResistanceMap[myConnections.device_p->parameters] * 100, maxNet_v.lastUpdate);
1083 							CheckResistorOverflow_(maxNet_v[myDrainNetId].finalResistance, myDrainNetId, logFile);
1084 							if ( leakVoltageSet && myMaxLeakVoltage != UNKNOWN_VOLTAGE && myMaxLeakVoltage >= myEventKey ) continue;
1085 							assert(netVoltagePtr_v[myDrainNetId].full);
1086 							if ( netVoltagePtr_v[myDrainNetId].full->pullUpVoltage() != UNKNOWN_VOLTAGE && netVoltagePtr_v[myDrainNetId].full->pullUpVoltage() >= myEventKey ) continue;
1087 							// pull up not known
1088 							netStatus_v[myDrainNetId][NEEDS_MAX_CONNECTION] = true;
1089 							if ( gDebug_cvc ) cout << "DEBUG: max estimate net: " << myDrainNetId << endl;
1090 							if ( netStatus_v[mySourceNetId][NEEDS_MAX_CONNECTION] == true ) {
1091 								if ( gDebug_cvc ) cout << "DEBUG: max estimate dependency net: " << mySourceNetId << endl;
1092 								maxConnectionDependencyMap[mySourceNetId].push_front(myDrainNetId);
1093 							}
1094 							// calculated power only
1095 						} else {
1096 							if ( myMaxDrainVoltage > myEventKey ) {
1097 								reportFile << "WARNING: Max voltage already set for " << NetName(myDrainNetId, PRINT_CIRCUIT_ON, PRINT_HIERARCHY_OFF);
1098 								reportFile << " at " << DeviceName(myConnections.deviceId, PRINT_CIRCUIT_ON)  << " expected/found " << myEventKey << "/" << myMaxDrainVoltage << endl;
1099 								netStatus_v[myDrainNetId][NEEDS_MAX_CONNECTION] = false;
1100 								netStatus_v[mySourceNetId][NEEDS_MAX_CONNECTION] = false; // reset parent also
1101 							}
1102 						}
1103 					}
1104 				}
1105 			}
1106 		}
1107 	}
1108 	if ( myGateBiasCount > 10000 && theEventQueue.queueType != SIM_QUEUE ) {
1109 		reportFile << "WARNING: large non-power gate/bias net " << NetName(theNetId) << " at " << DeviceName(theFirstDevice_v[theNetId]) << endl;
1110 	}
1111 }
1112 
EnqueueAttachedDevices(CEventQueue & theEventQueue,netId_t theNetId,eventKey_t theEventKey)1113 void CCvcDb::EnqueueAttachedDevices(CEventQueue& theEventQueue, netId_t theNetId, eventKey_t theEventKey) {
1114 	EnqueueAttachedDevicesByTerminal(theEventQueue, theNetId, firstSource_v, nextSource_v, theEventKey);
1115 	EnqueueAttachedDevicesByTerminal(theEventQueue, theNetId, firstDrain_v, nextDrain_v, theEventKey);
1116 //	EnqueueAttachedDevicesByTerminal(theEventQueue, theNetId, firstBulk_v, nextBulk_v, theEventKey);
1117 	EnqueueAttachedDevicesByTerminal(theEventQueue, theNetId, firstGate_v, nextGate_v, theEventKey);
1118 }
1119 
EnqueueAttachedResistorsByTerminal(CEventQueue & theEventQueue,netId_t theNetId,CDeviceIdVector & theFirstDevice_v,CDeviceIdVector & theNextDevice_v,eventKey_t theEventKey,queuePosition_t theQueuePosition)1120 void CCvcDb::EnqueueAttachedResistorsByTerminal(CEventQueue& theEventQueue, netId_t theNetId, CDeviceIdVector& theFirstDevice_v, CDeviceIdVector& theNextDevice_v, eventKey_t theEventKey, queuePosition_t theQueuePosition) {
1121 	// TODO: possibly remove inactive devices from connection lists
1122 	for (deviceId_t device_it = theFirstDevice_v[theNetId]; device_it != UNKNOWN_DEVICE; device_it = theNextDevice_v[device_it]) {
1123 		if ( deviceType_v[device_it] == RESISTOR ) {
1124 			if ( deviceStatus_v[device_it][theEventQueue.inactiveBit] || deviceStatus_v[device_it][theEventQueue.pendingBit] ) {
1125 				continue; // skip inactive and pending devices
1126 			} else {
1127 				theEventQueue.AddEvent(theEventKey, device_it, theQueuePosition);
1128 				deviceStatus_v[device_it][theEventQueue.pendingBit] = true;
1129 			}
1130 		}
1131 	}
1132 }
1133 
EnqueueAttachedResistors(CEventQueue & theEventQueue,netId_t theNetId,eventKey_t theEventKey,queuePosition_t theQueuePosition)1134 void CCvcDb::EnqueueAttachedResistors(CEventQueue& theEventQueue, netId_t theNetId, eventKey_t theEventKey, queuePosition_t theQueuePosition) {
1135 	EnqueueAttachedResistorsByTerminal(theEventQueue, theNetId, firstSource_v, nextSource_v, theEventKey, theQueuePosition);
1136 	EnqueueAttachedResistorsByTerminal(theEventQueue, theNetId, firstDrain_v, nextDrain_v, theEventKey, theQueuePosition);
1137 }
1138 
ShiftVirtualNets(CEventQueue & theEventQueue,netId_t theNewNetId,CVirtualNet & theLastVirtualNet,resistance_t theSourceResistance,resistance_t theDrainResistance)1139 void CCvcDb::ShiftVirtualNets(CEventQueue& theEventQueue, netId_t theNewNetId, CVirtualNet& theLastVirtualNet, resistance_t theSourceResistance, resistance_t theDrainResistance) {
1140 	netId_t myNetId;
1141 	resistance_t myNewResistance;
1142 	int myShiftCount = 0;
1143 	while ( long(theSourceResistance) + theLastVirtualNet.resistance < long(theDrainResistance) - theLastVirtualNet.resistance ) {
1144 		if ( myShiftCount++ > 10000 ) {
1145 			cout << "ERROR: exceeded shift limit for net# " << theNewNetId << endl;
1146 			cout << "	name: " << NetName(theNewNetId) << endl;
1147 			cout << "	next net is " << theEventQueue.virtualNet_v[theNewNetId].nextNetId << endl;
1148 			assert(myShiftCount < 10000 );
1149 		}
1150 		if (gDebug_cvc) cout << gEventQueueTypeMap[theEventQueue.queueType] << " Shifted Net " << theNewNetId << endl;
1151 		assert(long(theSourceResistance) + theLastVirtualNet.resistance < MAX_RESISTANCE);
1152 		theSourceResistance += theLastVirtualNet.resistance;
1153 		assert(theDrainResistance >= theLastVirtualNet.resistance);
1154 		theDrainResistance -= theLastVirtualNet.resistance;
1155 		myNetId = theLastVirtualNet.nextNetId;
1156 		myNewResistance = theLastVirtualNet.resistance;
1157 		theLastVirtualNet(theEventQueue.virtualNet_v, myNetId);
1158 		if ( theEventQueue.virtualNet_v[myNetId].finalResistance != theDrainResistance ) {
1159 			cout << "Shift: unexpected drain resistance at net " << myNetId
1160 					<< " found " << theEventQueue.virtualNet_v[myNetId].finalResistance << " expected " << theDrainResistance << endl;
1161 		}
1162 		theEventQueue.virtualNet_v.Set(myNetId, theNewNetId, myNewResistance, ++theEventQueue.virtualNet_v.lastUpdate);
1163 		if ( theEventQueue.virtualNet_v[myNetId].finalResistance != theSourceResistance ) {
1164 			cout << "Shift: unexpected source resistance at net " << myNetId
1165 					<< " found " << theEventQueue.virtualNet_v[myNetId].finalResistance << " expected " << theSourceResistance << endl;
1166 		}
1167 		CheckResistorOverflow_(theEventQueue.virtualNet_v[myNetId].finalResistance, myNetId, logFile);
1168 		theNewNetId = myNetId;
1169 	}
1170 }
1171 
RecalculateFinalResistance(CEventQueue & theEventQueue,netId_t theNetId,bool theRecursingFlag)1172 void CCvcDb::RecalculateFinalResistance(CEventQueue& theEventQueue, netId_t theNetId, bool theRecursingFlag) {
1173 	netId_t mySourceId, myDrainId;
1174 	CConnection myConnections;
1175 	CDevice myDevice;
1176 	static unordered_set<netId_t> myProccessedNets;
1177 	if ( ! theRecursingFlag ) {
1178 		myProccessedNets.clear();
1179 	}
1180 	myProccessedNets.insert(theNetId);
1181 	netId_t mySearchNetId = theNetId;
1182 	while ( theEventQueue.virtualNet_v[mySearchNetId].nextNetId != mySearchNetId && theEventQueue.virtualNet_v[mySearchNetId].resistance == 0 ) {
1183 		// find the master net for non-conducting resistors
1184 		mySearchNetId = theEventQueue.virtualNet_v[mySearchNetId].nextNetId;
1185 	}
1186 	for (deviceId_t device_it = firstSource_v[mySearchNetId]; device_it != UNKNOWN_DEVICE; device_it = nextSource_v[device_it]) {
1187 		if ( deviceStatus_v[device_it][theEventQueue.inactiveBit] ) { // only process shorted nets
1188 			SetDeviceNets(device_it, &myDevice, myConnections.sourceId, myConnections.gateId, myConnections.drainId, myConnections.bulkId);
1189 			if ( myConnections.sourceId != theNetId ) continue; // skip devices that aren't connected to the net we want
1190 			myDrainId = myConnections.drainId;
1191 			if ( theNetId == theEventQueue.virtualNet_v[myDrainId].nextNetId ) { // only process nets that need to be recalculated
1192 				theEventQueue.virtualNet_v.Set(myDrainId, theNetId, theEventQueue.virtualNet_v[myDrainId].resistance, ++theEventQueue.virtualNet_v.lastUpdate);
1193 				CheckResistorOverflow_(theEventQueue.virtualNet_v[myDrainId].finalResistance, myDrainId, logFile);
1194 			}
1195 		}
1196 	}
1197 	for (deviceId_t device_it = firstDrain_v[mySearchNetId]; device_it != UNKNOWN_DEVICE; device_it = nextDrain_v[device_it]) {
1198 		if ( deviceStatus_v[device_it][theEventQueue.inactiveBit] ) { // only process shorted nets (process source but not drain)
1199 			SetDeviceNets(device_it, &myDevice, myConnections.sourceId, myConnections.gateId, myConnections.drainId, myConnections.bulkId);
1200 			if ( myConnections.drainId != theNetId ) continue; // skip devices that aren't connected to the net we want
1201 			mySourceId = myConnections.sourceId;
1202 			if ( theNetId == theEventQueue.virtualNet_v[mySourceId].nextNetId ) { // only process nets that need to be recalculated
1203 				theEventQueue.virtualNet_v.Set(mySourceId, theNetId, theEventQueue.virtualNet_v[mySourceId].resistance, ++theEventQueue.virtualNet_v.lastUpdate);
1204 				CheckResistorOverflow_(theEventQueue.virtualNet_v[mySourceId].finalResistance, mySourceId, logFile);
1205 			}
1206 		}
1207 	}
1208 }
1209 
ShortNets(CEventQueue & theEventQueue,deviceId_t theDeviceId,CConnection & theConnections,shortDirection_t theDirection)1210 void CCvcDb::ShortNets(CEventQueue& theEventQueue, deviceId_t theDeviceId, CConnection& theConnections, shortDirection_t theDirection) {
1211 	if ( theDirection == DRAIN_TO_MASTER_SOURCE ) {
1212 		// do not increment lastUpdate (increment in calling routine if necessary)
1213 		theEventQueue.virtualNet_v.Set(theConnections.drainId, theConnections.sourceId, parameterResistanceMap[theConnections.device_p->parameters], theEventQueue.virtualNet_v.lastUpdate);
1214 		CheckResistorOverflow_(theEventQueue.virtualNet_v[theConnections.drainId].finalResistance, theConnections.drainId, logFile);
1215 		if ( deviceType_v[theDeviceId] == RESISTOR ) {
1216 			PropagateConnectionType(theEventQueue.virtualNet_v, connectionCount_v[theConnections.drainId].sourceDrainType, theConnections.sourceId);
1217 		}
1218 	} else if ( theDirection == SOURCE_TO_MASTER_DRAIN ) {
1219 		// do not increment lastUpdate (increment in calling routine if necessary)
1220 		theEventQueue.virtualNet_v.Set(theConnections.sourceId, theConnections.drainId, parameterResistanceMap[theConnections.device_p->parameters], theEventQueue.virtualNet_v.lastUpdate);
1221 		CheckResistorOverflow_(theEventQueue.virtualNet_v[theConnections.sourceId].finalResistance, theConnections.sourceId, logFile);
1222 		if ( deviceType_v[theDeviceId] == RESISTOR ) {
1223 			PropagateConnectionType(theEventQueue.virtualNet_v, connectionCount_v[theConnections.sourceId].sourceDrainType, theConnections.drainId);
1224 		}
1225 	} else {
1226 		throw EDatabaseError("ShortNets: " + DeviceName(theDeviceId));
1227 	}
1228 	deviceStatus_v[theDeviceId][theEventQueue.inactiveBit] = true;
1229 }
1230 
ShortNets(CEventQueue & theEventQueue,deviceId_t theDeviceId,CConnection & theConnections,shortDirection_t theDirection,voltage_t theShortVoltage,string theCalculation)1231 void CCvcDb::ShortNets(CEventQueue& theEventQueue, deviceId_t theDeviceId, CConnection& theConnections, shortDirection_t theDirection, voltage_t theShortVoltage, string theCalculation) {
1232 	// for min/max queues.
1233 	netId_t myMasterNet, mySlaveNet;
1234 	voltage_t myMasterVoltage;
1235 	voltage_t mySimVoltage;
1236 	if ( theDirection == DRAIN_TO_MASTER_SOURCE ) {
1237 		myMasterNet = theConnections.sourceId;
1238 		mySlaveNet = theConnections.drainId;
1239 		myMasterVoltage = theConnections.sourceVoltage;
1240 	} else if ( theDirection == SOURCE_TO_MASTER_DRAIN ) {
1241 		myMasterNet = theConnections.drainId;
1242 		mySlaveNet = theConnections.sourceId;
1243 		myMasterVoltage = theConnections.drainVoltage;
1244 	} else {
1245 		throw EDatabaseError("ShortNets " + DeviceName(theDeviceId));
1246 	}
1247 	if ( isFixedSimNet ) {
1248 		mySimVoltage = SimVoltage(mySlaveNet);
1249 		if ( theEventQueue.queueType == MIN_QUEUE ) {
1250 			if ( mySimVoltage != UNKNOWN_VOLTAGE && theShortVoltage > mySimVoltage ) {
1251 				if (gDebug_cvc) cout << "DEBUG: min > sim (" << theShortVoltage << ">" << mySimVoltage << ")" << endl;
1252 				theShortVoltage = mySimVoltage;
1253 				theCalculation = " Limited min to sim";
1254 			}
1255 		} else if ( theEventQueue.queueType == MAX_QUEUE ) {
1256 			if ( mySimVoltage != UNKNOWN_VOLTAGE && theShortVoltage < mySimVoltage ) {
1257 				if (gDebug_cvc) cout << "DEBUG: max < sim (" << theShortVoltage << "<" << mySimVoltage << ")" << endl;
1258 				theShortVoltage = mySimVoltage;
1259 				theCalculation = " Limited max to sim";
1260 			}
1261 		}
1262 	}
1263 	if ( theShortVoltage == myMasterVoltage ) {
1264 		// do not increment lastUpdate (increment in calling routine if necessary)
1265 		theEventQueue.virtualNet_v.Set(mySlaveNet, myMasterNet, parameterResistanceMap[theConnections.device_p->parameters], theEventQueue.virtualNet_v.lastUpdate);
1266 		CheckResistorOverflow_(theEventQueue.virtualNet_v[mySlaveNet].finalResistance, mySlaveNet, logFile);
1267 	} else {
1268 		netVoltagePtr_v.CalculatePower(theEventQueue, theShortVoltage, mySlaveNet, myMasterNet, this, theCalculation);
1269 		if ( gDebug_cvc ) cout << "DEBUG: Calculated power at net: " << mySlaveNet << " " << gEventQueueTypeMap[theEventQueue.queueType] << " " << theShortVoltage << endl;
1270 		// do not increment lastUpdate (increment in calling routine if necessary)
1271 		theEventQueue.virtualNet_v.Set(mySlaveNet, mySlaveNet, parameterResistanceMap[theConnections.device_p->parameters] + theEventQueue.virtualNet_v[myMasterNet].finalResistance, theEventQueue.virtualNet_v.lastUpdate);
1272 		CheckResistorOverflow_(theEventQueue.virtualNet_v[mySlaveNet].finalResistance, mySlaveNet, logFile);
1273 	}
1274 	if ( deviceType_v[theDeviceId] == RESISTOR ) {
1275 		PropagateConnectionType(theEventQueue.virtualNet_v, connectionCount_v[mySlaveNet].sourceDrainType, myMasterNet);
1276 	} else if ( deviceType_v[theDeviceId] == FUSE_ON || deviceType_v[theDeviceId] == FUSE_OFF ) {
1277 		netId_t myNextOtherNet;
1278 		if ( theEventQueue.queueType == MIN_QUEUE ) {
1279 			myNextOtherNet = maxNet_v[mySlaveNet].nextNetId;
1280 		} else {
1281 			assert( theEventQueue.queueType == MAX_QUEUE );
1282 			myNextOtherNet = minNet_v[mySlaveNet].nextNetId;
1283 		}
1284 		if ( myNextOtherNet == myMasterNet ) {
1285 			PrintFuseError(mySlaveNet, theConnections);
1286 		}
1287 	}
1288 	deviceStatus_v[theDeviceId][theEventQueue.inactiveBit] = true;
1289 }
1290 
ShortSimNets(CEventQueue & theEventQueue,deviceId_t theDeviceId,CConnection & theConnections,shortDirection_t theDirection,voltage_t theShortVoltage,string theCalculation)1291 void CCvcDb::ShortSimNets(CEventQueue& theEventQueue, deviceId_t theDeviceId, CConnection& theConnections, shortDirection_t theDirection, voltage_t theShortVoltage, string theCalculation) {
1292 	netId_t myMasterNet, mySlaveNet;
1293 	voltage_t myMasterVoltage;
1294 	CPower * myMasterPower_p;
1295 	if ( theDirection == DRAIN_TO_MASTER_SOURCE ) {
1296 		myMasterPower_p = theConnections.sourcePower_p;
1297 		myMasterNet = theConnections.sourceId;
1298 		mySlaveNet = theConnections.drainId;
1299 		myMasterVoltage = theConnections.sourceVoltage;
1300 	} else if ( theDirection == SOURCE_TO_MASTER_DRAIN ) {
1301 		myMasterPower_p = theConnections.drainPower_p;
1302 		myMasterNet = theConnections.drainId;
1303 		mySlaveNet = theConnections.sourceId;
1304 		myMasterVoltage = theConnections.drainVoltage;
1305 	} else {
1306 		throw EDatabaseError("ShortSimNets " + DeviceName(theDeviceId));
1307 	}
1308 	voltage_t myMaxSlaveVoltage = MaxLeakVoltage(mySlaveNet);
1309 	voltage_t myMinSlaveVoltage = MinLeakVoltage(mySlaveNet);
1310 	// 2013.11.13 added min max limits for sim voltages
1311 	string myCalculation = "";
1312 	if ( myMaxSlaveVoltage != UNKNOWN_VOLTAGE && myMaxSlaveVoltage < theShortVoltage ) {
1313 		theShortVoltage = myMaxSlaveVoltage;
1314 		myCalculation = " Limited to max";
1315 	}
1316 	if ( myMinSlaveVoltage != UNKNOWN_VOLTAGE && myMinSlaveVoltage > theShortVoltage ) {
1317 		theShortVoltage = myMinSlaveVoltage;
1318 		myCalculation = " Limited to min";
1319 	}
1320 	if ( theShortVoltage == myMasterVoltage ) {
1321 		if ( IsSCRCPower(myMasterPower_p) && connectionCount_v[mySlaveNet].sourceDrainType[NMOS] && connectionCount_v[mySlaveNet].sourceDrainType[PMOS] ) {
1322 			if ( IncrementDeviceError(theDeviceId, LEAK) < cvcParameters.cvcCircuitErrorLimit || cvcParameters.cvcCircuitErrorLimit == 0 ) {
1323 				errorFile << "! Short Detected: SCRC " << PrintVoltage(myMasterVoltage) << " to output" << endl;
1324 				static CFullConnection myConnections;
1325 				MapDeviceNets(theDeviceId, myConnections);
1326 				PrintDeviceWithAllConnections(deviceParent_v[theDeviceId], myConnections, errorFile);
1327 				errorFile << endl;
1328 			}
1329 		}
1330 		// do not increment lastUpdate
1331 		theEventQueue.virtualNet_v.Set(mySlaveNet, myMasterNet, parameterResistanceMap[theConnections.device_p->parameters], theEventQueue.virtualNet_v.lastUpdate);
1332 	} else {
1333 		netVoltagePtr_v.CalculatePower(theEventQueue, theShortVoltage, mySlaveNet, myMasterNet, this, theCalculation + myCalculation);
1334 		if ( gDebug_cvc ) cout << "DEBUG: Calculated power at net: " << mySlaveNet << " " << gEventQueueTypeMap[theEventQueue.queueType] << " " << theShortVoltage << endl;
1335 		if ( IsMos_(deviceType_v[theDeviceId]) && theConnections.gateId == mySlaveNet ) { // gate/drain connections increase effective resistance (trace is broken so add master final resistance)
1336 			// do not increment lastUpdate
1337 			theEventQueue.virtualNet_v.Set(mySlaveNet, mySlaveNet, parameterResistanceMap[theConnections.device_p->parameters] * 100 + theEventQueue.virtualNet_v[myMasterNet].finalResistance, theEventQueue.virtualNet_v.lastUpdate);
1338 		} else {
1339 			// do not increment lastUpdate
1340 			theEventQueue.virtualNet_v.Set(mySlaveNet, mySlaveNet, parameterResistanceMap[theConnections.device_p->parameters] + theEventQueue.virtualNet_v[myMasterNet].finalResistance, theEventQueue.virtualNet_v.lastUpdate);
1341 		}
1342 	}
1343 	CheckResistorOverflow_(theEventQueue.virtualNet_v[mySlaveNet].finalResistance, mySlaveNet, logFile);
1344 	if ( deviceType_v[theDeviceId] == RESISTOR ) {
1345 		PropagateConnectionType(theEventQueue.virtualNet_v, connectionCount_v[mySlaveNet].sourceDrainType, myMasterNet);
1346 	}
1347 	deviceStatus_v[theDeviceId][theEventQueue.inactiveBit] = true;
1348 }
1349 
PropagateConnectionType(CVirtualNetVector & theVirtualNet_v,CStatus theSourceDrainType,netId_t theNetId)1350 void CCvcDb::PropagateConnectionType(CVirtualNetVector& theVirtualNet_v, CStatus theSourceDrainType, netId_t theNetId) {
1351 	CStatus myNewStatus;
1352 	// TODO: Propagate upstream??
1353 	int myPropagationCount = 0;
1354 	while ( theNetId != theVirtualNet_v[theNetId].nextNetId ) {
1355 		assert(theNetId != UNKNOWN_NET );
1356 		myNewStatus = connectionCount_v[theNetId].sourceDrainType | theSourceDrainType;
1357 		if ( myNewStatus == connectionCount_v[theNetId].sourceDrainType ) break;
1358 		connectionCount_v[theNetId].sourceDrainType = myNewStatus;
1359 		theNetId = theVirtualNet_v[theNetId].nextNetId;
1360 		if ( myPropagationCount++ > 10000 ) {
1361 			reportFile << "ERROR: exceeded connection type propagation limit for net# " << theNetId << endl;
1362 			reportFile << "	name: " << NetName(theNetId) << endl;
1363 			reportFile << "	next net is " << theVirtualNet_v[theNetId].nextNetId << endl;
1364 			assert(myPropagationCount < 10000 );
1365 		}
1366 	}
1367 }
1368 
PropagateResistorVoltages(CEventQueue & theEventQueue)1369 void CCvcDb::PropagateResistorVoltages(CEventQueue& theEventQueue) {
1370 	deviceId_t myDeviceId = theEventQueue.GetEvent();
1371 	deviceStatus_v[myDeviceId][theEventQueue.pendingBit] = false;
1372 	queuePosition_t myQueuePosition;
1373 	if ( deviceStatus_v[myDeviceId][theEventQueue.inactiveBit] ) return;
1374 	static CConnection myConnections;
1375 	MapDeviceNets(myDeviceId, theEventQueue, myConnections);
1376 	if ( myConnections.IsUnknownSourceVoltage() ) {
1377 		assert (myConnections.drainVoltage != UNKNOWN_VOLTAGE);
1378 		ShortNets(theEventQueue, myDeviceId, myConnections, SOURCE_TO_MASTER_DRAIN);
1379 		myQueuePosition = ( myConnections.drainPower_p->type[POWER_BIT] ) ? MAIN_BACK : DELAY_FRONT;
1380 		EnqueueAttachedResistors(theEventQueue, myConnections.sourceId, myConnections.drainVoltage, myQueuePosition);
1381 	} else if ( myConnections.IsUnknownDrainVoltage() ) { // sourceVoltage != UNKNOWN_VOLTAGE
1382 		ShortNets(theEventQueue, myDeviceId, myConnections, DRAIN_TO_MASTER_SOURCE);
1383 		myQueuePosition = ( myConnections.sourcePower_p->type[POWER_BIT] ) ? MAIN_BACK : DELAY_FRONT;
1384 		EnqueueAttachedResistors(theEventQueue, myConnections.drainId, myConnections.sourceVoltage, myQueuePosition);
1385 	} else {
1386 		if (gDebug_cvc) cout << "already shorted PRV " << gEventQueueTypeMap[theEventQueue.queueType] << " " << myDeviceId << endl;
1387 		AlreadyShorted(theEventQueue, myDeviceId, myConnections);
1388 		if ( theEventQueue.virtualNet_v[myConnections.drainId].nextNetId != myConnections.drainId ) { // not terminal
1389 			PropagateConnectionType(theEventQueue.virtualNet_v, connectionCount_v[myConnections.drainId].sourceDrainType, myConnections.sourceId);
1390 		}
1391 		if ( theEventQueue.virtualNet_v[myConnections.sourceId].nextNetId != myConnections.sourceId ) { // not terminal
1392 			PropagateConnectionType(theEventQueue.virtualNet_v, connectionCount_v[myConnections.sourceId].sourceDrainType, myConnections.drainId);
1393 		}
1394 	}
1395 }
1396 
PropagateMinMaxVoltages(CEventQueue & theEventQueue)1397 void CCvcDb::PropagateMinMaxVoltages(CEventQueue& theEventQueue) {
1398 	eventKey_t myQueueKey = theEventQueue.QueueTime();
1399 	deviceId_t myDeviceId = theEventQueue.GetEvent();
1400 	deviceStatus_v[myDeviceId][theEventQueue.pendingBit] = false;
1401 	if ( deviceStatus_v[myDeviceId][theEventQueue.inactiveBit] ) return;
1402 	eventKey_t myOriginalEventKey, myEventKey;
1403 	queuePosition_t myQueuePosition;
1404 	netId_t myDrainId, mySourceId;
1405 	shortDirection_t myDirection;
1406 	static CConnection myConnections;
1407 	MapDeviceNets(myDeviceId, theEventQueue, myConnections);
1408 	// BUG: 20140307 if both nets are known, need highest for max, lowest for min.
1409 	if ( myConnections.sourceVoltage != UNKNOWN_VOLTAGE ) {
1410 		if ( myConnections.drainVoltage != UNKNOWN_VOLTAGE ) {
1411 			if ( theEventQueue.queueType == MIN_QUEUE ) {
1412 				if ( myConnections.sourceVoltage <= myConnections.drainVoltage ) {
1413 					myDirection = DRAIN_TO_MASTER_SOURCE;
1414 				} else {
1415 					myDirection = SOURCE_TO_MASTER_DRAIN;
1416 				}
1417 			} else { // MAX_QUEUE
1418 				assert(theEventQueue.queueType == MAX_QUEUE);
1419 				if ( myConnections.sourceVoltage >= myConnections.drainVoltage ) {
1420 					myDirection = DRAIN_TO_MASTER_SOURCE;
1421 				} else {
1422 					myDirection = SOURCE_TO_MASTER_DRAIN;
1423 				}
1424 			}
1425 		} else {
1426 			myDirection = DRAIN_TO_MASTER_SOURCE;
1427 		}
1428 	} else if ( myConnections.drainVoltage != UNKNOWN_VOLTAGE ) {
1429 		myDirection = SOURCE_TO_MASTER_DRAIN;
1430 	} else return; // enqueued due to gate/bias changes. ignore for now.
1431 	if ( myDirection == DRAIN_TO_MASTER_SOURCE ) {
1432 		myOriginalEventKey = myConnections.sourceVoltage;
1433 		myDrainId = myConnections.drainId;
1434 		mySourceId = myConnections.sourceId;
1435 		myQueuePosition = DefaultQueuePosition_(myConnections.sourcePower_p->type[POWER_BIT], theEventQueue);
1436 	} else { // myDirection = SOURCE_TO_MASTER_DRAIN;
1437 		myOriginalEventKey = myConnections.drainVoltage;
1438 		myDrainId = myConnections.sourceId;
1439 		mySourceId = myConnections.drainId;
1440 		myQueuePosition = DefaultQueuePosition_(myConnections.drainPower_p->type[POWER_BIT], theEventQueue);
1441 	}
1442 	myEventKey = myOriginalEventKey;
1443 	string myAdjustedCalculation = "";
1444 	if ( IsIrrelevant(theEventQueue, myDeviceId, myConnections, myEventKey, DEQUEUE) ) { // both source/drain defined handled here
1445 		deviceStatus_v[myDeviceId][theEventQueue.inactiveBit] = true;
1446 	} else {
1447 		if ( myDirection == DRAIN_TO_MASTER_SOURCE) assert (myConnections.drainVoltage == UNKNOWN_VOLTAGE);
1448 
1449 		myAdjustedCalculation = AdjustKey(theEventQueue, myDeviceId, myConnections, myEventKey, myQueuePosition, myDirection, PRINT_WARNINGS);
1450 		if ( myQueuePosition == SKIP_QUEUE ) return;
1451 		if (gDebug_cvc) cout << "DEBUG propagation:(" << gEventQueueTypeMap[theEventQueue.queueType] << ") device: " << myDeviceId << " QueueKey: " << myQueueKey << " EventKey: " << myEventKey << endl;
1452 		if ( theEventQueue.Later(myEventKey, myQueueKey) ) {
1453 			theEventQueue.AddEvent(myEventKey, myDeviceId, myQueuePosition);
1454 			deviceStatus_v[myDeviceId][theEventQueue.pendingBit] = true;
1455 			theEventQueue.requeueCount++;
1456 			if (gDebug_cvc) cout << "requeueing" << endl;
1457 		} else {
1458 			ShortNets(theEventQueue, myDeviceId, myConnections, myDirection, myEventKey, myAdjustedCalculation);
1459 			if ( theEventQueue.queueType == MIN_QUEUE && myOriginalEventKey < myEventKey && IsPmos_(deviceType_v[myConnections.deviceId]) ) {
1460 				voltage_t myMaxVoltage = MaxVoltage(myDrainId);
1461 				if ( IsDerivedFromFloating(maxNet_v, myDrainId) || myMaxVoltage == UNKNOWN_VOLTAGE || myMaxVoltage == myEventKey || netStatus_v[mySourceId][NEEDS_MAX_CHECK] ) {
1462 					if (netVoltagePtr_v[myDrainId].full ) {
1463 						if ( netVoltagePtr_v[myDrainId].full->pullUpVoltage() == UNKNOWN_VOLTAGE || netVoltagePtr_v[myDrainId].full->pullUpVoltage() < myEventKey ) {
1464 							if (gDebug_cvc) cout << "DEBUG: Adding max check at net " << myDrainId << endl;
1465 							netStatus_v[myDrainId][NEEDS_MAX_CHECK] = true;
1466 						}
1467 					} else cout << "DEBUG: missing voltage for max check " << NetName(myDrainId) << endl;
1468 				}
1469 			} else if ( theEventQueue.queueType == MAX_QUEUE && myOriginalEventKey > myEventKey && IsNmos_(deviceType_v[myConnections.deviceId]) ) {
1470 				voltage_t myMinVoltage = MinVoltage(myDrainId);
1471 				if ( IsDerivedFromFloating(minNet_v, myDrainId) || myMinVoltage == UNKNOWN_VOLTAGE || myMinVoltage == myEventKey || netStatus_v[mySourceId][NEEDS_MIN_CHECK] ) {
1472 					if ( netVoltagePtr_v[myDrainId].full ) {
1473 						if ( netVoltagePtr_v[myDrainId].full->pullDownVoltage() == UNKNOWN_VOLTAGE || netVoltagePtr_v[myDrainId].full->pullDownVoltage() > myEventKey ) {
1474 							if (gDebug_cvc) cout << "DEBUG: Adding min check at net " << myDrainId << endl;
1475 							netStatus_v[myDrainId][NEEDS_MIN_CHECK] = true;
1476 						}
1477 					} else cout << "DEBUG: missing voltage for min check " << NetName(myDrainId) << endl;
1478 				}
1479 			}
1480 			EnqueueAttachedDevices(theEventQueue, myDrainId, myEventKey);
1481 			if ( deviceType_v[myDeviceId] == RESISTOR && myOriginalEventKey == myEventKey ) {
1482 				// resistors propagating unchanged voltages
1483 				CDeviceCount myDeviceCount(myDrainId, this);
1484 				if ( theEventQueue.queueType == MIN_QUEUE && myDeviceCount.resistorCount == 1 && myDeviceCount.activePmosCount == 0 ) {
1485 					// one resistor connected to no pmos
1486 					ShortNets(minEventQueue, myDeviceId, myConnections, myDirection, myEventKey, "power through resistor");
1487 					EnqueueAttachedDevices(minEventQueue, myDrainId, myEventKey);
1488 				} else if (theEventQueue.queueType == MAX_QUEUE && myDeviceCount.resistorCount == 1 && myDeviceCount.activeNmosCount == 0 ) {
1489 					// one resistor connected to no nmos
1490 					ShortNets(maxEventQueue, myDeviceId, myConnections, myDirection, myEventKey, "power through resistor");
1491 					EnqueueAttachedDevices(maxEventQueue, myDrainId, myEventKey);
1492 				}
1493 			}
1494 		}
1495 	}
1496 }
1497 
PropagateSimVoltages(CEventQueue & theEventQueue,propagation_t thePropagationType)1498 void CCvcDb::PropagateSimVoltages(CEventQueue& theEventQueue, propagation_t thePropagationType) {
1499 	eventKey_t myQueueKey = theEventQueue.QueueTime();
1500 	deviceId_t myDeviceId = theEventQueue.GetEvent();
1501 	deviceStatus_v[myDeviceId][theEventQueue.pendingBit] = false;
1502 	if ( deviceStatus_v[myDeviceId][theEventQueue.inactiveBit] ) return;
1503 	voltage_t mySimVoltage;
1504 	netId_t myNextNetId;
1505 	shortDirection_t myDirection;
1506 	static CConnection myConnections;
1507 	MapDeviceNets(myDeviceId, theEventQueue, myConnections);
1508 	// 20140522A: when both source and drain are known, choose high for pmos, low for nmos
1509 	if ( myConnections.IsUnknownSourceVoltage() ) {
1510 		if ( myConnections.IsUnknownDrainVoltage() ) return; // enqueued to do gate/bias changes. ignore for now.
1511 		myDirection = SOURCE_TO_MASTER_DRAIN;
1512 		if ( myConnections.drainPower_p && myConnections.drainPower_p->type[HIZ_BIT] && ! IsSCRCPower(myConnections.drainPower_p) ) return;  // Don't propagate non-SCRC Hi-Z power
1513 	} else if ( myConnections.IsUnknownDrainVoltage() ) {
1514 		myDirection = DRAIN_TO_MASTER_SOURCE;
1515 		if ( myConnections.sourcePower_p && myConnections.sourcePower_p->type[HIZ_BIT] && ! IsSCRCPower(myConnections.sourcePower_p) ) return;  // Don't propagate non-SCRC Hi-Z power
1516 	} else if ( myConnections.sourceVoltage == UNKNOWN_VOLTAGE && myConnections.drainVoltage == UNKNOWN_VOLTAGE ) {  // drain/source Hi-Z, use default
1517 		myDirection = DRAIN_TO_MASTER_SOURCE;
1518 	} else if ( myConnections.sourceVoltage == UNKNOWN_VOLTAGE ) {  // source Hi-Z
1519 		myDirection = SOURCE_TO_MASTER_DRAIN;
1520 	} else if ( myConnections.drainVoltage == UNKNOWN_VOLTAGE ) {  // drain Hi-Z
1521 		myDirection = DRAIN_TO_MASTER_SOURCE;
1522 	} else if ( ( IsPmos_(deviceType_v[myDeviceId]) && myConnections.drainVoltage >= myConnections.sourceVoltage ) \
1523 			|| ( IsNmos_(deviceType_v[myDeviceId]) && myConnections.drainVoltage <= myConnections.sourceVoltage ) ) { // both source drain known
1524 		myDirection = SOURCE_TO_MASTER_DRAIN;
1525 	} else {
1526 		myDirection = DRAIN_TO_MASTER_SOURCE;
1527 	}
1528 	if ( myDirection == SOURCE_TO_MASTER_DRAIN ) {
1529 		mySimVoltage = myConnections.drainVoltage;
1530 		myNextNetId = myConnections.sourceId;
1531 		// TODO: Possibly not necessary. Only primed voltages are processed.
1532 		if ( thePropagationType == POWER_NETS_ONLY && ! IsPriorityPower_(myConnections.drainPower_p) ) return;
1533 	} else {
1534 		mySimVoltage = myConnections.sourceVoltage;
1535 		myNextNetId = myConnections.drainId;
1536 		// TODO: Possibly not necessary. Only primed voltages are processed.
1537 		if ( thePropagationType == POWER_NETS_ONLY && ! IsPriorityPower_(myConnections.sourcePower_p) ) return;
1538 	}
1539 	if ( IsMos_(deviceType_v[myDeviceId]) ) {
1540 		if ( myConnections.gateVoltage == UNKNOWN_VOLTAGE ) {
1541 			// check always on devices
1542 			voltage_t myMaxGateVoltage = MaxVoltage(myConnections.masterGateNet.finalNetId);
1543 			voltage_t myMinGateVoltage = MinVoltage(myConnections.masterGateNet.finalNetId);
1544 			if ( IsPmos_(deviceType_v[myDeviceId]) && myMaxGateVoltage != UNKNOWN_VOLTAGE && mySimVoltage != UNKNOWN_VOLTAGE
1545 					&& myMaxGateVoltage < mySimVoltage + myConnections.device_p->model_p->Vth ) {
1546 				if ( ! IsAlwaysOnCandidate(myDeviceId, myDirection) ) return;
1547 				myConnections.gateVoltage = myMaxGateVoltage;
1548 			} else if ( IsNmos_(deviceType_v[myDeviceId]) && myMinGateVoltage != UNKNOWN_VOLTAGE && mySimVoltage != UNKNOWN_VOLTAGE
1549 					&& myMinGateVoltage > mySimVoltage + myConnections.device_p->model_p->Vth ) {
1550 				if ( ! IsAlwaysOnCandidate(myDeviceId, myDirection) ) return;
1551 				myConnections.gateVoltage = myMinGateVoltage;
1552 			} else if ( thePropagationType == POWER_NETS_ONLY ||  // no mos-diode propagation for fixed-only
1553 					(myConnections.gateId != myConnections.sourceId && myConnections.gateId != myConnections.drainId)) return; // skip unknown non-diode mos gates
1554 		} else {
1555 			if ( thePropagationType == POWER_NETS_ONLY && ! IsPriorityPower_(myConnections.gatePower_p) ) return;
1556 		}
1557 	}
1558 	if (deviceType_v[myDeviceId] == FUSE_ON	&& thePropagationType != ALL_NETS_AND_FUSE)	return;
1559 	if ( deviceType_v[myDeviceId] == FUSE_OFF /* && thePropagationType == ALL_NETS_AND_FUSE */ ) {
1560 		deviceStatus_v[myDeviceId][theEventQueue.inactiveBit] = true;
1561 	} else if ( IsIrrelevant(theEventQueue, myDeviceId, myConnections, mySimVoltage, DEQUEUE) ) {
1562 		deviceStatus_v[myDeviceId][theEventQueue.inactiveBit] = true;
1563 	} else {
1564 		if (gDebug_cvc) cout << "DEBUG propagation:(" << gEventQueueTypeMap[theEventQueue.queueType] << ") device: " << myDeviceId << " QueueKey: " << myQueueKey << " EventKey: " << mySimVoltage << endl;
1565 		string myCalculation;
1566 		myCalculation = AdjustSimVoltage(theEventQueue, myDeviceId, myConnections, mySimVoltage, myDirection, thePropagationType);
1567 		if ( thePropagationType == POWER_NETS_ONLY && ! IsEmpty(myCalculation) ) return;  // skip adjusted sim voltages with fixed-only
1568 		if ( mySimVoltage == UNKNOWN_VOLTAGE ) return; // gate input = Vth (non mos diode)
1569 		ShortSimNets(theEventQueue, myDeviceId, myConnections, myDirection, mySimVoltage, myCalculation);
1570 		EnqueueAttachedDevices(theEventQueue, myNextNetId, mySimVoltage);
1571 	}
1572 }
1573 
CalculateResistorVoltage(netId_t theNetId,voltage_t theMinVoltage,resistance_t theMinResistance,voltage_t theMaxVoltage,resistance_t theMaxResistance)1574 void CCvcDb::CalculateResistorVoltage(netId_t theNetId, voltage_t theMinVoltage, resistance_t theMinResistance,
1575 			voltage_t theMaxVoltage, resistance_t theMaxResistance ) {
1576 	if ( theMinVoltage == UNKNOWN_VOLTAGE || theMaxVoltage == UNKNOWN_VOLTAGE ) return; // myIgnoreResistorFlag = true; // can't propagate unknown voltage
1577 	if ( theMinResistance == 0 || theMaxResistance == 0 ) return; //myIgnoreResistorFlag = true; // don't recalculate 0 resistance
1578 	netId_t myMinNet = minNet_v[theNetId].finalNetId;
1579 	netId_t myMaxNet = maxNet_v[theNetId].finalNetId;
1580 	if ( ! netVoltagePtr_v[myMinNet].full || netVoltagePtr_v[myMinNet].full->type[HIZ_BIT] ) return;  // don't calculate non-power or open
1581 	if ( ! netVoltagePtr_v[myMaxNet].full || netVoltagePtr_v[myMaxNet].full->type[HIZ_BIT] ) return;  // don't calculate non-power or open
1582 	if (  // myIgnoreResistorFlag == false &&
1583 			minNet_v[theNetId].nextNetId != maxNet_v[theNetId].nextNetId && // different paths to min/max
1584 			( minNet_v.IsTerminal(minNet_v[theNetId].nextNetId) || theNetId == maxNet_v[minNet_v[theNetId].nextNetId].nextNetId ) &&
1585 			( maxNet_v.IsTerminal(maxNet_v[theNetId].nextNetId) || theNetId == minNet_v[maxNet_v[theNetId].nextNetId].nextNetId ) ) {
1586 		if ( ! netVoltagePtr_v[theNetId].full ) {
1587 			cvcParameters.cvcPowerPtrList.push_back(new CPower(theNetId));
1588 			netVoltagePtr_v[theNetId].full = cvcParameters.cvcPowerPtrList.back();
1589 			netVoltagePtr_v[theNetId].full->extraData = new CExtraPowerData;
1590 			netVoltagePtr_v[theNetId].full->extraData->powerSignal = CPower::powerDefinitionText.SetTextAddress(RESISTOR_TEXT);
1591 		}
1592 		CPower * myPower_p = netVoltagePtr_v[theNetId].full;
1593 		voltage_t myNewVoltage = theMinVoltage + long( theMaxVoltage - theMinVoltage ) * theMinResistance / ( theMinResistance + theMaxResistance );
1594 		calculatedResistanceInfo_v[theNetId] = NetName(theNetId, PRINT_CIRCUIT_ON) + " " + to_string<voltage_t>(myNewVoltage);
1595 		calculatedResistanceInfo_v[theNetId] += " MinV:" + to_string<voltage_t>(theMinVoltage) + " MaxV:" + to_string<voltage_t>(theMaxVoltage);
1596 		calculatedResistanceInfo_v[theNetId] += " MinR:" + to_string<resistance_t>(theMinResistance) + " MaxR:" + to_string<resistance_t>(theMaxResistance);
1597 		calculatedResistanceInfo_v[theNetId] += (netVoltagePtr_v[theNetId].full->type[RESISTOR_BIT] ? " explicit" : " implicit");
1598 		string myCalculation = " R: " + PrintParameter(theMaxVoltage, 1000) + "V -> " + AddSiSuffix((float) theMaxResistance) + " ohm -> ";
1599 		myCalculation += PrintParameter(myNewVoltage, 1000) + "V -> ";
1600 		myCalculation += AddSiSuffix((float) theMinResistance) + " ohm -> " + PrintParameter(theMinVoltage, 1000) + "V";
1601 
1602 		myPower_p->simVoltage = myNewVoltage;
1603 		myPower_p->simCalculationType = RESISTOR_CALCULATION;
1604 		myPower_p->maxVoltage = myNewVoltage;
1605 		myPower_p->maxCalculationType = RESISTOR_CALCULATION;
1606 		myPower_p->minVoltage = myNewVoltage;
1607 		myPower_p->minCalculationType = RESISTOR_CALCULATION;
1608 		myPower_p->defaultMinNet = minNet_v[theNetId].finalNetId;
1609 		myPower_p->defaultMaxNet = maxNet_v[theNetId].finalNetId;
1610 		myPower_p->netId = theNetId;
1611 		myPower_p->type[MIN_CALCULATED_BIT] = true;
1612 	//	myPower_p->type[SIM_CALCULATED_BIT] = true;
1613 		myPower_p->type[MAX_CALCULATED_BIT] = true;
1614 		myPower_p->type[ANALOG_BIT] = true;
1615 		string myDefinition = myPower_p->definition + (" calculation=> " + myCalculation);
1616 		myPower_p->definition = CPower::powerDefinitionText.SetTextAddress((text_t)myDefinition.c_str());
1617 		myPower_p->type[RESISTOR_BIT] = true;
1618 		minNet_v.lastUpdate += 1;
1619 		simNet_v.lastUpdate += 1;
1620 		maxNet_v.lastUpdate += 1;
1621 	}
1622 }
1623 
PropagateResistorCalculations(netId_t theNetId,CDeviceIdVector & theFirstDevice_v,CDeviceIdVector & theNextDevice_v)1624 void CCvcDb::PropagateResistorCalculations(netId_t theNetId, CDeviceIdVector& theFirstDevice_v, CDeviceIdVector& theNextDevice_v) {
1625 	CFullConnection myConnections;
1626 	for ( deviceId_t device_it = theFirstDevice_v[theNetId]; device_it != UNKNOWN_DEVICE; device_it = theNextDevice_v[device_it] ) {
1627 		if ( deviceType_v[device_it] == RESISTOR ) {
1628 			MapDeviceNets(device_it, myConnections);
1629 			if ( netVoltagePtr_v[myConnections.drainId].full == NULL ) {
1630 				cvcParameters.cvcPowerPtrList.push_back(new CPower(myConnections.drainId));
1631 				netVoltagePtr_v[myConnections.drainId].full = cvcParameters.cvcPowerPtrList.back();
1632 				netVoltagePtr_v[myConnections.drainId].full->type[RESISTOR_BIT] = true;
1633 				netVoltagePtr_v[myConnections.drainId].full->extraData = new CExtraPowerData;
1634 				netVoltagePtr_v[myConnections.drainId].full->extraData->powerSignal = CPower::powerDefinitionText.SetTextAddress(RESISTOR_TEXT);
1635 			}
1636 			if ( netVoltagePtr_v[myConnections.sourceId].full == NULL ) {
1637 				cvcParameters.cvcPowerPtrList.push_back(new CPower(myConnections.sourceId));
1638 				netVoltagePtr_v[myConnections.sourceId].full = cvcParameters.cvcPowerPtrList.back();
1639 				netVoltagePtr_v[myConnections.sourceId].full->type[RESISTOR_BIT] = true;
1640 				netVoltagePtr_v[myConnections.sourceId].full->extraData = new CExtraPowerData;
1641 				netVoltagePtr_v[myConnections.sourceId].full->extraData->powerSignal = CPower::powerDefinitionText.SetTextAddress(RESISTOR_TEXT);
1642 			}
1643 		}
1644 	}
1645 }
1646 
CalculateResistorVoltages()1647 void CCvcDb::CalculateResistorVoltages() {
1648 	CFullConnection myConnections;
1649 	calculatedResistanceInfo_v.clear();
1650 	for (auto power_ppit = cvcParameters.cvcPowerPtrList.begin(); power_ppit != cvcParameters.cvcPowerPtrList.end(); power_ppit++) {
1651 		// since new entries are appended to the power list, this routine is effectively recursive
1652 		if ( (*power_ppit)->type[RESISTOR_BIT] ) { // && (*power_ppit)->simVoltage == UNKNOWN_VOLTAGE ) {
1653 			netId_t myPowerNet = (*power_ppit)->netId;
1654 			if ( myPowerNet != UNKNOWN_NET && netVoltagePtr_v[myPowerNet].full == *power_ppit ) { // process only used power nodes (ununsed power kept in powerPtrList)
1655 				PropagateResistorCalculations(myPowerNet, firstSource_v, nextSource_v);
1656 				PropagateResistorCalculations(myPowerNet, firstDrain_v, nextDrain_v);
1657 			}
1658 		}
1659 	}
1660 	for (deviceId_t device_it = 0; device_it < deviceCount; device_it++ ) {
1661 		if ( deviceType_v[device_it] == RESISTOR && deviceStatus_v[device_it][SIM_INACTIVE] == false ) {
1662 			MapDeviceNets(device_it, myConnections);
1663 			if ( ( netVoltagePtr_v[myConnections.sourceId].full == NULL && connectionCount_v[myConnections.sourceId].sourceDrainType == RESISTOR_ONLY ) ||
1664 					( netVoltagePtr_v[myConnections.sourceId].full && netVoltagePtr_v[myConnections.sourceId].full->type[RESISTOR_BIT] && netVoltagePtr_v[myConnections.sourceId].full->simVoltage == UNKNOWN_VOLTAGE ) ) {
1665 				if ( myConnections.minSourceVoltage != myConnections.maxSourceVoltage ) {
1666 					CalculateResistorVoltage(myConnections.sourceId, myConnections.minSourceVoltage, myConnections.masterMinSourceNet.finalResistance,
1667 							myConnections.maxSourceVoltage, myConnections.masterMaxSourceNet.finalResistance);
1668 
1669 				}
1670 			}
1671 			if ( ( netVoltagePtr_v[myConnections.drainId].full == NULL && connectionCount_v[myConnections.drainId].sourceDrainType == RESISTOR_ONLY ) ||
1672 					( netVoltagePtr_v[myConnections.drainId].full && netVoltagePtr_v[myConnections.drainId].full->type[RESISTOR_BIT] && netVoltagePtr_v[myConnections.drainId].full->simVoltage == UNKNOWN_VOLTAGE  ) ) {
1673 				if ( myConnections.minDrainVoltage != myConnections.maxDrainVoltage ) {
1674 					CalculateResistorVoltage(myConnections.drainId, myConnections.minDrainVoltage, myConnections.masterMinDrainNet.finalResistance,
1675 							myConnections.maxDrainVoltage, myConnections.masterMaxDrainNet.finalResistance);
1676 				}
1677 			}
1678 		}
1679 	}
1680 	netId_t myLastPowerNet;
1681 	vector<bool> myPrintedPower(netCount, false);
1682 	for (auto power_ppit = cvcParameters.cvcPowerPtrList.begin(); power_ppit != cvcParameters.cvcPowerPtrList.end(); power_ppit++) {
1683 		if ( myPrintedPower[(*power_ppit)->netId] ) continue;  // already printed
1684 		if ( (*power_ppit)->type[RESISTOR_BIT] ) {
1685 			netId_t myPowerNet = (*power_ppit)->netId;
1686 			if ( netVoltagePtr_v[myPowerNet].full->simVoltage == UNKNOWN_VOLTAGE ) {
1687 				if ( ! IsEmpty(netVoltagePtr_v[myPowerNet].full->definition) ) {
1688 					reportFile << "WARNING: Could not calculate explicit resistor voltage for " << NetName((*power_ppit)->netId, PRINT_CIRCUIT_ON) << endl;
1689 				}
1690 			} else if ( IsCalculatedVoltage_((*power_ppit)) ) {
1691 				if ( netVoltagePtr_v[myPowerNet].full != *power_ppit ) continue; // skip unused power nodes
1692 				netId_t myNextNet = minNet_v[myPowerNet].nextNetId;
1693 				while ( netVoltagePtr_v[myNextNet].full && netVoltagePtr_v[myNextNet].full->simVoltage != UNKNOWN_VOLTAGE && ! minNet_v.IsTerminal(myNextNet) ) {
1694 					myPowerNet = myNextNet;
1695 					myNextNet = minNet_v[myNextNet].nextNetId;
1696 				}
1697 				do {
1698 					debugFile << "INFO: Resistor voltage calculation " << calculatedResistanceInfo_v[myPowerNet] << endl;
1699 					myPrintedPower[(*power_ppit)->netId] = true;
1700 					myLastPowerNet = myPowerNet;
1701 					myPowerNet = maxNet_v[myPowerNet].nextNetId;
1702 					minNet_v[myLastPowerNet].nextNetId = maxNet_v[myLastPowerNet].nextNetId = myLastPowerNet;
1703 					minNet_v[myLastPowerNet].finalNetId = maxNet_v[myLastPowerNet].finalNetId = myLastPowerNet;
1704 				} while ( netVoltagePtr_v[myPowerNet].full && netVoltagePtr_v[myPowerNet].full->simVoltage != UNKNOWN_VOLTAGE && ! maxNet_v.IsTerminal(myPowerNet));
1705 				debugFile << endl;
1706 			}
1707 		}
1708 	}
1709 }
1710 
SetResistorVoltagesByPower()1711 void CCvcDb::SetResistorVoltagesByPower() {
1712 	reportFile << "CVC: Calculating resistor voltages..." << endl;
1713 	queuePosition_t myQueuePosition;
1714 	for (CPowerPtrList::iterator power_ppit = cvcParameters.cvcPowerPtrList.begin(); power_ppit != cvcParameters.cvcPowerPtrList.end(); power_ppit++) {
1715 		// should only be defined voltages at this time.
1716 		CPower * myPower_p = * power_ppit;
1717 		netId_t myNetId = myPower_p->netId;
1718 		if ( myPower_p->minVoltage != UNKNOWN_VOLTAGE ) {
1719 			myQueuePosition = DefaultQueuePosition_(myPower_p->type[POWER_BIT], minEventQueue);
1720 			EnqueueAttachedResistors(minEventQueue, myNetId, myPower_p->minVoltage, myQueuePosition);
1721 		}
1722 		if ( myPower_p->maxVoltage != UNKNOWN_VOLTAGE ) {
1723 			myQueuePosition = DefaultQueuePosition_(myPower_p->type[POWER_BIT], maxEventQueue);
1724 			EnqueueAttachedResistors(maxEventQueue, myNetId, myPower_p->maxVoltage, myQueuePosition);
1725 		}
1726 	}
1727 	minEventQueue.queueStart = true;
1728 	maxEventQueue.queueStart = true;
1729 	while (minEventQueue.QueueSize() + maxEventQueue.QueueSize() > 0) {
1730 		if (minEventQueue.QueueSize() > maxEventQueue.QueueSize()) {
1731 			PropagateResistorVoltages(minEventQueue);
1732 		} else {
1733 			PropagateResistorVoltages(maxEventQueue);
1734 		}
1735 	}
1736 	CalculateResistorVoltages();
1737 	cvcCircuitList.PrintAndResetCircuitErrors(this, cvcParameters.cvcCircuitErrorLimit, logFile, errorFile, "! Resistor Errors");
1738 	if ( gDebug_cvc ) {
1739 		PrintVirtualNets(minNet_v, "(minimum r)");
1740 		PrintVirtualNets(maxNet_v, "(maximum r)");
1741 		PrintVirtualNets(simNet_v, "(simulation r)");
1742 	}
1743 }
1744 
CheckEstimateDependency(CDependencyMap & theDependencyMap,size_t theEstimateType,list<netId_t> & theDependencyList)1745 bool CCvcDb::CheckEstimateDependency(CDependencyMap& theDependencyMap, size_t theEstimateType, list<netId_t>& theDependencyList) {
1746 	assert(! theDependencyList.empty());
1747 	for (auto net_pit = theDependencyList.begin(); net_pit != theDependencyList.end(); net_pit++) {
1748 		if ( netStatus_v[*net_pit][theEstimateType] == false ) return false;
1749 		if ( theDependencyMap.count(*net_pit) == 0 ) continue;
1750 		if ( CheckEstimateDependency(theDependencyMap, theEstimateType, theDependencyMap[*net_pit]) == false ) return false;
1751 	}
1752 	return(true);
1753 }
1754 
CheckEstimateDependencies()1755 void CCvcDb::CheckEstimateDependencies() {
1756 	for(auto netListPair_pit = minConnectionDependencyMap.begin(); netListPair_pit != minConnectionDependencyMap.end(); netListPair_pit++) {
1757 		netId_t myNetId = netListPair_pit->first;
1758 		if ( gDebug_cvc ) cout << "DEBUG: Min dependency queue " << myNetId << "(" << netListPair_pit->second.front() << "-" << netListPair_pit->second.size() << ")" << endl;
1759 		if ( netStatus_v[myNetId][NEEDS_MIN_CONNECTION] == false ) continue;
1760 		netStatus_v[myNetId][NEEDS_MIN_CONNECTION] = CheckEstimateDependency(minConnectionDependencyMap, NEEDS_MIN_CONNECTION, netListPair_pit->second);
1761 	}
1762 	for(auto netListPair_pit = maxConnectionDependencyMap.begin(); netListPair_pit != maxConnectionDependencyMap.end(); netListPair_pit++) {
1763 		netId_t myNetId = netListPair_pit->first;
1764 		if ( gDebug_cvc ) cout << "DEBUG: Max dependency queue " << myNetId << "(" << netListPair_pit->second.front() << "-" << netListPair_pit->second.size() << ")" << endl;
1765 		if ( netStatus_v[myNetId][NEEDS_MAX_CONNECTION] == false ) continue;
1766 		netStatus_v[myNetId][NEEDS_MAX_CONNECTION] = CheckEstimateDependency(maxConnectionDependencyMap, NEEDS_MAX_CONNECTION, netListPair_pit->second);
1767 	}
1768 }
1769 
SetTrivialMinMaxPower()1770 void CCvcDb::SetTrivialMinMaxPower() {
1771 	reportFile << "Processing trivial nets";
1772 	cout.flush();
1773 	deviceId_t myNmos, myPmos;
1774 	CConnection myConnections;
1775 	netId_t myGroundNet, myPowerNet, myGateNet;
1776 	voltage_t myMinPower, myMaxPower;
1777 	resistance_t myNmosResistance, myPmosResistance;
1778 	int	myTrivialCount = 0;
1779 	int myPrintCount = 1000000;
1780 	set<string> myUndefinedPowerNets;
1781 	for ( netId_t net_it = 0; net_it < netCount; net_it++ ) {
1782 		if ( net_it != GetEquivalentNet(net_it) ) continue;
1783 		if ( myPrintCount-- <= 0 ) {
1784 			cout << "."; cout.flush();
1785 			myPrintCount = 1000000;
1786 		}
1787 		if ( minNet_v[net_it].nextNetId != net_it || maxNet_v[net_it].nextNetId != net_it ) continue; // already assigned
1788 		if ( netVoltagePtr_v[net_it].full
1789 			&& ! ( netVoltagePtr_v[net_it].full->minVoltage == UNKNOWN_VOLTAGE && netVoltagePtr_v[net_it].full->minVoltage == UNKNOWN_VOLTAGE ) ) continue;  // skip defined min/max
1790 		if ( connectionCount_v[net_it].sourceCount + connectionCount_v[net_it].drainCount == 2 ) { // only hits master equivalent nets
1791 			if ( connectionCount_v[net_it].sourceDrainType[NMOS] && connectionCount_v[net_it].sourceDrainType[PMOS] ) {
1792 				myNmos = UNKNOWN_DEVICE;
1793 				myPmos = UNKNOWN_DEVICE;
1794 				for ( deviceId_t device_it = firstDrain_v[net_it]; device_it != UNKNOWN_DEVICE; device_it = nextDrain_v[device_it] ) {
1795 					//if ( sourceNet_v[device_it] == gateNet_v[device_it] ) continue; // skip mos diodes  (need this for tied inverters)
1796 					if ( sourceNet_v[device_it] == drainNet_v[device_it] ) continue; // skip mos capacitors
1797 
1798 					if ( IsNmos_(deviceType_v[device_it]) ) {
1799 						if ( myNmos == UNKNOWN_DEVICE || sourceNet_v[device_it] != gateNet_v[device_it] ) {  // only use tied input if nothing else is available
1800 							myNmos = device_it;
1801 						}
1802 					}
1803 					if ( IsPmos_(deviceType_v[device_it]) ) {
1804 						if ( myPmos == UNKNOWN_DEVICE || sourceNet_v[device_it] != gateNet_v[device_it] ) {  // only use tied input if nothing else is available
1805 							myPmos = device_it;
1806 						}
1807 					}
1808 				}
1809 				for ( deviceId_t device_it = firstSource_v[net_it]; device_it != UNKNOWN_DEVICE; device_it = nextSource_v[device_it] ) {
1810 					if ( sourceNet_v[device_it] == drainNet_v[device_it] ) continue; // skip mos capacitors
1811 
1812 					if ( IsNmos_(deviceType_v[device_it]) ) {
1813 						if ( myNmos == UNKNOWN_DEVICE || drainNet_v[device_it] != gateNet_v[device_it] ) {  // only use tied input if nothing else is available
1814 							myNmos = device_it;
1815 						}
1816 					}
1817 					if ( IsPmos_(deviceType_v[device_it]) ) {
1818 						if ( myPmos == UNKNOWN_DEVICE || drainNet_v[device_it] != gateNet_v[device_it] ) {  // only use tied input if nothing else is available
1819 							myPmos = device_it;
1820 						}
1821 					}
1822 				}
1823 				if ( myNmos == UNKNOWN_DEVICE ) continue;
1824 				if ( myPmos == UNKNOWN_DEVICE ) continue;
1825 				if ( deviceStatus_v[myNmos][MIN_INACTIVE] ) continue;
1826 				if ( deviceStatus_v[myPmos][MAX_INACTIVE] ) continue;
1827 				MapDeviceNets(myNmos, minEventQueue, myConnections);
1828 				myGateNet = myConnections.gateId;
1829 				if ( myConnections.sourceId == net_it ) {
1830 					myGroundNet = myConnections.drainId;
1831 				} else if ( myConnections.drainId == net_it ) {
1832 					myGroundNet = myConnections.sourceId;
1833 				} else {
1834 					continue; // net already assigned
1835 				}
1836 				if ( myConnections.gateId == net_it ) continue; // mos diodes are not trivial
1837 				myNmosResistance = myConnections.resistance;
1838 				MapDeviceNets(myPmos, maxEventQueue, myConnections);
1839 				if ( myConnections.sourceId == net_it ) {
1840 					myPowerNet = myConnections.drainId;
1841 				} else if ( myConnections.drainId == net_it ) {
1842 					myPowerNet = myConnections.sourceId;
1843 				} else {
1844 					continue; // net already assigned
1845 				}
1846 				if ( myConnections.gateId == net_it ) continue; // mos diodes are not trivial
1847 				myPmosResistance = myConnections.resistance;
1848 				if ( myGateNet != myConnections.gateId ) continue; // ignore non-inverters
1849 				if ( netVoltagePtr_v[myGroundNet].full && netVoltagePtr_v[myPowerNet].full && netVoltagePtr_v[myGroundNet].full->type[POWER_BIT] && netVoltagePtr_v[myPowerNet].full->type[POWER_BIT] ) {
1850 					if ( netVoltagePtr_v[myGroundNet].full->minVoltage != netVoltagePtr_v[myGroundNet].full->maxVoltage ) continue; // ignore variable power
1851 					if ( netVoltagePtr_v[myPowerNet].full->minVoltage != netVoltagePtr_v[myPowerNet].full->maxVoltage ) continue; // ignore variable power
1852 					myMinPower = netVoltagePtr_v[myGroundNet].full->minVoltage;
1853 					myMaxPower = netVoltagePtr_v[myPowerNet].full->maxVoltage;
1854 					if ( myMaxPower != UNKNOWN_VOLTAGE && myMinPower < myMaxPower ) { // implies myMinPower != UNKNOWN_VOLTAGE
1855 						minNet_v.Set(net_it, myGroundNet, myNmosResistance, 0);
1856 						CheckResistorOverflow_(minNet_v[net_it].resistance, net_it, logFile);
1857 						maxNet_v.Set(net_it, myPowerNet, myPmosResistance, 0);
1858 						CheckResistorOverflow_(maxNet_v[net_it].resistance, net_it, logFile);
1859 						deviceStatus_v[myNmos][MIN_INACTIVE] = true;
1860 						deviceStatus_v[myNmos][MAX_INACTIVE] = true;
1861 						deviceStatus_v[myPmos][MIN_INACTIVE] = true;
1862 						deviceStatus_v[myPmos][MAX_INACTIVE] = true;
1863 						myTrivialCount++;
1864 						if ( inverterNet_v[net_it] == UNKNOWN_NET ) {
1865 							inverterNet_v[net_it] = myGateNet;
1866 						} else if ( inverterNet_v[net_it] != myGateNet ) {
1867 							reportFile << "WARNING: could not set " << myGateNet << " ->inv-> " << net_it;
1868 							reportFile << " because " << inverterNet_v[net_it] << " ->inv-> " << net_it << " already set" << endl;
1869 						}
1870 					}
1871 				} else if ( gSetup_cvc ) {
1872 					CStatus myGateTypes;
1873 					for ( deviceId_t device_it = firstGate_v[net_it]; device_it != UNKNOWN_DEVICE; device_it = nextGate_v[device_it] ) {
1874 						if ( IsNmos_(deviceType_v[device_it]) ) {
1875 							myGateTypes[NMOS] = true;
1876 						} else if ( IsPmos_(deviceType_v[device_it]) ) {
1877 							myGateTypes[PMOS] = true;
1878 						}
1879 					}
1880 					if ( myGateTypes != NMOS_PMOS ) continue;  // Only flag if has connections to nmos and pmos gates.
1881 					if ( ! netVoltagePtr_v[myGroundNet].full && connectionCount_v[myGroundNet].SourceDrainCount() > 5 ) {
1882 						myUndefinedPowerNets.insert(NetName(myGroundNet, PRINT_CIRCUIT_ON) + " " + to_string<deviceId_t>(connectionCount_v[myGroundNet].SourceDrainCount()) );
1883 					}
1884 					if ( ! netVoltagePtr_v[myPowerNet].full && connectionCount_v[myPowerNet].SourceDrainCount() > 5 ) {
1885 						myUndefinedPowerNets.insert(NetName(myPowerNet, PRINT_CIRCUIT_ON) + " " + to_string<deviceId_t>(connectionCount_v[myPowerNet].SourceDrainCount()) );
1886 					}
1887 				}
1888 			}
1889 		}
1890 	}
1891 	reportFile << " found " << myTrivialCount << " trivial nets" << endl;
1892 	if ( ! myUndefinedPowerNets.empty() ) {
1893 		reportFile << endl << "CVC SETUP: Undefined inverter power" << endl << endl;
1894 		for ( auto net_pit = myUndefinedPowerNets.begin(); net_pit != myUndefinedPowerNets.end(); net_pit++ ) {
1895 			reportFile << *net_pit << endl;
1896 		}
1897 		reportFile << endl;
1898 	}
1899 }
ResetMinMaxActiveStatus()1900 void CCvcDb::ResetMinMaxActiveStatus() {
1901 	// possibly change to netVoltagePtr_v
1902 	for (auto power_ppit = cvcParameters.cvcPowerPtrList.begin(); power_ppit != cvcParameters.cvcPowerPtrList.end(); power_ppit++) {
1903 		(*power_ppit)->active[MIN_ACTIVE] = (*power_ppit)->active[MAX_ACTIVE] = false;
1904 		if ( (*power_ppit)->type[INPUT_BIT] // always activate min/max for inputs
1905 				|| (*power_ppit)->type[POWER_BIT] // always activate min/max for power
1906 				|| ! ((*power_ppit)->simVoltage == UNKNOWN_VOLTAGE || (*power_ppit)->type[SIM_CALCULATED_BIT]) ) { // activate min/max if sim set but not calculated
1907 			if ( (*power_ppit)->minVoltage != UNKNOWN_VOLTAGE && ! (*power_ppit)->active[MIN_IGNORE] ) {
1908 				(*power_ppit)->active[MIN_ACTIVE] = true;
1909 			}
1910 			if ( (*power_ppit)->maxVoltage != UNKNOWN_VOLTAGE && ! (*power_ppit)->active[MAX_IGNORE] ) {
1911 				(*power_ppit)->active[MAX_ACTIVE] = true;
1912 			}
1913 		}
1914 	}
1915 }
1916 
SetInitialMinMaxPower()1917 void CCvcDb::SetInitialMinMaxPower() {
1918 	reportFile << "CVC: Calculating min/max voltages..." << endl;
1919 	isFixedMinNet = isFixedMaxNet = false;
1920 	minConnectionDependencyMap.clear();
1921 	maxConnectionDependencyMap.clear();
1922 	unknownGateSet.clear();
1923 	ResetMinMaxActiveStatus();
1924 	SetTrivialMinMaxPower();
1925 	CVirtualNet myMinMasterNet, myMaxMasterNet;
1926 	for ( netId_t net_it = 0; net_it < netCount; net_it++ ) {
1927 		if ( net_it != GetEquivalentNet(net_it) ) continue; // skip subordinate nets
1928 		myMinMasterNet(minNet_v, net_it);
1929 		myMaxMasterNet(maxNet_v, net_it);
1930 		CPower * myPower_p = netVoltagePtr_v[myMinMasterNet.finalNetId].full;
1931 		if ( myPower_p && myPower_p->active[MIN_ACTIVE] ) {
1932 			voltage_t myMinVoltage = ( isFixedSimNet && myPower_p->simVoltage != UNKNOWN_VOLTAGE ) ? myPower_p->simVoltage : myPower_p->minVoltage;
1933 			if ( myMinVoltage != UNKNOWN_VOLTAGE ) {
1934 				EnqueueAttachedDevicesByTerminal(minEventQueue, net_it, firstSource_v, nextSource_v, myMinVoltage);
1935 				EnqueueAttachedDevicesByTerminal(minEventQueue, net_it, firstDrain_v, nextDrain_v, myMinVoltage);
1936 			}
1937 		}
1938 		myPower_p = netVoltagePtr_v[myMaxMasterNet.finalNetId].full;
1939 		if ( myPower_p && myPower_p->active[MAX_ACTIVE] ) {
1940 			voltage_t myMaxVoltage = ( isFixedSimNet && myPower_p->simVoltage != UNKNOWN_VOLTAGE ) ? myPower_p->simVoltage : myPower_p->maxVoltage;
1941 			if ( myMaxVoltage != UNKNOWN_VOLTAGE ) {
1942 				EnqueueAttachedDevicesByTerminal(maxEventQueue, net_it, firstSource_v, nextSource_v, myMaxVoltage);
1943 				EnqueueAttachedDevicesByTerminal(maxEventQueue, net_it, firstDrain_v, nextDrain_v, myMaxVoltage);
1944 			}
1945 		}
1946 	}
1947 	minEventQueue.queueStart = true;
1948 	maxEventQueue.queueStart = true;
1949 	long myLoopCount = minEventQueue.QueueSize() + maxEventQueue.QueueSize();
1950 	long myDequeueCount = 0;
1951 	bool myProcessingMinQueue = false;
1952 	while ( myLoopCount > 0 ) {
1953 		if (gDebug_cvc) cout << "Event Queue Size(min/max): " << minEventQueue.mainQueue.size() << "+" << minEventQueue.delayQueue.size();
1954 		if (gDebug_cvc) cout << "/" << maxEventQueue.mainQueue.size() << "+" << maxEventQueue.delayQueue.size() << endl;
1955 
1956 		// main queues first, then by size
1957 		if ( myDequeueCount == 0 ) {
1958 			if ((minEventQueue.IsNextMainQueue() == maxEventQueue.IsNextMainQueue() && minEventQueue.QueueSize() > maxEventQueue.QueueSize())
1959 					|| (minEventQueue.IsNextMainQueue() && ! maxEventQueue.IsNextMainQueue()) ) {
1960 				myProcessingMinQueue = true;
1961 				myDequeueCount = ( minEventQueue.IsNextMainQueue() ) ?
1962 					minEventQueue.mainQueue.begin()->second.eventListSize :
1963 					minEventQueue.delayQueue.begin()->second.eventListSize;
1964 			} else {
1965 				myProcessingMinQueue = false;
1966 				myDequeueCount = ( maxEventQueue.IsNextMainQueue() ) ?
1967 					maxEventQueue.mainQueue.begin()->second.eventListSize :
1968 					maxEventQueue.delayQueue.begin()->second.eventListSize;
1969 			}
1970 		}
1971 		assert(myDequeueCount);
1972 		if ( myProcessingMinQueue ) {
1973 			PropagateMinMaxVoltages(minEventQueue);
1974 		} else {
1975 			PropagateMinMaxVoltages(maxEventQueue);
1976 		}
1977 		myDequeueCount --;
1978 		myLoopCount --;
1979 		if ( myLoopCount < 1 ) {
1980 			myLoopCount = minEventQueue.QueueSize() + maxEventQueue.QueueSize();
1981 		}
1982 	}
1983 	// Reset min/max voltage conflict errors
1984 	cvcCircuitList.PrintAndResetCircuitErrors(this, cvcParameters.cvcCircuitErrorLimit, logFile, errorFile, "! Power/Ground path through fuse", FUSE_ERROR - FUSE_ERROR, FUSE_MODELS);
1985 	cvcCircuitList.PrintAndResetCircuitErrors(this, cvcParameters.cvcCircuitErrorLimit, logFile, errorFile, "! ... voltage already set");
1986 	CheckEstimateDependencies();
1987 	reportFile << "CVC: Ignoring invalid calculations..." << endl;
1988 	size_t myRemovedCount = 0;
1989 	for ( netId_t net_it = 0; net_it < netCount; net_it++ ) {
1990 		if ( netVoltagePtr_v[net_it].full == NULL ) continue; // skips subordinate nets
1991 		RemoveInvalidPower(net_it, myRemovedCount);
1992 	}
1993 	reportFile << "CVC:   Removed " << myRemovedCount << " calculations" << endl;
1994 	int	myProgressCount = 0;
1995 	reportFile << "Copying master nets"; cout.flush();
1996 	for ( netId_t net_it = 0; net_it < netCount; net_it++ ) {
1997 		if ( ++myProgressCount == 1000000 ) {
1998 			cout << "."; cout.flush();
1999 			myProgressCount = 0;
2000 		}
2001 		minNet_v[net_it](minNet_v, net_it); // recalculate final values
2002 		maxNet_v[net_it](maxNet_v, net_it); // recalculate final values
2003 	}
2004 	reportFile << endl;
2005 	isFixedMinNet = isFixedMaxNet = true;
2006 	if ( gSetup_cvc ) {
2007 		set<string> myUndefinedPowerNets;
2008 		for ( netId_t net_it = 0; net_it < netCount; net_it++ ) {
2009 			if ( ! netVoltagePtr_v[net_it].full || netVoltagePtr_v[net_it].full->type[POWER_BIT] ) continue;
2010 			if ( minNet_v[net_it].finalNetId != UNKNOWN_NET && maxNet_v[net_it].finalNetId != UNKNOWN_NET
2011 					&& netVoltagePtr_v[minNet_v[net_it].finalNetId].full && netVoltagePtr_v[maxNet_v[net_it].finalNetId].full
2012 					&& netVoltagePtr_v[minNet_v[net_it].finalNetId].full->minVoltage != UNKNOWN_VOLTAGE
2013 					&& netVoltagePtr_v[maxNet_v[net_it].finalNetId].full->maxVoltage != UNKNOWN_VOLTAGE
2014 					&& netVoltagePtr_v[minNet_v[net_it].finalNetId].full->minVoltage <= netVoltagePtr_v[maxNet_v[net_it].finalNetId].full->maxVoltage ) continue;
2015 			if ( connectionCount_v[net_it].SourceDrainCount() > 9 ) {
2016 				myUndefinedPowerNets.insert(NetName(net_it, PRINT_CIRCUIT_ON) + " " + to_string<size_t>(connectionCount_v[net_it].SourceDrainCount()));
2017 			}
2018 		}
2019 		reportFile << endl << "CVC SETUP: possible power nodes..." << endl << endl;
2020 		for ( auto item_pit = myUndefinedPowerNets.begin(); item_pit != myUndefinedPowerNets.end(); item_pit++ ) {
2021 			reportFile << *item_pit << endl;
2022 		}
2023 		reportFile << endl;
2024 	}
2025 	reportFile << "CVC: Ignoring non-conducting devices..." << endl;
2026 	// ignore devices with no leak paths
2027 	// really slow. has to calculate #device*#terminal instead of #net
2028 	size_t myIgnoreCount = 0;
2029 	CFullConnection myConnections;
2030 	for ( deviceId_t device_it = 0; device_it < deviceCount; device_it++ ) {
2031 		if ( deviceStatus_v[device_it][SIM_INACTIVE] ) continue;
2032 		MapDeviceSourceDrainNets(device_it, myConnections);
2033 		bool myIsHiZDrain = ( myConnections.minDrainPower_p && myConnections.minDrainPower_p->type[HIZ_BIT] ) ||
2034 				( myConnections.maxDrainPower_p && myConnections.maxDrainPower_p->type[HIZ_BIT] );
2035 		bool myIsHiZSource = ( myConnections.minSourcePower_p && myConnections.minSourcePower_p->type[HIZ_BIT] ) ||
2036 				( myConnections.maxSourcePower_p && myConnections.maxSourcePower_p->type[HIZ_BIT] );
2037 		if ( (! myIsHiZSource && myConnections.minSourceVoltage == UNKNOWN_VOLTAGE && myConnections.maxSourceVoltage == UNKNOWN_VOLTAGE) ||
2038 				(! myIsHiZDrain && myConnections.minDrainVoltage == UNKNOWN_VOLTAGE && myConnections.maxDrainVoltage == UNKNOWN_VOLTAGE) ) {
2039 			if (gDebug_cvc) cout << "Ignoring device " << device_it << " Connected to unknown min/max voltage." << endl;
2040 			IgnoreDevice(device_it);
2041 			myIgnoreCount++;
2042 		}
2043 	}
2044 	reportFile << "CVC:   Ignored " << myIgnoreCount << " devices" << endl;
2045 }
2046 
IgnoreUnusedDevices()2047 void CCvcDb::IgnoreUnusedDevices() {
2048 	CFullConnection myConnections;
2049 	for ( deviceId_t device_it = 0; device_it < deviceCount; device_it++ ) {
2050 		if ( deviceStatus_v[device_it][SIM_INACTIVE] ) continue;
2051 		MapDeviceNets(device_it, myConnections);
2052 		if ( myConnections.minSourceVoltage == UNKNOWN_VOLTAGE || myConnections.minDrainVoltage == UNKNOWN_VOLTAGE ||
2053 				myConnections.maxSourceVoltage == UNKNOWN_VOLTAGE || myConnections.maxDrainVoltage == UNKNOWN_VOLTAGE ) {
2054 			if (gDebug_cvc) cout << "Ignoring device " << device_it << " Connected to unknown min/max voltage." << endl;
2055 			IgnoreDevice(device_it);
2056 		}
2057 	}
2058 }
2059 
ResetMinMaxPower()2060 void CCvcDb::ResetMinMaxPower() {
2061 	minEventQueue.ResetQueue(deviceCount);
2062 	maxEventQueue.ResetQueue(deviceCount);
2063 	minNet_v.InitializeUpdateArray();
2064 	maxNet_v.InitializeUpdateArray();
2065 	for (deviceId_t device_it = 0; device_it < deviceCount; device_it++) {
2066 		deviceStatus_v[device_it][MIN_INACTIVE] = deviceStatus_v[device_it][MAX_INACTIVE] = deviceStatus_v[device_it][SIM_INACTIVE];
2067 	}
2068 	CPower * myVoltage_p;
2069 	for (netId_t net_it = 0; net_it < netCount; net_it++) {
2070 		if ( isFixedSimNet ) { // after first sim pass
2071 			if ( simNet_v[net_it].finalNetId == UNKNOWN_NET
2072 					|| ! netVoltagePtr_v[simNet_v[net_it].finalNetId].full
2073 					|| netVoltagePtr_v[simNet_v[net_it].finalNetId].full->simVoltage == UNKNOWN_VOLTAGE ) {
2074 				minNet_v[net_it].Copy(simNet_v[net_it]);
2075 				maxNet_v[net_it].Copy(simNet_v[net_it]);
2076 			} else {
2077 				if ( minNet_v[net_it].finalNetId == UNKNOWN_NET
2078 						|| ! netVoltagePtr_v[minNet_v[net_it].finalNetId].full
2079 						|| netVoltagePtr_v[minNet_v[net_it].finalNetId].full->minVoltage == UNKNOWN_VOLTAGE
2080 						|| ( netVoltagePtr_v[simNet_v[net_it].finalNetId].full->minVoltage != UNKNOWN_VOLTAGE
2081 								&& netVoltagePtr_v[minNet_v[net_it].finalNetId].full->minVoltage <= netVoltagePtr_v[simNet_v[net_it].finalNetId].full->minVoltage ) ) {
2082 					minNet_v[net_it].Copy(simNet_v[net_it]);
2083 				} else {
2084 					minNet_v.Set(net_it, net_it, 0, 0);
2085 				}
2086 				if ( maxNet_v[net_it].finalNetId == UNKNOWN_NET
2087 					|| ! netVoltagePtr_v[maxNet_v[net_it].finalNetId].full
2088 					|| netVoltagePtr_v[maxNet_v[net_it].finalNetId].full->maxVoltage == UNKNOWN_VOLTAGE
2089 					|| ( netVoltagePtr_v[maxNet_v[net_it].finalNetId].full->maxVoltage != UNKNOWN_VOLTAGE
2090 							&& netVoltagePtr_v[maxNet_v[net_it].finalNetId].full->maxVoltage >= netVoltagePtr_v[simNet_v[net_it].finalNetId].full->maxVoltage ) ) {
2091 					maxNet_v[net_it].Copy(simNet_v[net_it]);
2092 				} else {
2093 					maxNet_v.Set(net_it, net_it, 0, 0);
2094 				}
2095 			}
2096 			if ( netVoltagePtr_v[net_it].full &&
2097 					simNet_v[net_it].finalNetId != UNKNOWN_NET &&
2098 					netVoltagePtr_v[simNet_v[net_it].finalNetId].full->simVoltage == UNKNOWN_VOLTAGE ) {
2099 				// remove min/max calculations if not equal to sim
2100 				if ( netVoltagePtr_v[net_it].full->type[MIN_CALCULATED_BIT] ) {
2101 					if ( netVoltagePtr_v[net_it].full == leakVoltagePtr_v[net_it].full ) {  // Save old copy before erasing.
2102 						leakVoltagePtr_v[net_it].full = new CPower(netVoltagePtr_v[net_it].full);
2103 					}
2104 					netVoltagePtr_v[net_it].full->type[MIN_CALCULATED_BIT] = false;
2105 					netVoltagePtr_v[net_it].full->defaultMinNet = UNKNOWN_NET;
2106 					netVoltagePtr_v[net_it].full->minVoltage = UNKNOWN_VOLTAGE;
2107 				}
2108 				if ( netVoltagePtr_v[net_it].full->type[MAX_CALCULATED_BIT] ) {
2109 					if ( netVoltagePtr_v[net_it].full == leakVoltagePtr_v[net_it].full ) {  // Save old copy before erasing.
2110 						leakVoltagePtr_v[net_it].full = new CPower(netVoltagePtr_v[net_it].full);
2111 					}
2112 					netVoltagePtr_v[net_it].full->type[MAX_CALCULATED_BIT] = false;
2113 					netVoltagePtr_v[net_it].full->defaultMaxNet = UNKNOWN_NET;
2114 					netVoltagePtr_v[net_it].full->maxVoltage = UNKNOWN_VOLTAGE;
2115 				}
2116 				if ( netVoltagePtr_v[net_it].full->type == NO_TYPE && IsEmpty(netVoltagePtr_v[net_it].full->powerSignal()) ) {
2117 					if ( gDebug_cvc ) {
2118 						cout << "DEBUG: Deleting net: " << net_it;
2119 						netVoltagePtr_v[net_it].full->Print(cout);
2120 					}
2121 					delete netVoltagePtr_v[net_it].full;
2122 					netVoltagePtr_v[net_it].full = NULL;
2123 				}
2124 			}
2125 		} else { // first min max. reset from resistance propagation.
2126 			if ( minNet_v[net_it].nextNetId == simNet_v[net_it].nextNetId ) {
2127 				minNet_v[net_it].finalNetId = simNet_v[net_it].finalNetId;
2128 				if ( minNet_v.IsTerminal(net_it) ) { // save resistances for calculated power
2129 					minNet_v[net_it].resistance = minNet_v[net_it].finalResistance;
2130 				}
2131 			} else {
2132 				minNet_v.Set(net_it, net_it, 0, 0);
2133 			}
2134 			if ( maxNet_v[net_it].nextNetId == simNet_v[net_it].nextNetId ) {
2135 				maxNet_v[net_it].finalNetId = simNet_v[net_it].finalNetId;
2136 				if ( maxNet_v.IsTerminal(net_it) ) { // save resistances for calculated power
2137 					maxNet_v[net_it].resistance = maxNet_v[net_it].finalResistance;
2138 				}
2139 			} else {
2140 				maxNet_v.Set(net_it, net_it, 0, 0);
2141 			}
2142 		}
2143 		myVoltage_p = netVoltagePtr_v[net_it].full;
2144 		if ( myVoltage_p == NULL ) continue; // skips subordinate nets
2145 		if ( isFixedSimNet && myVoltage_p->simVoltage != UNKNOWN_VOLTAGE ) {
2146 			// default min/max voltages are not calculated. meaning there is no path to source voltage.
2147 			string myDefinition = myVoltage_p->definition;
2148 			if ( myVoltage_p->minVoltage == UNKNOWN_VOLTAGE ) {
2149 				if ( leakVoltagePtr_v[net_it].full && leakVoltagePtr_v[net_it].full->minVoltage != UNKNOWN_VOLTAGE
2150 						&& leakVoltagePtr_v[net_it].full->minVoltage > myVoltage_p->simVoltage ) {
2151 					myVoltage_p->minVoltage = leakVoltagePtr_v[net_it].full->minVoltage;
2152 					myVoltage_p->defaultMinNet = leakVoltagePtr_v[net_it].full->defaultMinNet;
2153 					myDefinition += " min=leak";
2154 				} else {
2155 					myVoltage_p->minVoltage = myVoltage_p->simVoltage;
2156 					myVoltage_p->defaultMinNet = UNKNOWN_NET;
2157 					myDefinition += " min=sim";
2158 				}
2159 				myVoltage_p->active[MIN_ACTIVE] = true;
2160 				myVoltage_p->type[MIN_CALCULATED_BIT] = true;
2161 			}
2162 			if ( myVoltage_p->maxVoltage == UNKNOWN_VOLTAGE ) {
2163 				if ( leakVoltagePtr_v[net_it].full && leakVoltagePtr_v[net_it].full->maxVoltage != UNKNOWN_VOLTAGE
2164 						&& leakVoltagePtr_v[net_it].full->maxVoltage < myVoltage_p->simVoltage ) {
2165 					myVoltage_p->maxVoltage = leakVoltagePtr_v[net_it].full->maxVoltage;
2166 					myVoltage_p->defaultMaxNet = UNKNOWN_NET;
2167 					myDefinition += " max=leak";
2168 				} else {
2169 					myVoltage_p->maxVoltage = myVoltage_p->simVoltage;
2170 					myVoltage_p->defaultMaxNet = UNKNOWN_NET;
2171 					myDefinition += " max=sim";
2172 				}
2173 				myVoltage_p->active[MAX_ACTIVE] = true;
2174 				myVoltage_p->type[MAX_CALCULATED_BIT] = true;
2175 			}
2176 			if ( myVoltage_p->active[MIN_ACTIVE] && myVoltage_p->minVoltage > myVoltage_p->simVoltage ) {
2177 				reportFile << "WARNING: MIN > SIM " << myVoltage_p->minVoltage << " > " << myVoltage_p->simVoltage << " for " << NetName(net_it, PRINT_CIRCUIT_ON) << endl;
2178 			}
2179 			if ( myVoltage_p->active[MAX_ACTIVE] && myVoltage_p->maxVoltage < myVoltage_p->simVoltage ) {
2180 				reportFile << "WARNING: MAX < SIM " << myVoltage_p->maxVoltage << " < " << myVoltage_p->simVoltage << " for " << NetName(net_it, PRINT_CIRCUIT_ON) << endl;
2181 			}
2182 			myVoltage_p->definition = CPower::powerDefinitionText.SetTextAddress((text_t)myDefinition.c_str());
2183 		} else if ( SimVoltage(net_it) == UNKNOWN_VOLTAGE && IsEmpty(myVoltage_p->powerSignal()) && IsCalculatedVoltage_(myVoltage_p) ) {
2184 			if ( gDebug_cvc ) {
2185 				cout << "DEBUG: Deleting net: " << net_it;
2186 				myVoltage_p->Print(cout);
2187 			}
2188 			netVoltagePtr_v[net_it].full = NULL;
2189 		}
2190 
2191 	}
2192 	SetInitialMinMaxPower();
2193 	minNet_v.ClearUpdateArray();
2194 	maxNet_v.ClearUpdateArray();
2195 }
2196 
SetAnalogNets()2197 void CCvcDb::SetAnalogNets() {
2198 	for (netId_t net_it = 0; net_it < netCount; net_it++) {
2199 		if ( net_it != GetEquivalentNet(net_it) ) continue;  // skip subordinate nets
2200 		if ( netVoltagePtr_v[net_it].full && netVoltagePtr_v[net_it].full->type[POWER_BIT] ) continue;  // skip power
2201 		bool myIsAnalogNet = false;
2202 		deviceId_t device_it = firstSource_v[net_it];
2203 		while ( ! myIsAnalogNet && device_it != UNKNOWN_DEVICE ) {
2204 			if ( GetEquivalentNet(drainNet_v[device_it]) != net_it ) {
2205 				switch( deviceType_v[device_it] ) {
2206 				case NMOS: case LDDN: case PMOS: case LDDP: {
2207 					if ( GetEquivalentNet(gateNet_v[device_it]) == net_it) myIsAnalogNet = true;
2208 					break;
2209 				}
2210 				case RESISTOR: { myIsAnalogNet = true; break; }
2211 				default: break;
2212 				}
2213 			}
2214 			device_it = nextSource_v[device_it];
2215 		}
2216 		device_it = firstDrain_v[net_it];
2217 		while ( ! myIsAnalogNet && device_it != UNKNOWN_DEVICE ) {
2218 			if ( GetEquivalentNet(sourceNet_v[device_it]) != net_it ) {
2219 				switch( deviceType_v[device_it] ) {
2220 				case NMOS: case LDDN: case PMOS: case LDDP: {
2221 					if ( GetEquivalentNet(gateNet_v[device_it]) == net_it) myIsAnalogNet = true;
2222 					break;
2223 				}
2224 				case RESISTOR: { myIsAnalogNet = true; break; }
2225 				default: break;
2226 				}
2227 			}
2228 			device_it = nextDrain_v[device_it];
2229 		}
2230 		if ( myIsAnalogNet ) {
2231 			PropagateAnalogNetType(net_it, 0);
2232 		}
2233 	}
2234 	for (CPowerPtrList::iterator power_ppit = cvcParameters.cvcPowerPtrList.begin(); power_ppit != cvcParameters.cvcPowerPtrList.end(); power_ppit++) {
2235 		if ( (*power_ppit)->type[ANALOG_BIT] ) {
2236 			PropagateAnalogNetType(GetEquivalentNet((*power_ppit)->netId), 0);
2237 		}
2238 	}
2239 }
2240 
PropagateAnalogNetType(netId_t theNetId,int theGateCount)2241 void CCvcDb::PropagateAnalogNetType(netId_t theNetId, int theGateCount) {
2242 	// must propagate through gates for all base analog nets (source/drain may have already been propagated)
2243 	bool myIsAlreadyAnalog = netStatus_v[theNetId][ANALOG];
2244 	netStatus_v[theNetId][ANALOG] = true;
2245 	if ( theGateCount < 1 ) {
2246 		PropagateAnalogNetTypeByTerminal(theNetId, firstGate_v, nextGate_v, theGateCount + 1);
2247 	}
2248 	if ( ! myIsAlreadyAnalog ) {
2249 		PropagateAnalogNetTypeByTerminal(theNetId, firstSource_v, nextSource_v, theGateCount);
2250 		PropagateAnalogNetTypeByTerminal(theNetId, firstDrain_v, nextDrain_v, theGateCount);
2251 	}
2252 }
2253 
PropagateAnalogNetTypeByTerminal(netId_t theNetId,CDeviceIdVector & theFirstDevice_v,CDeviceIdVector & theNextDevice_v,int theGateCount)2254 void CCvcDb::PropagateAnalogNetTypeByTerminal(netId_t theNetId, CDeviceIdVector& theFirstDevice_v, CDeviceIdVector& theNextDevice_v, int theGateCount) {
2255 	for (deviceId_t device_it = theFirstDevice_v[theNetId]; device_it != UNKNOWN_DEVICE; device_it = theNextDevice_v[device_it]) {
2256 		netId_t mySourceId = GetEquivalentNet(sourceNet_v[device_it]);
2257 		netId_t myDrainId = GetEquivalentNet(drainNet_v[device_it]);
2258 		if ( mySourceId != myDrainId ) {
2259 			if ( ! ( netVoltagePtr_v[mySourceId].full || netStatus_v[mySourceId][ANALOG] ) ) {  // ignore power and already set
2260 				PropagateAnalogNetType(mySourceId, theGateCount);
2261 			}
2262 			if ( ! ( netVoltagePtr_v[myDrainId].full || netStatus_v[myDrainId][ANALOG] ) ) {  // ignore power and already set
2263 				PropagateAnalogNetType(myDrainId, theGateCount);
2264 			}
2265 		}
2266 	}
2267 }
2268 
SetSimPower(propagation_t thePropagationType,CNetIdSet & theNewNetSet)2269 void CCvcDb::SetSimPower(propagation_t thePropagationType, CNetIdSet & theNewNetSet) {
2270 	reportFile << "CVC: Propagating Simulation voltages " << thePropagationType << "..." << endl;
2271 	simEventQueue.ResetQueue(deviceCount);
2272 	simNet_v.InitializeUpdateArray();
2273 	isFixedSimNet = false;
2274 	CVirtualNet mySimMasterNet;
2275 	for (netId_t net_it = 0; net_it < netCount; net_it++) {
2276 		if ( net_it != GetEquivalentNet(net_it) ) continue; // skip subordinate nets
2277 		// TODO: Change to GetMasterNet
2278 		mySimMasterNet(simNet_v, net_it);
2279 		if ( theNewNetSet.size() > 0 && theNewNetSet.count(net_it) == 0 ) continue;  // not relavant to this pass
2280 		if ( netVoltagePtr_v[mySimMasterNet.finalNetId].full == NULL ) continue;
2281 		CPower * myPower_p = netVoltagePtr_v[mySimMasterNet.finalNetId].full;
2282 		if ( myPower_p->simVoltage == UNKNOWN_VOLTAGE && ! IsSCRCPower(myPower_p) ) continue;
2283 		if ( thePropagationType == POWER_NETS_ONLY && ! IsPriorityPower_(myPower_p) ) continue;
2284 		EnqueueAttachedDevicesByTerminal(simEventQueue, net_it, firstSource_v, nextSource_v, myPower_p->simVoltage);
2285 		EnqueueAttachedDevicesByTerminal(simEventQueue, net_it, firstDrain_v, nextDrain_v, myPower_p->simVoltage);
2286 		EnqueueAttachedDevicesByTerminal(simEventQueue, net_it, firstGate_v, nextGate_v, myPower_p->simVoltage);
2287 	}
2288 	simEventQueue.queueStart = true;
2289 	while (simEventQueue.QueueSize() > 0) {
2290 		PropagateSimVoltages(simEventQueue, thePropagationType);
2291 	}
2292 	for ( netId_t net_it = 0; net_it < netCount; net_it++ ) {
2293 		simNet_v[net_it](simNet_v, net_it); // recalculate final values
2294 	}
2295 	isFixedSimNet = true;
2296 	simNet_v.ClearUpdateArray();
2297 }
2298 
CheckConnections()2299 void CCvcDb::CheckConnections() {
2300 	static CVirtualNet myVirtualNet;
2301 	static CVirtualNet myMinNet;
2302 	static CVirtualNet myMaxNet;
2303 	unordered_map<netId_t, pair<deviceId_t, deviceId_t>> myBulkCount;
2304 	for (deviceId_t device_it = 0; device_it < deviceCount; device_it++) {
2305 		if ( bulkNet_v[device_it] == UNKNOWN_NET ) continue;
2306 		if ( IsMos_(deviceType_v[device_it]) && sourceNet_v[device_it] != drainNet_v[device_it] ) {  // only count non-capacitor mosfet
2307 			netId_t myBulkNet = bulkNet_v[device_it];
2308 			if ( myBulkCount[myBulkNet].first++ == 0 ) {  // remember the first connected device
2309 				myBulkCount[myBulkNet].second = device_it;
2310 			}
2311 		}
2312 	}
2313 	for (netId_t net_it = 0; net_it < netCount; net_it++) {
2314 		if ( myBulkCount.count(net_it) > 0 && myBulkCount[net_it].first >= connectionCount_v[net_it].sourceCount + connectionCount_v[net_it].drainCount ) {
2315 			// skips subordinate nets because only equivalent masters have counts.
2316 			// may have problems with moscaps, because one device has both source and drain connection.  <- moscaps not included in connectionCounts
2317 			myVirtualNet(simNet_v, net_it);
2318 			assert( myVirtualNet.finalNetId != UNKNOWN_NET );
2319 			CPower * myPower_p = netVoltagePtr_v[myVirtualNet.finalNetId].full;
2320 			if ( myVirtualNet.finalResistance > 1000000 && myVirtualNet.finalResistance != INFINITE_RESISTANCE ) {
2321 				reportFile << "WARNING: high res bias (" << myBulkCount[net_it].first << ") " << NetName(net_it, PRINT_CIRCUIT_ON) << " r=" << myVirtualNet.finalResistance << endl;
2322 			} else if ( ! myPower_p
2323 					|| ( myPower_p->simVoltage == UNKNOWN_VOLTAGE
2324 						&& ( myPower_p->minVoltage == UNKNOWN_VOLTAGE || myPower_p->maxVoltage == UNKNOWN_VOLTAGE ) ) ) {  // no error for missing bias if min/max defined.
2325 				myMinNet(minNet_v, net_it);
2326 				myMaxNet(maxNet_v, net_it);
2327 				if ( myMinNet.finalNetId != UNKNOWN_NET
2328 						&& netVoltagePtr_v[myMinNet.finalNetId].full
2329 						&& netVoltagePtr_v[myMinNet.finalNetId].full->minVoltage != UNKNOWN_VOLTAGE
2330 						&& myMinNet.finalNetId == myMaxNet.finalNetId ) continue;  // bias with min/max to same voltage not error
2331 				reportFile << "WARNING: missing bias (" << myBulkCount[net_it].first << ") " << NetName(net_it, PRINT_CIRCUIT_ON);
2332 				reportFile << " at " << DeviceName(myBulkCount[net_it].second, PRINT_CIRCUIT_ON, PRINT_HIERARCHY_OFF) << endl;
2333 			} else if ( IsCalculatedVoltage_(myPower_p) ) {
2334 				reportFile << "WARNING: calculated bias (" << myBulkCount[net_it].first << ") " << NetName(net_it, PRINT_CIRCUIT_ON);
2335 				reportFile << " at " << DeviceName(myBulkCount[net_it].second, PRINT_CIRCUIT_ON, PRINT_HIERARCHY_OFF)
2336 						<< (myPower_p->type[MIN_CALCULATED_BIT] ? " 1|" : " 0|")
2337 						<< (myPower_p->type[SIM_CALCULATED_BIT] ? "1|" : "0|")
2338 						<< (myPower_p->type[MAX_CALCULATED_BIT] ? "1" : "0") <<	endl;
2339 			}
2340 		}
2341 	}
2342 }
2343 
SetInverterHighLow(netId_t theNetId,netId_t theMaxNetId)2344 void CCvcDb::SetInverterHighLow(netId_t theNetId, netId_t theMaxNetId) {
2345 	bool myDebug = false;
2346 	if ( inverterNet_v[theNetId] == UNKNOWN_NET ) {
2347 		return;
2348 	} else if ( inverterNet_v[theNetId] == theMaxNetId ) { // prevent looping
2349 		return;
2350 	} else {
2351 		netId_t myInputId = inverterNet_v[theNetId];
2352 		SetInverterHighLow(myInputId, max(theMaxNetId, myInputId));
2353 		highLow_v[theNetId] = ! highLow_v[myInputId];
2354 		if ( myDebug ) cout << "Net " << theNetId << " input " << inverterNet_v[theNetId] << " " << highLow_v[theNetId] << " " << myInputId << endl;
2355 	}
2356 }
2357 
SetInverterInput(netId_t theNetId,netId_t theMaxNetId)2358 netId_t CCvcDb::SetInverterInput(netId_t theNetId, netId_t theMaxNetId) {
2359 	bool myDebug = false;
2360 	if ( inverterNet_v[theNetId] == UNKNOWN_NET ) {
2361 		return(theNetId);
2362 	} else if ( inverterNet_v[theNetId] == theMaxNetId ) { // prevent looping
2363 		return(theMaxNetId);
2364 	} else {
2365 		netId_t myInputId = inverterNet_v[theNetId];
2366 		inverterNet_v[theNetId] = SetInverterInput(myInputId, max(theMaxNetId, myInputId));
2367 		if ( myDebug ) cout << "Net " << theNetId << " input " << inverterNet_v[theNetId] << " " << highLow_v[theNetId] << " " << myInputId << endl;
2368 		return(inverterNet_v[theNetId]);
2369 	}
2370 }
2371 
SetInverters()2372 void CCvcDb::SetInverters() {
2373 	bool myDebug = false;
2374 	for( netId_t net_it = 0; net_it < netCount; net_it++ ) {
2375 		if ( net_it != GetEquivalentNet(net_it) ) continue;
2376 		myDebug = false;
2377 		if ( myDebug ) cout << endl << "Starting " << net_it << endl;
2378 		if ( inverterNet_v[net_it] != UNKNOWN_NET ) {
2379 			netId_t myInputId = inverterNet_v[net_it];
2380 			SetInverterHighLow(myInputId, max(net_it, myInputId));
2381 			highLow_v[net_it] = ! highLow_v[myInputId];
2382 		}
2383 	}
2384 	for( netId_t net_it = 0; net_it < netCount; net_it++ ) {
2385 		if ( net_it != GetEquivalentNet(net_it) ) continue;
2386 		myDebug = false;
2387 		if ( myDebug ) cout << endl << "Starting " << net_it << endl;
2388 		if ( inverterNet_v[net_it] != UNKNOWN_NET ) {
2389 			netId_t myInputId = inverterNet_v[net_it];
2390 			inverterNet_v[net_it] = SetInverterInput(myInputId, max(net_it, myInputId));
2391 		}
2392 	}
2393 }
2394