1 /*
2  * CCvcDb_init.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 #include <csignal>
35 #include <sys/stat.h>
36 #include <regex>
37 #include "mmappable_vector.h"
38 
39 extern CCvcDb * gCvcDb;
40 extern int gContinueCount;
41 
42 char SCRC_FORCED_TEXT[] = "SCRC forced";
43 char SCRC_EXPECTED_TEXT[] = "SCRC expected";
44 
interrupt_handler(int signum)45 void interrupt_handler(int signum) {
46 	if ( gInteractive_cvc ) {
47 		if ( gContinueCount > 0 ) {
48 			cout << endl << "Stopping at next stage. Use Control-\\ to abort." << endl << endl;
49 			gContinueCount = 0;
50 		} else {
51 			cout << endl << "Control-C disabled in interactive mode. Use Control-\\ to abort." << endl << endl;
52 		}
53 	} else {
54 		cout << endl << "Switching to interactive mode at next stage. Use Control-\\ to abort." << endl << endl;
55 		gInteractive_cvc = true;
56 	}
57 	gInterrupted = true;
58 }
59 
cleanup_handler(int signum)60 void cleanup_handler(int signum) {
61 	gCvcDb->RemoveLock();
62 	signal(signum, SIG_DFL);
63 	raise(signum);
64 }
65 
CCvcDb(int argc,const char * argv[])66 CCvcDb::CCvcDb(int argc, const char * argv[]) :
67 		cvcParameters(reportFile),
68 		minNet_v(MIN_CALCULATED_BIT),
69 		simNet_v(SIM_CALCULATED_BIT),
70 		maxNet_v(MAX_CALCULATED_BIT),
71 //		initialSimNet_v(mmap_allocator<CVirtualNet>("", READ_WRITE_SHARED, 0, MAP_WHOLE_FILE | ALLOW_REMAP | BYPASS_FILE_POOL)),
72 //		maxLeakNet_v(mmap_allocator<CVirtualNet>("", READ_WRITE_SHARED, 0, MAP_WHOLE_FILE | ALLOW_REMAP | BYPASS_FILE_POOL)),
73 //		minLeakNet_v(mmap_allocator<CVirtualNet>("", READ_WRITE_SHARED, 0, MAP_WHOLE_FILE | ALLOW_REMAP | BYPASS_FILE_POOL)),
74 		maxEventQueue(MAX_QUEUE, MAX_INACTIVE, MAX_PENDING, maxNet_v, netVoltagePtr_v),
75 		minEventQueue(MIN_QUEUE, MIN_INACTIVE, MIN_PENDING, minNet_v, netVoltagePtr_v),
76 		simEventQueue(SIM_QUEUE, SIM_INACTIVE, SIM_PENDING, simNet_v, netVoltagePtr_v),
77 		reportFile(cout, logFile) {
78 	cvcArgCount = argc;
79 	reportPrefix = "";
80 	while ( cvcArgIndex < argc && argv[cvcArgIndex][0] == '-' ) {
81 		if ( strcmp(argv[cvcArgIndex], "--debug") == 0 ) {
82 			gDebug_cvc = true;
83 		} else if ( strcmp(argv[cvcArgIndex], "-i") == 0 || strcmp(argv[cvcArgIndex], "--interactive") == 0 ) {
84 			gInteractive_cvc = true;
85 		} else if ( strcmp(argv[cvcArgIndex], "-p") == 0 || strcmp(argv[cvcArgIndex], "--prefix") == 0 ) {
86 			cvcArgIndex++;
87 			reportPrefix = argv[cvcArgIndex];
88 			if ( ! IsAlphanumeric(reportPrefix) ) throw EFatalError("invalid prefix " + reportPrefix);
89 		} else if ( strcmp(argv[cvcArgIndex], "-v") == 0 || strcmp(argv[cvcArgIndex], "--version") == 0 ) {
90 			cout << "CVC: Circuit Validation Check  Version " << CVC_VERSION << endl;
91 		} else if ( strcmp(argv[cvcArgIndex], "-s") == 0 || strcmp(argv[cvcArgIndex], "--setup") == 0 ) {
92 			cout << "CVC: Creating setup files " << endl;
93 			gSetup_cvc = true;
94 		} else {
95 			cout << "WARNING: unrecognized option " << argv[cvcArgIndex] << endl;
96 		}
97 		cvcArgIndex++;
98 	}
99 	signal(SIGINT, interrupt_handler);
100 	signal(SIGABRT, cleanup_handler);
101 	signal(SIGFPE, cleanup_handler);
102 	signal(SIGILL, cleanup_handler);
103 	signal(SIGSEGV, cleanup_handler);
104 	signal(SIGTERM, cleanup_handler);
105 	signal(SIGQUIT, cleanup_handler);
106 }
107 
~CCvcDb()108 CCvcDb::~CCvcDb() {
109 	cvcCircuitList.Clear();
110 	instancePtr_v.Clear();
111 }
112 
CountObjectsAndLinkSubcircuits()113 void CCvcDb::CountObjectsAndLinkSubcircuits() {
114 	reportFile << "CVC: Counting and linking..." << endl;
115 	isDeviceModelSet = false;
116 	try {
117 		topCircuit_p = cvcCircuitList.FindCircuit(cvcParameters.cvcTopBlock);
118 	}
119 	catch (const out_of_range& oor_exception) {
120 		throw EFatalError("could not find subcircuit: " + cvcParameters.cvcTopBlock);
121 	}
122 	topCircuit_p->CountObjectsAndLinkSubcircuits(cvcCircuitList.circuitNameMap);
123 	topCircuit_p->netCount += topCircuit_p->portCount;
124 	topCircuit_p->subcircuitCount++;
125 	topCircuit_p->instanceCount++;
126 	if ( topCircuit_p->netCount > MAX_NET || topCircuit_p->subcircuitCount > MAX_SUBCIRCUIT || topCircuit_p->deviceCount > MAX_DEVICE ) {
127 		throw EFatalError("data size exceeds 4G items");
128 	}
129 }
130 
AssignGlobalIDs()131 void CCvcDb::AssignGlobalIDs() {
132 	reportFile << "CVC: Assigning IDs ..." << endl;
133 	deviceCount = 0;
134 	subcircuitCount = 0;
135 	netCount = 0;
136 	netParent_v.clear();
137 	netParent_v.reserve(topCircuit_p->netCount);
138 	deviceParent_v.clear();
139 	deviceParent_v.reserve(topCircuit_p->deviceCount);
140 
141 	instancePtr_v.clear();
142 	instancePtr_v.reserve(topCircuit_p->subcircuitCount);
143 	instancePtr_v.resize(topCircuit_p->subcircuitCount, NULL);
144 	instancePtr_v[0] = new CInstance;
145 	instancePtr_v[0]->AssignTopGlobalIDs(this, topCircuit_p);
146 }
147 
ResetMinSimMaxAndQueues()148 void CCvcDb::ResetMinSimMaxAndQueues() {
149 	isFixedEquivalentNet = false;
150 	ResetVector<CVirtualNetVector>(maxNet_v, netCount);
151 	maxNet_v.ClearUpdateArray();
152 	ResetVector<CVirtualNetVector>(minNet_v, netCount);
153 	minNet_v.ClearUpdateArray();
154 	ResetVector<CVirtualNetVector>(simNet_v, netCount);
155 	simNet_v.ClearUpdateArray();
156 	for (netId_t net_it = 0; net_it < netCount; net_it++) { // process all nets. before equivalency processing
157 		minNet_v.Set(net_it, net_it, 0, 0);
158 		simNet_v.Set(net_it, net_it, 0, 0);
159 		maxNet_v.Set(net_it, net_it, 0, 0);
160 	}
161 
162 	ResetVector<CStatusVector>(deviceStatus_v, deviceCount, 0);
163 //	ResetVector<CStatusVector>(netStatus_v, netCount, 0);
164 	minEventQueue.leakMap.powerPtrList_p = &cvcParameters.cvcPowerPtrList;
165 	maxEventQueue.leakMap.powerPtrList_p = &cvcParameters.cvcPowerPtrList;
166 	simEventQueue.leakMap.powerPtrList_p = &cvcParameters.cvcPowerPtrList;
167 	minEventQueue.ResetQueue(deviceCount);
168 	maxEventQueue.ResetQueue(deviceCount);
169 //	simEventQueue.ResetQueue(deviceCount);
170 //	cvcParameters.cvcPowerPtrList.Clear();
171 
172 	isFixedMinNet = isFixedSimNet = isFixedMaxNet = false;
173 	leakVoltageSet = false;
174 	isValidShortData = false;
175 
176 	for ( size_t error_it = 0; error_it < ERROR_TYPE_COUNT; error_it++ ) {
177 		errorCount[error_it] = 0;
178 	}
179 }
180 
SetMasterPower(netId_t theFirstNetId,netId_t theSecondNetId,bool & theSamePowerFlag)181 CPower * CCvcDb::SetMasterPower(netId_t theFirstNetId, netId_t theSecondNetId, bool & theSamePowerFlag) {
182 	theSamePowerFlag = false;
183 	CPower * myFirstPower_p = netVoltagePtr_v[theFirstNetId].full;
184 	CPower * mySecondPower_p = netVoltagePtr_v[theSecondNetId].full;
185 	if ( myFirstPower_p == NULL ) return mySecondPower_p;
186 	if ( mySecondPower_p == NULL ) return myFirstPower_p;
187 	if ( myFirstPower_p->IsSamePower(mySecondPower_p) ) {
188 		theSamePowerFlag = true;
189 		return NULL;
190 	}
191 	if ( myFirstPower_p->IsValidSubset(mySecondPower_p, cvcParameters.cvcShortErrorThreshold) ) {
192 		theSamePowerFlag = true;
193 		return myFirstPower_p;
194 	}
195 	if ( mySecondPower_p->IsValidSubset(myFirstPower_p, cvcParameters.cvcShortErrorThreshold) ) {
196 		theSamePowerFlag = true;
197 		return mySecondPower_p;
198 	}
199 	throw EEquivalenceError();
200 }
201 
202 // unused
MasterPowerNet(netId_t theFirstNetId,netId_t theSecondNetId)203 netId_t CCvcDb::MasterPowerNet(netId_t theFirstNetId, netId_t theSecondNetId) {
204 	if ( netVoltagePtr_v[theFirstNetId].full == NULL ) return theSecondNetId;
205 	if ( netVoltagePtr_v[theSecondNetId].full == NULL ) return theFirstNetId;
206 	throw EEquivalenceError();
207 }
208 
209 // merges 2 equivalency lists
MakeEquivalentNets(CNetMap & theNetMap,netId_t theFirstNetId,netId_t theSecondNetId,deviceId_t theDeviceId)210 void CCvcDb::MakeEquivalentNets(CNetMap & theNetMap, netId_t theFirstNetId, netId_t theSecondNetId, deviceId_t theDeviceId) {
211 	netId_t myLesserNetId, myGreaterNetId;
212 
213 	theFirstNetId = GetLeastEquivalentNet(theFirstNetId);
214 	theSecondNetId = GetLeastEquivalentNet(theSecondNetId);
215 	if ( theFirstNetId > theSecondNetId ) {
216 		myGreaterNetId = theFirstNetId;
217 		myLesserNetId = theSecondNetId;
218 	} else if ( theFirstNetId < theSecondNetId ) {
219 		myLesserNetId = theFirstNetId;
220 		myGreaterNetId = theSecondNetId;
221 	} else {
222 		return; // already equivalent
223 	}
224 	bool mySamePowerFlag;
225 	CPower * myMasterPower_p = SetMasterPower(theFirstNetId, theSecondNetId, mySamePowerFlag);
226 	netId_t myMinorNetId = ( netVoltagePtr_v[myGreaterNetId].full == myMasterPower_p ) ? myLesserNetId : myGreaterNetId;
227 	if ( mySamePowerFlag ) { // skip to short same definition
228 		if ( myMasterPower_p ) {  // ignore near subset
229 			reportFile << endl << "INFO: Power definition ignored at " << DeviceName(theDeviceId, PRINT_CIRCUIT_ON) << endl;
230 			reportFile << " net " << NetName(GetEquivalentNet(myMinorNetId)) << " (" << netVoltagePtr_v[myMinorNetId].full->definition << ")" << endl;
231 			reportFile << " shorted to " << NetName(myMasterPower_p->netId) << " (" << netVoltagePtr_v[myMasterPower_p->netId].full->definition << ")" << endl;
232 		} else {
233 			reportFile << endl << "INFO: Short between same power definitions ignored at " << DeviceName(theDeviceId, PRINT_CIRCUIT_ON);
234 			reportFile << " net " << NetName(GetEquivalentNet(theFirstNetId), PRINT_CIRCUIT_ON) << " <-> " << NetName(GetEquivalentNet(theSecondNetId), PRINT_CIRCUIT_ON) << endl;
235 			return;
236 		}
237 	}
238 	if ( myMasterPower_p ) {
239 		netVoltagePtr_v[myMinorNetId].full = myMasterPower_p;
240 		for ( auto net_pit = theNetMap[myMinorNetId].begin(); net_pit != theNetMap[myMinorNetId].end(); net_pit++ ) {
241 			netVoltagePtr_v[*net_pit].full = myMasterPower_p;
242 		}
243 	}
244 	theNetMap[myLesserNetId].push_front(myGreaterNetId);
245 	if ( theNetMap.count(myGreaterNetId) > 0 ) {
246 		theNetMap[myLesserNetId].splice_after(theNetMap[myLesserNetId].before_begin(), theNetMap[myGreaterNetId]);
247 	}
248 	equivalentNet_v[myGreaterNetId] = myLesserNetId;
249 }
250 
SetEquivalentNets()251 void CCvcDb::SetEquivalentNets() {
252 	reportFile << "CVC: Shorting switches..." << endl;
253 	isFixedEquivalentNet = false;
254 	ResetVector<CNetIdVector>(equivalentNet_v, netCount);
255 	for (netId_t net_it = 0; net_it < netCount; net_it++) {
256 		equivalentNet_v[net_it] = net_it;
257 	}
258 	CNetMap myEquivalentNetMap;
259 	for (CModelListMap::iterator keyModelListPair_pit = cvcParameters.cvcModelListMap.begin(); keyModelListPair_pit != cvcParameters.cvcModelListMap.end(); keyModelListPair_pit++) {
260 		for (CModelList::iterator model_pit = keyModelListPair_pit->second.begin(); model_pit != keyModelListPair_pit->second.end(); model_pit++) {
261 			if ( model_pit->type == SWITCH_ON ) {
262 				cout << " model " << model_pit->name << "..."; cout.flush();
263 				deviceId_t myPrintCount = 10000;
264 				deviceId_t myDeviceCount = 0;
265 				CDevice * myDevice_p = model_pit->firstDevice_p;
266 				while (myDevice_p) {
267 					CCircuit * myParent_p = myDevice_p->parent_p;
268 					deviceId_t myLocalDeviceId = myDevice_p->offset;
269 					for (instanceId_t instance_it = 0; instance_it < myParent_p->instanceId_v.size(); instance_it++) {
270 						if ( instancePtr_v[myParent_p->instanceId_v[instance_it]]->IsParallelInstance() ) continue;  // parallel instances
271 						if ( --myPrintCount <= 0 ) {
272 							cout << "."; cout.flush();
273 							myPrintCount = 10000;
274 						}
275 						CInstance * myInstance_p = instancePtr_v[myParent_p->instanceId_v[instance_it]];
276 						deviceId_t myDeviceId = myInstance_p->firstDeviceId + myLocalDeviceId;
277 						try {
278 							// short source and drain
279 							MakeEquivalentNets(myEquivalentNetMap,
280 									myInstance_p->localToGlobalNetId_v[myDevice_p->signalId_v[0]],
281 									myInstance_p->localToGlobalNetId_v[myDevice_p->signalId_v[1]],
282 									myDeviceId);
283 						}
284 						catch (const EEquivalenceError& myException) {
285 							CFullConnection myConnections;
286 							myConnections.originalSourceId = myInstance_p->localToGlobalNetId_v[myDevice_p->signalId_v[0]];
287 							myConnections.originalDrainId = myInstance_p->localToGlobalNetId_v[myDevice_p->signalId_v[1]];
288 							myConnections.masterSimSourceNet.finalNetId = GetEquivalentNet(myConnections.originalSourceId);
289 							myConnections.masterSimDrainNet.finalNetId = GetEquivalentNet(myConnections.originalDrainId);
290 							myConnections.simSourceVoltage = SimVoltage(myConnections.masterSimSourceNet.finalNetId);
291 							myConnections.simDrainVoltage = SimVoltage(myConnections.masterSimDrainNet.finalNetId);
292 							myConnections.simSourcePower_p = netVoltagePtr_v[myConnections.masterSimSourceNet.finalNetId].full;
293 							myConnections.simDrainPower_p = netVoltagePtr_v[myConnections.masterSimDrainNet.finalNetId].full;
294 							myConnections.deviceId = myDeviceId;
295 							myConnections.device_p = myDevice_p;
296 							if ( cvcParameters.cvcCircuitErrorLimit == 0 || IncrementDeviceError(myConnections.deviceId, LEAK) < cvcParameters.cvcCircuitErrorLimit ) {
297 								errorFile << "! Short Detected: " << endl;
298 								if ( myConnections.simSourceVoltage == myConnections.simDrainVoltage ) {
299 									errorFile << "Unrelated power error" << endl;
300 								}
301 								PrintDeviceWithSimConnections(myParent_p->instanceId_v[instance_it], myConnections, errorFile);
302 								errorFile << endl;
303 							}
304 						}
305 						IgnoreDevice(myInstance_p->firstDeviceId + myLocalDeviceId);
306 						myDeviceCount++;
307 					}
308 					myDevice_p = myDevice_p->nextDevice_p;
309 				}
310 				cout << endl;
311 				reportFile << "	Shorted " << myDeviceCount << " " << model_pit->name << endl;
312 			}
313 		}
314 	}
315 	cvcCircuitList.PrintAndResetCircuitErrors(this, cvcParameters.cvcCircuitErrorLimit, logFile, errorFile, "! Switch shorts");
316 	// following iterator must be int! netId_t results in infinite loop
317 	for (int net_it = equivalentNet_v.size() - 1; net_it >= 0; net_it--) {
318 		equivalentNet_v[net_it] = GetEquivalentNet(net_it);
319 		if ( netVoltagePtr_v[net_it].full && netId_t(net_it) != netVoltagePtr_v[net_it].full->netId ) netVoltagePtr_v[net_it].full = NULL;
320 	}
321 	myEquivalentNetMap.clear();
322 	isFixedEquivalentNet = true;
323 }
324 
LinkDevices()325 void CCvcDb::LinkDevices() {
326 	reportFile << "CVC: Linking devices..." << endl;
327 	ResetVector<CDeviceIdVector>(firstSource_v, netCount, UNKNOWN_DEVICE);
328 	ResetVector<CDeviceIdVector>(firstGate_v, netCount, UNKNOWN_DEVICE);
329 	ResetVector<CDeviceIdVector>(firstDrain_v, netCount, UNKNOWN_DEVICE);
330 //	ResetVector<CDeviceIdVector>(firstBulk_v, netCount, UNKNOWN_DEVICE);
331 	ResetVector<CDeviceIdVector>(nextSource_v, deviceCount, UNKNOWN_DEVICE);
332 	ResetVector<CDeviceIdVector>(nextGate_v, deviceCount, UNKNOWN_DEVICE);
333 	ResetVector<CDeviceIdVector>(nextDrain_v, deviceCount, UNKNOWN_DEVICE);
334 //	ResetVector<CDeviceIdVector>(nextBulk_v, deviceCount, UNKNOWN_DEVICE);
335 	ResetVector<CNetIdVector>(sourceNet_v, deviceCount, UNKNOWN_NET);
336 	ResetVector<CNetIdVector>(drainNet_v, deviceCount, UNKNOWN_NET);
337 	ResetVector<CNetIdVector>(gateNet_v, deviceCount, UNKNOWN_NET);
338 	ResetVector<CNetIdVector>(bulkNet_v, deviceCount, UNKNOWN_NET);
339 	ResetVector<CNetIdVector>(inverterNet_v, netCount, UNKNOWN_NET);
340 	ResetVector<vector<bool>>(highLow_v, netCount);
341 	ResetVector<vector<modelType_t>>(deviceType_v, deviceCount, UNKNOWN);
342 	ResetVector<CConnectionCountVector>(connectionCount_v, netCount);
343 	deviceId_t myDeviceCount = 0;
344 	instanceId_t myInstanceCount = 0;
345 	deviceId_t myPrintCount = 0;
346 	register netId_t mySourceNet, myDrainNet, myGateNet; //, myBulkNet;
347 	for (CCircuitPtrList::iterator circuit_ppit = cvcCircuitList.begin(); circuit_ppit != cvcCircuitList.end(); circuit_ppit++) {
348 		CCircuit * myCircuit_p = *circuit_ppit;
349 		if ( myCircuit_p->linked ) {
350 			for (instanceId_t instance_it = 0; instance_it < myCircuit_p->instanceId_v.size(); instance_it++) {
351 				if ( instancePtr_v[myCircuit_p->instanceId_v[instance_it]]->IsParallelInstance() ) continue;  // parallel instances
352 				myInstanceCount++;
353 				CInstance * myInstance_p = instancePtr_v[myCircuit_p->instanceId_v[instance_it]];
354 				for (deviceId_t device_it = 0; device_it < myCircuit_p->devicePtr_v.size(); device_it++) {
355 					myDeviceCount++;
356 					CDevice * myDevice_p = myCircuit_p->devicePtr_v[device_it];
357 					deviceId_t myDeviceId = myInstance_p->firstDeviceId + device_it;
358 					deviceType_v[myDeviceId] = myDevice_p->model_p->type;
359 					SetDeviceNets(myInstance_p, myDevice_p, sourceNet_v[myDeviceId], gateNet_v[myDeviceId], drainNet_v[myDeviceId], bulkNet_v[myDeviceId]);
360 					if ( ++myPrintCount >= 1000000 ) {
361 						cout << "	Average device/instance: " << myDeviceCount << "/" << myInstanceCount << "=" << myDeviceCount / myInstanceCount << "\r" << std::flush;
362 						myPrintCount = 0;
363 					}
364 					if ( sourceNet_v[myDeviceId] == drainNet_v[myDeviceId] ) {
365 						IgnoreDevice(myDeviceId);
366 						continue;
367 					}
368 					switch (deviceType_v[myDeviceId]) {
369 						case NMOS: case PMOS: case LDDN: case LDDP: {
370 							myGateNet = gateNet_v[myDeviceId];
371 							if ( firstGate_v[myGateNet] != UNKNOWN_DEVICE ) nextGate_v[myDeviceId] = firstGate_v[myGateNet];
372 							firstGate_v[myGateNet] = myDeviceId;
373 							connectionCount_v[myGateNet].gateCount++;
374 /*
375 							myBulkNet = bulkNet_v[myDeviceId];
376 							if ( myBulkNet != UNKNOWN_NET ) {
377 								if ( firstBulk_v[myBulkNet] != UNKNOWN_DEVICE ) nextBulk_v[myDeviceId] = firstBulk_v[myBulkNet];
378 								firstBulk_v[myBulkNet] = myDeviceId;
379 								connectionCount_v[myBulkNet].bulkCount++;
380 							}
381 */
382 						}
383 						//continues
384 						case FUSE_ON: case FUSE_OFF: case RESISTOR: {
385 							modelType_t myDeviceType = deviceType_v[myDeviceId];
386 							if ( IsNmos_(myDeviceType) ) myDeviceType = NMOS; // LDDN -> NMOS
387 							if ( IsPmos_(myDeviceType) ) myDeviceType = PMOS; // LDDP -> PMOS
388 							mySourceNet = sourceNet_v[myDeviceId];
389 							if ( firstSource_v[mySourceNet] != UNKNOWN_DEVICE ) nextSource_v[myDeviceId] = firstSource_v[mySourceNet];
390 							firstSource_v[mySourceNet] = myDeviceId;
391 							connectionCount_v[mySourceNet].sourceCount++;
392 							connectionCount_v[mySourceNet].sourceDrainType[myDeviceType] = true;
393 							myDrainNet = drainNet_v[myDeviceId];
394 //							if ( myDrainNet != mySourceNet ) { // avoid double counting mos caps and inactive res
395 							assert(myDrainNet != mySourceNet);  // previously ignored
396 							if ( firstDrain_v[myDrainNet] != UNKNOWN_DEVICE ) nextDrain_v[myDeviceId] = firstDrain_v[myDrainNet];
397 							firstDrain_v[myDrainNet] = myDeviceId;
398 							connectionCount_v[myDrainNet].drainCount++;
399 							connectionCount_v[myDrainNet].sourceDrainType[myDeviceType] = true;
400 //							}
401 							break; }
402 						case SWITCH_ON: {
403 //							MakeEquivalentNets(mySourceId, myDrainId);
404 							break; }
405 						case BIPOLAR:	case DIODE:	case SWITCH_OFF: case CAPACITOR: {
406 							IgnoreDevice(myDeviceId);
407 							break; }
408 						default: {
409 							myDevice_p->model_p->Print();
410 							throw EUnknownModel();
411 						}
412 					}
413 				}
414 			}
415 		}
416 	}
417 	cout << endl;
418 }
419 
SetDeviceModels()420 returnCode_t CCvcDb::SetDeviceModels() {
421 	set<string> myErrorModelSet;
422 	reportFile << "CVC: Setting models ..." << endl;
423 	parameterResistanceMap.clear();
424 	parameterResistanceMap.reserve(cvcCircuitList.parameterText.Entries());
425 	bool myModelError = false;
426 	for (CCircuitPtrList::iterator circuit_ppit = cvcCircuitList.begin(); circuit_ppit != cvcCircuitList.end(); circuit_ppit++) {
427 		CCircuit * myCircuit_p = *circuit_ppit;
428 		if ( myCircuit_p->linked ) {
429 			for (deviceId_t device_it = 0; device_it < myCircuit_p->devicePtr_v.size(); device_it++) {
430 				CDevice * myDevice_p = myCircuit_p->devicePtr_v[device_it];
431 				myDevice_p->model_p = cvcParameters.cvcModelListMap.FindModel(myCircuit_p->name, myDevice_p->parameters, parameterResistanceMap, logFile);
432 				if ( myDevice_p->model_p == NULL ) {
433 					if ( ! gSetup_cvc ) {
434 						reportFile << "ERROR: No model match " << (*circuit_ppit)->name << "/" << myDevice_p->name;
435 						reportFile << " " << myDevice_p->parameters << endl;
436 					}
437 					string	myParameterString = trim_(string(myDevice_p->parameters));
438 					myErrorModelSet.insert(myParameterString.substr(0, myParameterString.find(" ", 2)));
439 					myModelError = true;
440 				} else if ( ! myDevice_p->model_p->validModel ) {
441 					reportFile << "ERROR: Invalid model definition for " << (*circuit_ppit)->name << "/" << myDevice_p->name;
442 					reportFile << " " << myDevice_p->parameters << endl;
443 					string	myParameterString = trim_(string(myDevice_p->parameters));
444 					myErrorModelSet.insert(myParameterString.substr(0, myParameterString.find(" ", 2)));
445 					myModelError = true;
446 				} else {
447 					if ( myDevice_p->model_p->firstDevice_p != NULL ) {
448 						myDevice_p->nextDevice_p = myDevice_p->model_p->firstDevice_p;
449 					}
450 					myDevice_p->model_p->firstDevice_p = myDevice_p;
451 					if ( myDevice_p->model_p->baseType == "M" && ( myDevice_p->model_p->type == FUSE_ON || myDevice_p->model_p->type == FUSE_OFF ) ) {
452 						if ( myDevice_p->signalId_v[0] != myDevice_p->signalId_v[2] ) {
453 							reportFile << "ERROR: mosfet used as fuse must have source=drain: " << (*circuit_ppit)->name << "/" << myDevice_p->name << endl;
454 							myModelError = true;
455 						} else if ( cvcParameters.cvcSOI && myDevice_p->signalId_v[0] != myDevice_p->signalId_v[3] ) {
456 							reportFile << "ERROR: mosfet used as fuse must have source=drain=bulk: " << (*circuit_ppit)->name << "/" << myDevice_p->name << endl;
457 							myModelError = true;
458 						}
459 					}
460 				}
461 			}
462 		}
463 	}
464 	isDeviceModelSet = true;
465 	if ( myModelError ) {
466 		if ( ! myErrorModelSet.empty() ) {
467 			reportFile << "Missing models" << endl << endl;
468 			for ( auto model_pit = myErrorModelSet.begin(); model_pit != myErrorModelSet.end(); model_pit++) {
469 				reportFile << model_pit->substr(2) << " " << model_pit->substr(0,1) << endl;
470 			}
471 		}
472 		if ( ! gSetup_cvc ) {
473 			reportFile << endl << "ERROR: Model file problem" << endl;
474 		}
475 		return(FAIL);
476 	} else {
477 		return (cvcParameters.cvcModelListMap.SetVoltageTolerances(reportFile, cvcParameters.cvcPowerMacroPtrMap));
478 	}
479 }
480 
OverrideFuses()481 void CCvcDb::OverrideFuses() {
482 	if ( IsEmpty(cvcParameters.cvcFuseFilename) ) return;
483 	ifstream myFuseFile(cvcParameters.cvcFuseFilename);
484 	if ( myFuseFile.fail() ) {
485 		throw EFatalError("Could not open fuse file: " + cvcParameters.cvcFuseFilename);
486 	}
487 	string myFuseName, myFuseStatus;
488 	bool myFuseError = false;
489 	deviceId_t myDeviceId;
490 	string myInputLine;
491 	while ( getline(myFuseFile, myInputLine) ) {
492 		if ( myInputLine.length() == 0 ) continue;
493 		if ( myInputLine.substr(0, 1) == "#" ) continue;
494 		myInputLine = trim_(myInputLine);
495 		stringstream myFuseStringStream(myInputLine);
496 		myFuseStringStream >> myFuseName >> myFuseStatus;
497 		if ( myFuseStringStream.fail() ) {
498 			myFuseError = true;
499 			continue;
500 		}
501 		myDeviceId = FindDevice(0, myFuseName);
502 		if ( myFuseStatus != "fuse_on" && myFuseStatus != "fuse_off" ) {
503 			myFuseError = true;
504 		}
505 		if ( myDeviceId == UNKNOWN_DEVICE ) {
506 			myFuseError = true;
507 		} else {
508 			CInstance * myInstance_p = instancePtr_v[deviceParent_v[myDeviceId]];
509 			CCircuit * myCircuit_p = myInstance_p->master_p;
510 			CModel * myModel_p = myCircuit_p->devicePtr_v[myDeviceId - myInstance_p->firstDeviceId]->model_p;
511 			if ( myModel_p->type != FUSE_ON && myModel_p->type != FUSE_OFF ) {
512 				myFuseError = true;
513 			}
514 			if ( myFuseError == false ) {
515 				if ( myModel_p->type == FUSE_ON && myFuseStatus == "fuse_off" ) {
516 					deviceType_v[myDeviceId] = FUSE_OFF;
517 					logFile << "INFO: fuse override ON->OFF " << myFuseName << endl;
518 				} else if ( myModel_p->type == FUSE_OFF && myFuseStatus == "fuse_on" ) {
519 					deviceType_v[myDeviceId] = FUSE_ON;
520 					logFile << "INFO: fuse override OFF->ON " << myFuseName << endl;
521 				}
522 			}
523 		}
524 	}
525 	myFuseFile.close();
526 	if ( myFuseError ) {
527 		logFile << "ABORT: unexpected fuse error" << endl;
528 		throw EFatalError("unexpected fuse error");
529 	}
530 	return;
531 }
532 
FindUniqueSourceDrainConnectedDevice(netId_t theNetId)533 deviceId_t CCvcDb::FindUniqueSourceDrainConnectedDevice(netId_t theNetId) {
534 	deviceId_t myResultDeviceId = UNKNOWN_DEVICE;
535 	for ( deviceId_t device_it = firstSource_v[theNetId]; device_it != UNKNOWN_DEVICE; device_it = nextSource_v[device_it] ) {
536 		if ( deviceType_v[device_it] == RESISTOR && ! deviceStatus_v[device_it][SIM_INACTIVE] ) {
537 			if ( myResultDeviceId != UNKNOWN_DEVICE ) throw EDatabaseError("FindUniqueSourceDrainConnectedDevice: " + NetName(theNetId));
538 			myResultDeviceId = device_it;
539 		}
540 	}
541 	for ( deviceId_t device_it = firstDrain_v[theNetId]; device_it != UNKNOWN_DEVICE; device_it = nextDrain_v[device_it] ) {
542 		if ( deviceType_v[device_it] == RESISTOR && ! deviceStatus_v[device_it][SIM_INACTIVE] ) {
543 			if ( myResultDeviceId != UNKNOWN_DEVICE ) throw EDatabaseError("FindUniqueSourceDrainConnectedDevice: " + NetName(theNetId));
544 			myResultDeviceId = device_it;
545 		}
546 	}
547 	return myResultDeviceId;
548 }
549 
MergeConnectionListByTerminals(netId_t theFromNet,netId_t theToNet,deviceId_t theIgnoreDeviceId,CDeviceIdVector & theFirstDevice_v,CDeviceIdVector & theNextDevice_v,CNetIdVector & theTerminal_v)550 void CCvcDb::MergeConnectionListByTerminals(netId_t theFromNet, netId_t theToNet, deviceId_t theIgnoreDeviceId,
551 		CDeviceIdVector& theFirstDevice_v, CDeviceIdVector& theNextDevice_v, CNetIdVector& theTerminal_v) {
552 	deviceId_t myNextDevice;
553 	for ( deviceId_t device_it = theFirstDevice_v[theFromNet]; device_it != UNKNOWN_DEVICE; device_it = myNextDevice) {
554 		myNextDevice = theNextDevice_v[device_it];
555 		theNextDevice_v[device_it] = theFirstDevice_v[theToNet];
556 		theFirstDevice_v[theToNet] = device_it;
557 		theTerminal_v[device_it] = theToNet;
558 	}
559 	theFirstDevice_v[theFromNet] = UNKNOWN_DEVICE;
560 }
561 
DumpConnectionList(string theHeading,CDeviceIdVector & theFirstDevice_v,CDeviceIdVector & theNextDevice_v)562 void CCvcDb::DumpConnectionList(string theHeading, CDeviceIdVector& theFirstDevice_v, CDeviceIdVector& theNextDevice_v) {
563 	deviceId_t myDeviceId;
564 	cout << theHeading << endl;
565 	for ( netId_t net_it = 0; net_it < theFirstDevice_v.size(); net_it++) {
566 		if ( theFirstDevice_v[net_it] == UNKNOWN_DEVICE ) continue;
567 		cout << "  " << net_it << ":" << NetName(net_it) << " => ";
568 		myDeviceId = theFirstDevice_v[net_it];
569 		while ( myDeviceId != UNKNOWN_DEVICE ) {
570 			cout << myDeviceId << ":" << DeviceName(myDeviceId) << " -> ";
571 			myDeviceId = theNextDevice_v[myDeviceId];
572 		}
573 		cout << "end" << endl;
574 	}
575 }
576 
DumpConnectionLists(string theHeading)577 void CCvcDb::DumpConnectionLists(string theHeading) {
578 	cout << "Connection list dump " << theHeading << endl;
579 	DumpConnectionList(" Gate connections", firstGate_v, nextGate_v);
580 	DumpConnectionList(" Source connections", firstSource_v, nextSource_v);
581 	DumpConnectionList(" Drain connections", firstDrain_v, nextDrain_v);
582 //	DumpConnectionList(" Bulk connections", firstBulk_v, nextBulk_v);
583 	cout << "Connection list dump end" << endl;
584 }
585 
RecountConnections(netId_t theNetId,CDeviceIdVector & theFirstDevice_v,CDeviceIdVector & theNextDevice_v)586 deviceId_t CCvcDb::RecountConnections(netId_t theNetId, CDeviceIdVector& theFirstDevice_v, CDeviceIdVector& theNextDevice_v) {
587 	deviceId_t myCount = 0;
588 	for ( deviceId_t device_it = theFirstDevice_v[theNetId]; device_it != UNKNOWN_DEVICE; device_it = theNextDevice_v[device_it] ) {
589 		myCount++;
590 	}
591 	return myCount;
592 }
593 
MergeConnectionLists(netId_t theFromNet,netId_t theToNet,deviceId_t theIgnoreDeviceId)594 void CCvcDb::MergeConnectionLists(netId_t theFromNet, netId_t theToNet, deviceId_t theIgnoreDeviceId) {
595 	MergeConnectionListByTerminals(theFromNet, theToNet, theIgnoreDeviceId, firstGate_v, nextGate_v, gateNet_v);
596 	MergeConnectionListByTerminals(theFromNet, theToNet, theIgnoreDeviceId, firstSource_v, nextSource_v, sourceNet_v);
597 	MergeConnectionListByTerminals(theFromNet, theToNet, theIgnoreDeviceId, firstDrain_v, nextDrain_v, drainNet_v);
598 	// Source/drain counts handled in calling routine
599 	connectionCount_v[theFromNet].gateCount = RecountConnections(theFromNet, firstGate_v, nextGate_v);
600 	connectionCount_v[theToNet].gateCount = RecountConnections(theToNet, firstGate_v, nextGate_v);
601 	connectionCount_v[theToNet].sourceDrainType |= connectionCount_v[theFromNet].sourceDrainType;
602 }
603 
ShortNonConductingResistor(deviceId_t theDeviceId,netId_t theFirstNet,netId_t theSecondNet,shortDirection_t theDirection)604 void CCvcDb::ShortNonConductingResistor(deviceId_t theDeviceId, netId_t theFirstNet, netId_t theSecondNet, shortDirection_t theDirection) {
605 	CCircuit * myParent_p = instancePtr_v[deviceParent_v[theDeviceId]]->master_p;
606 	deviceId_t myLocalDeviceId = theDeviceId - instancePtr_v[deviceParent_v[theDeviceId]]->firstDeviceId;
607 	CDevice * myDevice_p = myParent_p->devicePtr_v[myLocalDeviceId];
608 	deviceStatus_v[theDeviceId][MAX_INACTIVE] = true;
609 	deviceStatus_v[theDeviceId][MIN_INACTIVE] = true;
610 	deviceStatus_v[theDeviceId][SIM_INACTIVE] = true;
611 	myDevice_p->sourceDrainSet = true;
612 
613 	if ( theDirection == SOURCE_TO_MASTER_DRAIN ) {
614 		connectionCount_v[theFirstNet].sourceCount--;
615 		connectionCount_v[theSecondNet].drainCount--;
616 	} else if ( theDirection == DRAIN_TO_MASTER_SOURCE ){
617 		connectionCount_v[theFirstNet].drainCount--;
618 		connectionCount_v[theSecondNet].sourceCount--;
619 	}
620 
621 	minNet_v.Set(theFirstNet, theSecondNet, 1, ++minNet_v.lastUpdate);
622 	simNet_v.Set(theFirstNet, theSecondNet, 1, ++simNet_v.lastUpdate);
623 	maxNet_v.Set(theFirstNet, theSecondNet, 1, ++maxNet_v.lastUpdate);
624 	MergeConnectionLists(theFirstNet, theSecondNet, theDeviceId);
625 	assert(connectionCount_v[theFirstNet].SourceDrainCount() == 0);
626 	// propagate
627 	if ( connectionCount_v[theSecondNet].SourceDrainCount() == 1 && netVoltagePtr_v[theSecondNet].full == NULL ) {
628 		deviceId_t myConnectedDeviceId = FindUniqueSourceDrainConnectedDevice(theSecondNet);
629 		if ( myConnectedDeviceId != UNKNOWN_DEVICE ) {
630 			if ( sourceNet_v[myConnectedDeviceId] == theSecondNet ) {
631 				ShortNonConductingResistor(myConnectedDeviceId, sourceNet_v[myConnectedDeviceId], drainNet_v[myConnectedDeviceId], SOURCE_TO_MASTER_DRAIN);
632 			} else if ( drainNet_v[myConnectedDeviceId] == theSecondNet ) {
633 				ShortNonConductingResistor(myConnectedDeviceId, drainNet_v[myConnectedDeviceId], sourceNet_v[myConnectedDeviceId], DRAIN_TO_MASTER_SOURCE);
634 			} else throw EDatabaseError("ShortNonConductingResistor: " + DeviceName(myConnectedDeviceId));
635 
636 		}
637 	}
638 }
639 
ShortNonConductingResistors()640 void CCvcDb::ShortNonConductingResistors() {
641 	reportFile << "CVC: Shorting non conducting resistors..." << endl;
642 //  TODO: process by model?
643 	for (deviceId_t device_it = 0; device_it < deviceCount; device_it++ ) {
644 		if ( deviceType_v[device_it] == RESISTOR && ! deviceStatus_v[device_it][SIM_INACTIVE] ) {
645 			if ( sourceNet_v[device_it] >= topCircuit_p->portCount  // don't consider input nets
646 					&& connectionCount_v[sourceNet_v[device_it]].SourceDrainCount() == 1  // only one leak path
647 					&& netVoltagePtr_v[sourceNet_v[device_it]].full == NULL ) {  // not defined
648 				ShortNonConductingResistor(device_it, sourceNet_v[device_it], drainNet_v[device_it], SOURCE_TO_MASTER_DRAIN);
649 			} else if ( drainNet_v[device_it] >= topCircuit_p->portCount  // don't consider ports
650 					&& connectionCount_v[drainNet_v[device_it]].SourceDrainCount() == 1  // only one leak path
651 					&& netVoltagePtr_v[drainNet_v[device_it]].full == NULL ) {  // not defined
652 				ShortNonConductingResistor(device_it, drainNet_v[device_it], sourceNet_v[device_it], DRAIN_TO_MASTER_SOURCE);
653 			} else {
654 				continue;
655 			}
656 		}
657 	}
658 }
659 
SetResistorVoltagesForMosSwitches()660 void CCvcDb::SetResistorVoltagesForMosSwitches() {
661 	for (CPowerPtrList::iterator power_ppit = cvcParameters.cvcPowerPtrList.begin(); power_ppit != cvcParameters.cvcPowerPtrList.end(); power_ppit++) {
662 		// should only be defined voltages at this time.
663 		CPower * myPower_p = * power_ppit;
664 //		if ( ! myPower_p->type[EXPECTED_ONLY_BIT] ) {
665 		netId_t myNetId = myPower_p->netId;
666 		if ( ! myPower_p->type[POWER_BIT] ) continue;  // only process power
667 		for (deviceId_t device_it = firstSource_v[myNetId]; device_it != UNKNOWN_DEVICE; device_it = nextSource_v[device_it]) {
668 			switch(deviceType_v[device_it]) {
669 			case NMOS: case PMOS: case LDDN: case LDDP:
670 				break;
671 			default:
672 				break;
673 			}
674 		}
675 	}
676 }
677 
FindInstanceIds(string theHierarchy,instanceId_t theParent)678 forward_list<instanceId_t> CCvcDb::FindInstanceIds(string theHierarchy, instanceId_t theParent) {
679 	list<string> * myHierarchyList_p = SplitHierarchy(theHierarchy);
680 	forward_list<instanceId_t> mySearchInstanceIdList;
681 	string	myInstanceName = "";
682 	string	myUnmatchedInstance = "";
683 	try {
684 		for ( auto hierarchy_pit = myHierarchyList_p->begin(); hierarchy_pit != myHierarchyList_p->end(); hierarchy_pit++ ) {
685 			if ( (*hierarchy_pit).empty() ) {
686 				mySearchInstanceIdList.push_front(0);
687 			} else if ( hierarchy_pit->substr(0,2) == "*(" && hierarchy_pit->substr(hierarchy_pit->size() - 1, 1) == ")" ) { // circuit search
688 				if ( ! IsEmpty(myUnmatchedInstance) ) throw out_of_range("invalid hierarchy: " + myUnmatchedInstance + HIERARCHY_DELIMITER + *hierarchy_pit ); // no circuit searches with pending hierarchy
689 				string myCellName = theHierarchy.substr(2, hierarchy_pit->size() - 3);
690 				regex mySearchPattern(FuzzyFilter(myCellName));
691 				bool myFoundMatch = false;
692 				if ( mySearchInstanceIdList.empty() ) { // global circuit search
693 					try { // exact match
694 						text_t myCellText = cvcCircuitList.cdlText.GetTextAddress(myCellName);
695 						CCircuit * myCircuit = cvcCircuitList.circuitNameMap.at(myCellText);
696 						myFoundMatch = true;
697 						for ( auto instance_pit = myCircuit->instanceId_v.begin(); instance_pit != myCircuit->instanceId_v.end(); instance_pit++ ) {
698 							mySearchInstanceIdList.push_front(*instance_pit);
699 						}
700 					}
701 					catch (const out_of_range& oor_exception) { // check for regex match
702 						for ( auto circuit_pit = cvcCircuitList.begin(); circuit_pit != cvcCircuitList.end(); circuit_pit++ ) {
703 							if ( regex_match((*circuit_pit)->name, mySearchPattern) ) {
704 								for ( auto instance_pit = (*circuit_pit)->instanceId_v.begin(); instance_pit != (*circuit_pit)->instanceId_v.end(); instance_pit++ ) {
705 									mySearchInstanceIdList.push_front(*instance_pit);
706 									myFoundMatch = true;
707 								}
708 							}
709 						}
710 					}
711 				} else { // local circuit search
712 					forward_list<instanceId_t> myNewSearchList;
713 					for (auto instanceId_pit = mySearchInstanceIdList.begin(); instanceId_pit != mySearchInstanceIdList.end(); instanceId_pit++) {
714 						if ( instancePtr_v[*instanceId_pit]->IsParallelInstance() ) continue;  // skip parallel instances
715 						instanceId_t myParentsFirstSubcircuitId = instancePtr_v[*instanceId_pit]->firstSubcircuitId;
716 						CCircuit * myCircuit = instancePtr_v[*instanceId_pit]->master_p;
717 						for ( size_t subcircuit_it = 0; subcircuit_it < myCircuit->subcircuitPtr_v.size(); subcircuit_it++ ) {
718 							try { // exact match
719 								text_t myCellText = cvcCircuitList.cdlText.GetTextAddress(myCellName);
720 								if ( myCircuit->subcircuitPtr_v[subcircuit_it]->masterName == myCellText ) {
721 									myNewSearchList.push_front(myParentsFirstSubcircuitId + subcircuit_it);
722 									myFoundMatch = true;
723 								}
724 							}
725 							catch (const out_of_range& oor_exception) { // check for regex match
726 								if ( regex_match(myCircuit->subcircuitPtr_v[subcircuit_it]->masterName, mySearchPattern) ) {
727 									myNewSearchList.push_front(myParentsFirstSubcircuitId + subcircuit_it);
728 									myFoundMatch = true;
729 								}
730 							}
731 						}
732 					}
733 					mySearchInstanceIdList.clear();
734 					mySearchInstanceIdList = myNewSearchList;
735 				}
736 				if ( ! myFoundMatch ) throw out_of_range("invalid hierarchy: missing circuit " + myCellName);
737 			} else {  // instance search
738 				if ( mySearchInstanceIdList.empty() ) throw out_of_range("invalid hierarchy: " + *hierarchy_pit); // no relative path searches
739 				if ( ! IsEmpty(myUnmatchedInstance) ) {
740 					myInstanceName = myUnmatchedInstance + HIERARCHY_DELIMITER + *hierarchy_pit;
741 				} else {
742 					myInstanceName = *hierarchy_pit;
743 				}
744 				regex mySearchPattern(FuzzyFilter(myInstanceName));
745 				forward_list<instanceId_t> myNewSearchList;
746 				bool myFoundMatch = false;
747 				for (auto instanceId_pit = mySearchInstanceIdList.begin(); instanceId_pit != mySearchInstanceIdList.end(); instanceId_pit++) {
748 					if ( instancePtr_v[*instanceId_pit]->IsParallelInstance() ) continue;  // skip parallel instances
749 					instanceId_t myParentsFirstSubcircuitId = instancePtr_v[*instanceId_pit]->firstSubcircuitId;
750 					CCircuit * myCircuit = instancePtr_v[*instanceId_pit]->master_p;
751 					for ( auto instance_pit = myCircuit->subcircuitPtr_v.begin(); instance_pit != myCircuit->subcircuitPtr_v.end(); instance_pit++ ) {
752 						try { // exact match
753 							text_t myInstanceText = cvcCircuitList.cdlText.GetTextAddress(myInstanceName);
754 							if ( (*instance_pit)->name == myInstanceText ) {
755 								myNewSearchList.push_front(myParentsFirstSubcircuitId + (*instance_pit)->offset);
756 								myFoundMatch = true;
757 							}
758 						}
759 						catch (const out_of_range& oor_exception) { // check for regex match
760 							if ( regex_match((*instance_pit)->name, mySearchPattern) ) {
761 								myNewSearchList.push_front(myParentsFirstSubcircuitId + (*instance_pit)->offset);
762 								myFoundMatch = true;
763 							}
764 						}
765 					}
766 				}
767 				if ( myFoundMatch ) {
768 					myUnmatchedInstance = "";
769 					mySearchInstanceIdList.clear();
770 					mySearchInstanceIdList = myNewSearchList;
771 				} else {
772 					myUnmatchedInstance = myInstanceName;
773 				}
774 			}
775 		}
776 		if ( theParent != 0 ) {
777 			// only use instances in parent
778 			forward_list<instanceId_t> myNewSearchList;
779 			for (auto instanceId_pit = mySearchInstanceIdList.begin(); instanceId_pit != mySearchInstanceIdList.end(); instanceId_pit++) {
780 				if ( IsSubcircuitOf(*instanceId_pit, theParent) ) {
781 					myNewSearchList.push_front(*instanceId_pit);
782 				}
783 			}
784 			mySearchInstanceIdList = myNewSearchList;
785 		}
786 	}
787 	catch (const out_of_range& oor_exception) {
788 		reportFile << "ERROR: could not expand instance " << theHierarchy << " " << oor_exception.what() << endl;
789 		mySearchInstanceIdList.clear();
790 	}
791 	catch (const regex_error& myError) {
792 		reportFile << "regex_error: " << RegexErrorString(myError.code()) << endl;
793 		mySearchInstanceIdList.clear();
794 	}
795 	if ( myUnmatchedInstance != "" ) {  // not a complete match
796 		mySearchInstanceIdList.clear();
797 	}
798 	delete myHierarchyList_p;
799 	return mySearchInstanceIdList;
800 }
801 
FindUniqueNetIds(string thePowerSignal,instanceId_t theParent)802 set<netId_t> * CCvcDb::FindUniqueNetIds(string thePowerSignal, instanceId_t theParent) {
803 	/// Returns a list of unique net ids for expanded signals. cells, instances and signals may include wildcards.
804 	list<string> * myHierarchyList_p = SplitHierarchy(thePowerSignal);
805 	set<netId_t> * myNetIdSet_p = new set<netId_t>;
806 	forward_list<instanceId_t> mySearchInstanceIdList;
807 	string	myInstanceName = "";
808 	string	mySignalName = "";
809 	string	myUnmatchedInstance = "";
810 	size_t mySearchEnd = thePowerSignal.length();
811 	do {
812 		mySearchEnd = thePowerSignal.find_last_of(cvcParameters.cvcHierarchyDelimiters, mySearchEnd-1);
813 		if (mySearchEnd > thePowerSignal.length()) {
814 			mySearchEnd = 0;
815 			myInstanceName = "";
816 			mySignalName = thePowerSignal;
817 		} else {
818 			myInstanceName = thePowerSignal.substr(0, mySearchEnd);
819 			mySignalName = thePowerSignal.substr(mySearchEnd+1);
820 		}
821 		mySearchInstanceIdList = FindInstanceIds(myInstanceName, theParent);
822 	} while( mySearchInstanceIdList.empty() && myInstanceName != "" );
823 	try {
824 		list<string> * myNetNameList_p = ExpandBusNet(mySignalName);
825 		bool myCheckTopPort = false;
826 		if ( mySignalName == thePowerSignal ) { // top port
827 			myCheckTopPort = true;
828 		}
829 		bool myFoundNetMatch = false;
830 		for ( auto myNetName_pit = myNetNameList_p->begin(); myNetName_pit != myNetNameList_p->end(); myNetName_pit++ ) {
831 			string myNetName = *myNetName_pit;
832 			if ( ! myUnmatchedInstance.empty() ) {
833 				myNetName = myUnmatchedInstance + HIERARCHY_DELIMITER + myNetName;
834 			}
835 			string myFuzzyFilter = FuzzyFilter(myNetName);
836 			regex mySearchPattern(myFuzzyFilter);
837 			netId_t myNetId;
838 			bool myExactMatch = true;
839 //			bool myFuzzySearch = (myFuzzyFilter.find_first_of("^$.*+?()[]{}|\\") < myFuzzyFilter.npos);
840 			text_t mySignalText;
841 			try {
842 				mySignalText = cvcCircuitList.cdlText.GetTextAddress(myNetName);
843 			}
844 			catch (const out_of_range& oor_exception) {
845 				myExactMatch = false;
846 			}
847 			for (auto instanceId_pit = mySearchInstanceIdList.begin(); instanceId_pit != mySearchInstanceIdList.end(); instanceId_pit++) {
848 				if ( instancePtr_v[*instanceId_pit]->IsParallelInstance() ) {
849 					cout << "Warning: can not define nets in parallel instances " << thePowerSignal << endl;
850 					continue;
851 				}
852 				CTextNetIdMap * mySignalIdMap_p = &(instancePtr_v[*instanceId_pit]->master_p->localSignalIdMap);
853 				if ( myExactMatch ) { // exact match
854 					if ( mySignalIdMap_p->count(mySignalText) > 0 ) {
855 						myNetId = instancePtr_v[*instanceId_pit]->localToGlobalNetId_v[mySignalIdMap_p->at(mySignalText)];
856 						if ( myCheckTopPort && *instanceId_pit == 0 && myNetId >= topCircuit_p->portCount ) continue; // top signals that are not ports posing as ports
857 						if ( ! myCheckTopPort && *instanceId_pit == 0 && myNetId < topCircuit_p->portCount ) continue; // top signals that should be ports
858 						myNetIdSet_p->insert(myNetId);
859 						myFoundNetMatch = true;
860 					}
861 				} else {
862 					for ( auto signalIdPair_pit = mySignalIdMap_p->begin(); signalIdPair_pit != mySignalIdMap_p->end(); signalIdPair_pit++ ) {
863 						if ( regex_match(signalIdPair_pit->first, mySearchPattern) ) {
864 							myNetId = instancePtr_v[*instanceId_pit]->localToGlobalNetId_v[signalIdPair_pit->second];
865 							if ( myCheckTopPort && *instanceId_pit == 0 && myNetId >= topCircuit_p->portCount ) continue; // top signals that are not ports posing as ports
866 							if ( ! myCheckTopPort && *instanceId_pit == 0 && myNetId < topCircuit_p->portCount ) continue; // top signals that should be ports
867 							myNetIdSet_p->insert(myNetId);
868 							myFoundNetMatch = true;
869 						}
870 					}
871 				}
872 			}
873 			if ( ! myFoundNetMatch ) throw out_of_range("signal " + myNetName + " not found");
874 		}
875 		delete myNetNameList_p;
876 		if ( ! myFoundNetMatch ) throw out_of_range("signal not found");
877 	}
878 	catch (const out_of_range& oor_exception) {
879 		reportFile << "ERROR: could not expand signal " << thePowerSignal << " " << oor_exception.what() << endl;
880 		myNetIdSet_p->clear();
881 	}
882 	catch (const regex_error& myError) {
883 		reportFile << "regex_error: " << RegexErrorString(myError.code()) << endl;
884 		myNetIdSet_p->clear();
885 	}
886 	delete myHierarchyList_p;
887 	return myNetIdSet_p;
888 }
889 
FindNetIds(string thePowerSignal,instanceId_t theParent)890 forward_list<netId_t> * CCvcDb::FindNetIds(string thePowerSignal, instanceId_t theParent) {
891 	/// Returns a list of non-unique net ids for expanded signals. cells and instances may include wildcards.
892 	list<string> * myHierarchyList_p = SplitHierarchy(thePowerSignal);
893 	forward_list<netId_t> * myNetIdList_p = new forward_list<netId_t>;
894 	forward_list<instanceId_t> mySearchInstanceIdList;
895 	string	myInstanceName = "";
896 	string	mySignalName = "";
897 	string	myUnmatchedInstance = "";
898 	size_t mySearchEnd = thePowerSignal.length();
899 	do {
900 		mySearchEnd = thePowerSignal.find_last_of(cvcParameters.cvcHierarchyDelimiters, mySearchEnd-1);
901 		if (mySearchEnd > thePowerSignal.length()) {
902 			mySearchEnd = 0;
903 			myInstanceName = "";
904 			mySignalName = thePowerSignal;
905 		} else {
906 			myInstanceName = thePowerSignal.substr(0, mySearchEnd);
907 			mySignalName = thePowerSignal.substr(mySearchEnd+1);
908 		}
909 		mySearchInstanceIdList = FindInstanceIds(myInstanceName, theParent);
910 	} while( mySearchInstanceIdList.empty() && myInstanceName != "" );
911 	try {
912 		bool myCheckTopPort = false;
913 		if ( mySignalName == thePowerSignal ) { // top port
914 			myCheckTopPort = true;
915 		}
916 		string myNetName = mySignalName;
917 		if ( ! myUnmatchedInstance.empty() ) {
918 			myNetName = myUnmatchedInstance + HIERARCHY_DELIMITER + myNetName;
919 		}
920 		netId_t myNetId;
921 		text_t mySignalText;
922 		try {
923 			mySignalText = cvcCircuitList.cdlText.GetTextAddress(myNetName);
924 			for (auto instanceId_pit = mySearchInstanceIdList.begin(); instanceId_pit != mySearchInstanceIdList.end(); instanceId_pit++) {
925 				if ( instancePtr_v[*instanceId_pit]->IsParallelInstance() ) {
926 					cout << "Warning: can not define nets in parallel instances " << thePowerSignal << endl;
927 					continue;
928 
929 				}
930 				CTextNetIdMap * mySignalIdMap_p = &(instancePtr_v[*instanceId_pit]->master_p->localSignalIdMap);
931 				if ( mySignalIdMap_p->count(mySignalText) > 0 ) {
932 					myNetId = instancePtr_v[*instanceId_pit]->localToGlobalNetId_v[mySignalIdMap_p->at(mySignalText)];
933 					if ( myCheckTopPort && *instanceId_pit == 0 && myNetId >= topCircuit_p->portCount ) continue; // top signals that are not ports posing as ports
934 					if ( ! myCheckTopPort && *instanceId_pit == 0 && myNetId < topCircuit_p->portCount ) continue; // top signals that should be ports
935 					myNetIdList_p->push_front(myNetId);
936 				}
937 			}
938 		}
939 		catch (const out_of_range& oor_exception) {
940 			throw out_of_range("signal " + myNetName + " not found");
941 		}
942 	}
943 	catch (const out_of_range& oor_exception) {
944 		reportFile << "ERROR: could not expand signal " << thePowerSignal << " " << oor_exception.what() << endl;
945 		myNetIdList_p->clear();
946 	}
947 	catch (const regex_error& myError) {
948 		reportFile << "regex_error: " << RegexErrorString(myError.code()) << endl;
949 		myNetIdList_p->clear();
950 	}
951 	delete myHierarchyList_p;
952 	return myNetIdList_p;
953 }
954 
SetModePower()955 returnCode_t CCvcDb::SetModePower() {
956 	bool myPowerError = false;
957 	netVoltagePtr_v.ResetPowerPointerVector(netCount);
958 	ResetVector<CStatusVector>(netStatus_v, netCount, 0);
959 	CPowerPtrList::iterator power_ppit = cvcParameters.cvcPowerPtrList.begin();
960 	// Normal power definitions
961 	while( power_ppit != cvcParameters.cvcPowerPtrList.end() ) {
962 		CPower * myPower_p = *power_ppit;
963 		set<netId_t> * myNetIdList = FindUniqueNetIds(string(myPower_p->powerSignal())); // expands buses and hierarchy
964 		for (auto netId_pit = myNetIdList->begin(); netId_pit != myNetIdList->end(); netId_pit++) {
965 			string myExpandedNetName = NetName(*netId_pit);
966 			CPower * myOtherPower_p = netVoltagePtr_v[*netId_pit].full;
967  			if (myOtherPower_p && myPower_p->definition != myOtherPower_p->definition ) {
968  				bool myPowerConflict = false;
969  				if ( myPower_p->expectedMin() != "" ) {
970  					if ( myOtherPower_p->expectedMin() == "" ) {
971  						logFile << "INFO: Override expectedMin for " << NetName(*netId_pit) << " from ";
972  						logFile << myPower_p->powerSignal() << " " << myPower_p->definition << endl;
973  						myOtherPower_p->expectedMin() = myPower_p->expectedMin();
974  					} else if ( myOtherPower_p->expectedMin() != myPower_p->expectedMin() ) {
975  						myPowerConflict = true;
976  					}
977  				}
978  				if ( myPower_p->expectedSim() != "" ) {
979  					if ( myOtherPower_p->expectedSim() == "" ) {
980  						logFile << "INFO: Override expectedSim for " << NetName(*netId_pit) << " from ";
981  						logFile << myPower_p->powerSignal() << " " << myPower_p->definition << endl;
982  						myOtherPower_p->expectedSim() = myPower_p->expectedSim();
983  					} else if ( myOtherPower_p->expectedSim() != myPower_p->expectedSim() ) {
984  						myPowerConflict = true;
985  					}
986  				}
987  				if ( myPower_p->expectedMax() != "" ) {
988  					if ( myOtherPower_p->expectedMax() == "" ) {
989  						logFile << "INFO: Override expectedMax for " << NetName(*netId_pit) << " from ";
990  						logFile << myPower_p->powerSignal() << " " << myPower_p->definition << endl;
991  						myOtherPower_p->expectedMax() = myPower_p->expectedMax();
992  					} else if ( myOtherPower_p->expectedMax() != myPower_p->expectedMax() ) {
993  						myPowerConflict = true;
994  					}
995  				}
996  				if ( myPower_p->minVoltage != UNKNOWN_VOLTAGE ) {
997  					if ( myOtherPower_p->minVoltage == UNKNOWN_VOLTAGE ) {
998  						logFile << "INFO: Override minVoltage for " << NetName(*netId_pit) << " from ";
999  						logFile << myPower_p->powerSignal() << " " << myPower_p->definition << endl;
1000  						myOtherPower_p->minVoltage = myPower_p->minVoltage;
1001  					} else if ( myOtherPower_p->minVoltage != myPower_p->minVoltage ) {
1002  						myPowerConflict = true;
1003  					}
1004  				}
1005  				if ( myPower_p->simVoltage != UNKNOWN_VOLTAGE ) {
1006  					if ( myOtherPower_p->simVoltage == UNKNOWN_VOLTAGE ) {
1007  						logFile << "INFO: Override simVoltage for " << NetName(*netId_pit) << " from ";
1008  						logFile << myPower_p->powerSignal() << " " << myPower_p->definition << endl;
1009  						myOtherPower_p->simVoltage = myPower_p->simVoltage;
1010  					} else if ( myOtherPower_p->simVoltage != myPower_p->simVoltage ) {
1011  						myPowerConflict = true;
1012  					}
1013  				}
1014  				if ( myPower_p->maxVoltage != UNKNOWN_VOLTAGE ) {
1015  					if ( myOtherPower_p->maxVoltage == UNKNOWN_VOLTAGE ) {
1016  						logFile << "INFO: Override maxVoltage for " << NetName(*netId_pit) << " from ";
1017  						logFile << myPower_p->powerSignal() << " " << myPower_p->definition << endl;
1018  						myOtherPower_p->maxVoltage = myPower_p->maxVoltage;
1019  					} else if ( myOtherPower_p->maxVoltage != myPower_p->maxVoltage ) {
1020  						myPowerConflict = true;
1021  					}
1022  				}
1023  				if ( myPower_p->type != myOtherPower_p->type || myPower_p->family() != myOtherPower_p->family() ) {  // can't override power types or families
1024  					myPowerConflict = true;
1025  				}
1026  				if ( myPowerConflict ) {
1027  					reportFile << "ERROR: Duplicate power definition " << NetName(*netId_pit) << ": \"";
1028  					reportFile << myOtherPower_p->powerSignal() << "(" << myOtherPower_p->definition;
1029  					reportFile << ")\" != \"" << myPower_p->powerSignal() << "(" << myPower_p->definition << ")\"" << endl;
1030  					myPowerError = true;
1031  				}
1032  			}
1033 			if ( netId_pit != myNetIdList->begin() ) {
1034 				myPower_p = new CPower(myPower_p, *netId_pit);
1035 				cvcParameters.cvcPowerPtrList.insert(++power_ppit, myPower_p); // insert after current power_ppit (before next node)
1036 				power_ppit--;  // set power_ppit to node just inserted
1037 			} else {  // add net number to existing power definitions
1038 				myPower_p->netId = *netId_pit;
1039 			}
1040 			if ( ! myOtherPower_p ) {
1041 				netVoltagePtr_v[*netId_pit].full = myPower_p;
1042 				netVoltagePtr_v.powerPtrType_v[*netId_pit] = FULL_POWER_PTR;
1043 			}
1044 			if ( myPower_p->minVoltage != UNKNOWN_VOLTAGE ) netStatus_v[*netId_pit][MIN_POWER] = true;
1045 			if ( myPower_p->maxVoltage != UNKNOWN_VOLTAGE ) netStatus_v[*netId_pit][MAX_POWER] = true;
1046 			if ( myPower_p->simVoltage != UNKNOWN_VOLTAGE ) netStatus_v[*netId_pit][SIM_POWER] = true;
1047 		}
1048 		if ( myNetIdList->empty() ) {
1049 			reportFile << "ERROR: Could not find net " << myPower_p->powerSignal() << endl;
1050 			myPowerError = true;
1051 		}
1052 		power_ppit++;
1053 		delete myNetIdList;
1054 	}
1055 	if ( myPowerError ) {
1056 		reportFile << "Power definition error" << endl;
1057 		return(SKIP);
1058 	} else {
1059 		return(OK);
1060 	}
1061 }
1062 
SetInstancePower()1063 returnCode_t CCvcDb::SetInstancePower() {
1064 	// Instance power definitions
1065 	reportFile << "Setting instance power..." << endl;
1066 	bool myPowerError = false;
1067 	// Instance power definitions
1068 	for ( auto instance_ppit = cvcParameters.cvcInstancePowerPtrList.begin(); instance_ppit != cvcParameters.cvcInstancePowerPtrList.end(); instance_ppit++ ) {
1069 		forward_list<instanceId_t> myInstanceIdList = FindInstanceIds((*instance_ppit)->instanceName);  // expands buses and hierarchy
1070 		for ( auto instanceId_pit = myInstanceIdList.begin(); instanceId_pit != myInstanceIdList.end(); instanceId_pit++ ) {
1071 			CPowerPtrMap myLocalMacroPtrMap;
1072 			for (auto powerMap_pit = cvcParameters.cvcPowerMacroPtrMap.begin(); powerMap_pit != cvcParameters.cvcPowerMacroPtrMap.end(); powerMap_pit++) {
1073 				// Add top macros
1074 				netId_t myNetId = FindNet(0, powerMap_pit->first, false);
1075 				if (myNetId == UNKNOWN_NET) {  // power definition does not exist, therefore this is macro
1076 					myLocalMacroPtrMap[powerMap_pit->first] = new CPower(powerMap_pit->second);
1077 				}
1078 			}
1079 			logFile << " Setting power for instance " << HierarchyName(*instanceId_pit) << " of " << instancePtr_v[*instanceId_pit]->master_p->name;
1080 			logFile << " from " << (*instance_ppit)->powerFile << endl;
1081 			for ( auto power_pit = (*instance_ppit)->powerList.begin(); power_pit != (*instance_ppit)->powerList.end(); power_pit++ ) {
1082 				CPower * myPower_p = new CPower(*power_pit, myLocalMacroPtrMap, cvcParameters.cvcModelListMap);
1083 				string myOriginalPower = myPower_p->powerSignal();
1084 				string myNewPower;
1085 				if ( myOriginalPower.substr(0, 1) == "/" ) {
1086 					myNewPower = HierarchyName(*instanceId_pit) + myPower_p->powerSignal();
1087 					myPower_p->extraData->powerSignal = CPower::powerDefinitionText.SetTextAddress((text_t)myNewPower.c_str());
1088 				} else if ( myOriginalPower.substr(0, 2) != "*(" ) {
1089 					myNewPower = HierarchyName(*instanceId_pit) + HIERARCHY_DELIMITER + myPower_p->powerSignal();
1090 					myPower_p->extraData->powerSignal = CPower::powerDefinitionText.SetTextAddress((text_t)myNewPower.c_str());
1091 				}
1092 				set<netId_t> * myNetIdList_p = FindUniqueNetIds(string(myPower_p->powerSignal()), *instanceId_pit);
1093 				for ( auto net_pit = myNetIdList_p->begin(); net_pit != myNetIdList_p->end(); net_pit++ ) {
1094 					netId_t myNetId = GetEquivalentNet(*net_pit);
1095 					if ( net_pit != myNetIdList_p->begin() ) {
1096 						myPower_p = new CPower(myPower_p, myNetId);
1097 					} else {  // add net number to existing power definitions
1098 						myPower_p->netId = myNetId;
1099 					}
1100 					CPower * myOtherPower_p = netVoltagePtr_v[myNetId].full;
1101 					if ( myPower_p->type[POWER_BIT] && isalpha(myOriginalPower[0]) ) {
1102 						if ( myOtherPower_p && myOtherPower_p->type[POWER_BIT] ) {  // regular power definitions become macros
1103 							myLocalMacroPtrMap[myOriginalPower] = myOtherPower_p;
1104 							logFile << "  " << myOriginalPower << " = " << NetName(myNetId) << endl;
1105 						} else {  // top instance power nets must be already defined
1106 							reportFile << "ERROR: Instance power signal " << myPower_p->powerSignal() << " not defined in parent " << NetName(myNetId) << endl;
1107 							myPowerError = true;
1108 						}
1109 					} else if ( myPower_p->type[INPUT_BIT] ) {
1110 						if ( ! myPower_p->extraData ) myPower_p->extraData = new CExtraPowerData;
1111 						if ( myPower_p->minVoltage != UNKNOWN_VOLTAGE ) myPower_p->extraData->expectedMin = to_string<float>(float(myPower_p->minVoltage) / VOLTAGE_SCALE);
1112 						if ( myPower_p->simVoltage != UNKNOWN_VOLTAGE ) myPower_p->extraData->expectedSim = to_string<float>(float(myPower_p->simVoltage) / VOLTAGE_SCALE);
1113 						if ( myPower_p->maxVoltage != UNKNOWN_VOLTAGE ) myPower_p->extraData->expectedMax = to_string<float>(float(myPower_p->maxVoltage) / VOLTAGE_SCALE);
1114 						if ( ! (IsEmpty(myPower_p->expectedMin()) && IsEmpty(myPower_p->expectedSim()) && IsEmpty(myPower_p->expectedMax())) ) {
1115 							myPower_p->minVoltage = UNKNOWN_VOLTAGE;
1116 							myPower_p->simVoltage = UNKNOWN_VOLTAGE;
1117 							myPower_p->maxVoltage = UNKNOWN_VOLTAGE;
1118 							myPower_p->type[INPUT_BIT] = false;
1119 							myPower_p->definition = CPower::powerDefinitionText.SetTextAddress((text_t)myPower_p->StandardDefinition().c_str());
1120 							cvcParameters.cvcExpectedLevelPtrList.push_back(myPower_p);
1121 							logFile << "  " << myOriginalPower << " = " << NetName(myNetId) << endl;
1122 						}
1123 					} else {
1124 						if ( myOtherPower_p ) {
1125 							if ( myOtherPower_p->definition != myPower_p->definition ) {
1126 								reportFile << "Warning: Duplicate power definition " << NetName(myNetId) << "(" << myOtherPower_p->definition << ")";
1127 								reportFile << " and " << myPower_p->powerSignal() << "(" << myPower_p->definition << ") of " << HierarchyName(*instanceId_pit) << " ignored" << endl;
1128 							}
1129 						} else {
1130 							cvcParameters.cvcPowerPtrList.push_back(myPower_p);
1131 							netVoltagePtr_v[myNetId].full = myPower_p;
1132 						}
1133 					}
1134 				}
1135 			}
1136 		}
1137 	}
1138 	if ( myPowerError ) {
1139 		reportFile << "Power definition error" << endl;
1140 		return(SKIP);
1141 	} else {
1142 		return(OK);
1143 	}
1144 }
1145 
SetExpectedPower()1146 returnCode_t CCvcDb::SetExpectedPower() {
1147 	// Expected voltage definitions
1148 	unordered_map<netId_t, text_t> myExpectedLevelDefinitionMap;
1149 	unordered_map<netId_t, string> myExpectedLevelSignalMap;
1150 	CPowerPtrList::iterator power_ppit = cvcParameters.cvcExpectedLevelPtrList.begin();
1151 	bool myPowerError = false;
1152 	while( power_ppit != cvcParameters.cvcExpectedLevelPtrList.end() ) {
1153 		CPower * myPower_p = *power_ppit;
1154 		set<netId_t> * myNetIdList;
1155 		if ( myPower_p->netId == UNKNOWN_NET ) {
1156 			myNetIdList = FindUniqueNetIds(string(myPower_p->powerSignal())); // expands buses and hierarchy
1157 		} else {
1158 			myNetIdList = new set<netId_t>;
1159 			myNetIdList->insert(myPower_p->netId);
1160 		}
1161 		for (auto netId_pit = myNetIdList->begin(); netId_pit != myNetIdList->end(); netId_pit++) {
1162 			string myExpandedNetName = NetName(*netId_pit);
1163 			CPower * myOtherPower_p = netVoltagePtr_v[*netId_pit].full;
1164 			if (myOtherPower_p && myPower_p->definition != myOtherPower_p->definition ) {
1165 				voltage_t mySimVoltage = myOtherPower_p->simVoltage;
1166 				if ( myPower_p->expectedSim() == ""
1167 						|| ( IsValidVoltage_(myPower_p->expectedSim()) && mySimVoltage == String_to_Voltage(myPower_p->expectedSim()) ) ) {
1168 					reportFile << "Warning: ignoring power check for " << NetName(*netId_pit) << ": \"";
1169 					reportFile << myPower_p->powerSignal() << "(" << myPower_p->definition << ")\" already set as ";
1170 					reportFile << myOtherPower_p->powerSignal() << "(" << myOtherPower_p->definition << ")\"" << endl;
1171 				} else {
1172 					reportFile << "ERROR: Duplicate power definition " << NetName(*netId_pit) << ": \"";
1173 					reportFile << myOtherPower_p->powerSignal() << "(" << myOtherPower_p->definition;
1174 					reportFile << ")\" != \"" << myPower_p->powerSignal() << "(" << myPower_p->definition << ")\"" << endl;
1175 					myPowerError = true;
1176 					continue;
1177 				}
1178 			}
1179 			if ( netId_pit != myNetIdList->begin() ) {
1180 				myPower_p = new CPower(myPower_p, *netId_pit);
1181 				cvcParameters.cvcExpectedLevelPtrList.insert(++power_ppit, myPower_p); // insert after current power_ppit (before next node)
1182 				power_ppit--; // set power_ppit to node just inserted
1183 			} else { // add net number to existing power definitions
1184 				myPower_p->netId = *netId_pit;
1185 			}
1186 		}
1187 		if ( myNetIdList->empty() ) {
1188 			reportFile << "ERROR: Could not find net " << myPower_p->powerSignal() << endl;
1189 			myPowerError = true;
1190 		}
1191 		power_ppit++;
1192 		delete myNetIdList;
1193 	}
1194 	if ( myPowerError ) {
1195 		reportFile << "Power definition error" << endl;
1196 		return(SKIP);
1197 	} else {
1198 		return(OK);
1199 	}
1200 }
1201 
LockReport(bool theInteractiveFlag)1202 bool CCvcDb::LockReport(bool theInteractiveFlag) {
1203 	if ( mkdir(cvcParameters.cvcLockFile.c_str(), 0700) != 0 ) {
1204 		cout << "ERROR: Could not create lock file " << cvcParameters.cvcLockFile << endl;
1205 		cout << "report file may be in use by another program." << endl;
1206 		cout << "If no other program is running, remove the lock file and try again." << endl;
1207 		if ( theInteractiveFlag ) {
1208 			cout << "Type \"rerun\" to try again, anything else to skip" << endl;
1209 			string myResponse;
1210 			getline(cin, myResponse);
1211 			if ( myResponse == "rerun" ) {
1212 				cvcArgIndex--;
1213 			}
1214 		}
1215 		lockFile = "";
1216 		return false;
1217 	} else {
1218 		lockFile = cvcParameters.cvcLockFile;
1219 		return true;
1220 	}
1221 }
1222 
RemoveLock()1223 void CCvcDb::RemoveLock() {
1224 	if ( ! IsEmpty(lockFile) ) {
1225 		int myStatus;
1226 		myStatus = rmdir(lockFile.c_str());
1227 		if (myStatus) {
1228 			cout << "Remove lock file return value " << myStatus << " error " << errno << endl;
1229 		}
1230 	}
1231 	lockFile = "";
1232 }
1233 
SetSCRCPower()1234 void CCvcDb::SetSCRCPower() {
1235 	reportFile << "Setting SCRC power mos nets..." << endl;
1236 	size_t mySCRCSignalCount = 0;
1237 	size_t mySCRCIgnoreCount = 0;
1238 	// Set expected levels for SCRC power mos.
1239 	for ( auto power_ppit = cvcParameters.cvcPowerPtrList.begin(); power_ppit != cvcParameters.cvcPowerPtrList.end(); power_ppit++ ) {
1240 		//if ( IsSCRCPower(*power_ppit) ) {
1241 		if ( (*power_ppit)->type[HIZ_BIT] ) {
1242 			// Check for power switches.
1243 			netId_t myNetId = (*power_ppit)->netId;
1244 			(void) SetSCRCGatePower(myNetId, firstDrain_v, nextDrain_v, sourceNet_v, mySCRCSignalCount, mySCRCIgnoreCount, true);
1245 			(void) SetSCRCGatePower(myNetId, firstSource_v, nextSource_v, drainNet_v, mySCRCSignalCount, mySCRCIgnoreCount, true);
1246 		}
1247 	}
1248 	reportFile << "Set " << mySCRCSignalCount << " power mos signals." << " Ignored " << mySCRCIgnoreCount << " signals." << endl;
1249 	mySCRCSignalCount = 0;
1250 	mySCRCIgnoreCount = 0;
1251 	reportFile << "Setting SCRC internal nets..." << endl;
1252 	// Set expected levels for SCRC logic.
1253 	for ( size_t net_it = 0; net_it < netCount; net_it++ ) {
1254 		if ( IsSCRCLogicNet(net_it) ) {
1255 			size_t myAttemptCount = 0;
1256 			myAttemptCount += SetSCRCGatePower(net_it, firstDrain_v, nextDrain_v, sourceNet_v, mySCRCSignalCount, mySCRCIgnoreCount, false);
1257 			myAttemptCount += SetSCRCGatePower(net_it, firstSource_v, nextSource_v, drainNet_v, mySCRCSignalCount, mySCRCIgnoreCount, false);
1258 			if ( myAttemptCount == 0 ) {  // Could not set any gate nets, so set net directly
1259 				CPower * myFinalMinPower_p = netVoltagePtr_v[minNet_v[net_it].finalNetId].full;
1260 				CPower * myFinalMaxPower_p = netVoltagePtr_v[maxNet_v[net_it].finalNetId].full;
1261 				voltage_t myExpectedVoltage = IsSCRCPower(myFinalMinPower_p) ? myFinalMaxPower_p->maxVoltage : myFinalMinPower_p->minVoltage;
1262 				if ( netVoltagePtr_v[net_it].full ) {
1263 					if ( netVoltagePtr_v[net_it].full->simVoltage != myExpectedVoltage ) {
1264 						reportFile << "Warning: " << NetName(net_it) << ": voltage already set expected " << myExpectedVoltage;
1265 						reportFile << " found " << netVoltagePtr_v[net_it].full->simVoltage << endl;
1266 						mySCRCIgnoreCount++;
1267 					}
1268 				} else {
1269 					debugFile << "Forcing net " << NetName(net_it) << " to " << PrintVoltage(myExpectedVoltage) << endl;
1270 					netVoltagePtr_v[net_it].full = new CPower(net_it, myExpectedVoltage, true);
1271 					netVoltagePtr_v[net_it].full->extraData->powerSignal = CPower::powerDefinitionText.SetTextAddress(SCRC_FORCED_TEXT);
1272 					cvcParameters.cvcPowerPtrList.push_back(netVoltagePtr_v[net_it].full);
1273 					mySCRCSignalCount++;
1274 				}
1275 			}
1276 		}
1277 	}
1278 	reportFile << "Set " << mySCRCSignalCount << " inverter signals." << " Ignored " << mySCRCIgnoreCount << " signals." << endl;
1279 }
1280 
SetSCRCGatePower(netId_t theNetId,CDeviceIdVector & theFirstSource_v,CDeviceIdVector & theNextSource_v,CNetIdVector & theDrain_v,size_t & theSCRCSignalCount,size_t & theSCRCIgnoreCount,bool theNoCheckFlag)1281 size_t CCvcDb::SetSCRCGatePower(netId_t theNetId, CDeviceIdVector & theFirstSource_v, CDeviceIdVector & theNextSource_v, CNetIdVector & theDrain_v,
1282 		size_t & theSCRCSignalCount, size_t & theSCRCIgnoreCount, bool theNoCheckFlag) {
1283 	CPower * mySourcePower_p = netVoltagePtr_v[theNetId].full;
1284 	size_t myAttemptCount = 0;
1285 	for ( auto device_it = theFirstSource_v[theNetId]; device_it != UNKNOWN_DEVICE; device_it = theNextSource_v[device_it] ) {
1286 		if ( ! IsMos_(deviceType_v[device_it]) ) continue;  // Only process mosfets.
1287 		CPower * myDrainPower_p = netVoltagePtr_v[theDrain_v[device_it]].full;
1288 		if ( ! myDrainPower_p ) continue;  // ignore non-power nets
1289 		if ( theNoCheckFlag && mySourcePower_p->IsRelatedPower(myDrainPower_p, netVoltagePtr_v, simNet_v, simNet_v, false) ) continue;  // ignore relatives
1290 		if ( myDrainPower_p->type[POWER_BIT] && (theNoCheckFlag || IsSCRCPower(myDrainPower_p)) ) {  // Mosfet bridges power nets.
1291 			SetSCRCParentPower(theNetId, device_it, IsPmos_(deviceType_v[device_it]), theSCRCSignalCount, theSCRCIgnoreCount);
1292 			myAttemptCount++;
1293 		}
1294 	}
1295 	return (myAttemptCount);
1296 }
1297 
SetSCRCParentPower(netId_t theNetId,deviceId_t theDeviceId,bool theExpectedHighInput,size_t & theSCRCSignalCount,size_t & theSCRCIgnoreCount)1298 void CCvcDb::SetSCRCParentPower(netId_t theNetId, deviceId_t theDeviceId, bool theExpectedHighInput, size_t & theSCRCSignalCount, size_t & theSCRCIgnoreCount) {
1299 	netId_t myParentNet = gateNet_v[theDeviceId];
1300 	while ( inverterNet_v[myParentNet] != UNKNOWN_NET && ! (netVoltagePtr_v[myParentNet].full && netVoltagePtr_v[myParentNet].full->simVoltage != UNKNOWN_VOLTAGE) ) {
1301 		myParentNet = inverterNet_v[myParentNet];
1302 		theExpectedHighInput = ! theExpectedHighInput;
1303 	}
1304 	CPower * myHighPower_p = netVoltagePtr_v[maxNet_v[myParentNet].finalNetId].full;
1305 	CPower * myLowPower_p = netVoltagePtr_v[minNet_v[myParentNet].finalNetId].full;
1306 	CPower * myExpectedPower_p = theExpectedHighInput ? myHighPower_p : myLowPower_p;
1307 	voltage_t myExpectedVoltage = UNKNOWN_VOLTAGE;
1308 	if ( myExpectedPower_p ) {
1309 		myExpectedVoltage = theExpectedHighInput ? myExpectedPower_p->maxVoltage : myExpectedPower_p->minVoltage;
1310 	}
1311 	if ( netVoltagePtr_v[myParentNet].full && netVoltagePtr_v[myParentNet].full->simVoltage != UNKNOWN_VOLTAGE ) {
1312 		if ( myExpectedPower_p && myExpectedVoltage != netVoltagePtr_v[myParentNet].full->simVoltage ) {
1313 			reportFile << "Warning: " << NetName(theNetId) << ": voltage already set for " << NetName(myParentNet) << " expected " << (theExpectedHighInput ? "high" : "low");
1314 			reportFile << " found " << netVoltagePtr_v[myParentNet].full->simVoltage << endl;
1315 		}
1316 		theSCRCIgnoreCount++;
1317 		return;  // return if voltage already set
1318 	}
1319 	if ( ! myExpectedPower_p ) {
1320 		reportFile << "Warning: " << NetName(theNetId) << ": voltage not set for " << NetName(myParentNet) << " expected " << (theExpectedHighInput ? "high" : "low");
1321 		reportFile << " found non-power" << endl;
1322 		theSCRCIgnoreCount++;
1323 	} else {
1324 		assert(myExpectedPower_p);
1325 		if ( myExpectedVoltage == UNKNOWN_VOLTAGE || myExpectedPower_p->type[HIZ_BIT] ) {
1326 			reportFile << "Warning: " << NetName(theNetId) << ": voltage not set for " << NetName(myParentNet) << " expected " << (theExpectedHighInput ? "high" : "low");
1327 			reportFile << " found " << (myExpectedVoltage == UNKNOWN_VOLTAGE ? "???" : "Hi-Z") << endl;
1328 			theSCRCIgnoreCount++;
1329 		} else if ( netVoltagePtr_v[myParentNet].full == NULL ) {
1330 			debugFile << "Setting net " << NetName(myParentNet) << " to " << PrintVoltage(myExpectedVoltage) << " for " << NetName(gateNet_v[theDeviceId]);
1331 			debugFile << " at device " << DeviceName(theDeviceId) << endl;
1332 			netVoltagePtr_v[myParentNet].full = new CPower(myParentNet, myExpectedVoltage, true);
1333 			netVoltagePtr_v[myParentNet].full->extraData->powerSignal = CPower::powerDefinitionText.SetTextAddress(SCRC_EXPECTED_TEXT);
1334 			cvcParameters.cvcPowerPtrList.push_back(netVoltagePtr_v[myParentNet].full);
1335 			theSCRCSignalCount++;
1336 		} else if ( netVoltagePtr_v[myParentNet].full->simVoltage != myExpectedVoltage ) {
1337 			reportFile << "ERROR: " << NetName(theNetId) << ": voltage not set for " << NetName(myParentNet) << " expected " << PrintVoltage(myExpectedVoltage);
1338 			reportFile << " found " << PrintVoltage(netVoltagePtr_v[myParentNet].full->simVoltage) << endl;
1339 			theSCRCIgnoreCount++;
1340 		}
1341 	}
1342 }
1343 
IsSCRCLogicNet(netId_t theNetId)1344 bool CCvcDb::IsSCRCLogicNet(netId_t theNetId) {
1345 	CPower * myMinPower = netVoltagePtr_v[minNet_v[theNetId].finalNetId].full;
1346 	CPower * myMaxPower = netVoltagePtr_v[maxNet_v[theNetId].finalNetId].full;
1347 	if ( ! myMinPower || ! myMaxPower ) return false;
1348 	if ( myMinPower->type[HIZ_BIT] == myMaxPower->type[HIZ_BIT] ) return false;
1349 	if ( myMinPower->type[MIN_CALCULATED_BIT] || myMaxPower->type[MAX_CALCULATED_BIT] ) return false;
1350 	if ( connectionCount_v[theNetId].sourceDrainType != NMOS_PMOS ) return false;
1351 	if ( IsSCRCPower(myMinPower) || IsSCRCPower(myMaxPower) ) return true;
1352 	return false;
1353 }
1354 
IsSCRCPower(CPower * thePower_p)1355 bool CCvcDb::IsSCRCPower(CPower * thePower_p) {
1356 	// TODO: change to macro.
1357 	if ( ! thePower_p ) return false;
1358 	if ( ! thePower_p->type[HIZ_BIT] ) return false;
1359 	if ( thePower_p->minVoltage != thePower_p->maxVoltage ) return false;
1360 	return true;
1361 }
1362 
1363 #define MAX_LATCH_DEVICE_COUNT 6
1364 
SetLatchPower(int thePassCount,vector<bool> & theIgnoreNet_v,CNetIdSet & theNewNetSet)1365 bool CCvcDb::SetLatchPower(int thePassCount, vector<bool> & theIgnoreNet_v, CNetIdSet & theNewNetSet) {
1366 	int myLatchCount = 0;
1367 	theNewNetSet.clear();
1368 	for (unsigned int net_it = 0; net_it < simNet_v.size(); net_it++) {
1369 		if ( thePassCount == 1 ) {
1370 			if ( net_it != GetEquivalentNet(net_it)  // ignore shorted nets
1371 					|| connectionCount_v[net_it].sourceDrainType != NMOS_PMOS  // not an output net
1372 					|| connectionCount_v[net_it].SourceDrainCount() > MAX_LATCH_DEVICE_COUNT ) {  // only simple connections
1373 				theIgnoreNet_v[net_it] = true;
1374 			}
1375 		}
1376 		if ( theIgnoreNet_v[net_it]
1377 				|| simNet_v[net_it].finalNetId != net_it  // already assigned
1378 				|| ( netVoltagePtr_v[net_it].full && netVoltagePtr_v[net_it].full->simVoltage != UNKNOWN_VOLTAGE ) ) {  // already defined
1379 			theIgnoreNet_v[net_it] = true;
1380 			continue;
1381 		}
1382 		int myNmosCount = 0;
1383 		int myPmosCount = 0;
1384 		netId_t myMinNet = minNet_v[net_it].finalNetId;
1385 		voltage_t myMinVoltage = UNKNOWN_VOLTAGE;
1386 		if ( myMinNet != UNKNOWN_NET && netVoltagePtr_v[myMinNet].full && netVoltagePtr_v[myMinNet].full->type[POWER_BIT] ) {
1387 			myMinVoltage = netVoltagePtr_v[myMinNet].full->minVoltage;
1388 		}
1389 		netId_t myMaxNet = maxNet_v[net_it].finalNetId;
1390 		voltage_t myMaxVoltage = UNKNOWN_VOLTAGE;
1391 		if ( myMaxNet != UNKNOWN_NET && netVoltagePtr_v[myMaxNet].full && netVoltagePtr_v[myMaxNet].full->type[POWER_BIT] ) {
1392 			myMaxVoltage = netVoltagePtr_v[myMaxNet].full->maxVoltage;
1393 		}
1394 		if ( myMinVoltage == UNKNOWN_VOLTAGE && myMaxVoltage == UNKNOWN_VOLTAGE ) continue;  // skip unknown min/max output
1395 		if ( myMinVoltage == UNKNOWN_VOLTAGE ) myMinVoltage = myMaxVoltage;
1396 		if ( myMaxVoltage == UNKNOWN_VOLTAGE ) myMaxVoltage = myMinVoltage;
1397 		mosData_t myNmosData_v[MAX_LATCH_DEVICE_COUNT];
1398 		mosData_t myPmosData_v[MAX_LATCH_DEVICE_COUNT];
1399 		FindLatchDevices(net_it, myNmosData_v, myPmosData_v, myNmosCount, myPmosCount, myMinVoltage, myMaxVoltage,
1400 			firstDrain_v, nextDrain_v, sourceNet_v);
1401 		FindLatchDevices(net_it, myNmosData_v, myPmosData_v, myNmosCount, myPmosCount, myMinVoltage, myMaxVoltage,
1402 			firstSource_v, nextSource_v, drainNet_v);
1403 		voltage_t myNmosVoltage = UNKNOWN_VOLTAGE;
1404 		voltage_t myPmosVoltage = UNKNOWN_VOLTAGE;
1405 		string myNmosPowerName;
1406 		text_t myNmosPowerAlias;
1407 		string myPmosPowerName;
1408 		text_t myPmosPowerAlias;
1409 		deviceId_t mySampleNmos = UNKNOWN_DEVICE;
1410 		for ( int mos_it = 0; mos_it < myNmosCount-1; mos_it++ ) {
1411 			CPower * myNmosSourcePower_p = netVoltagePtr_v[myNmosData_v[mos_it].source].full;
1412 			if ( ! myNmosSourcePower_p || myNmosSourcePower_p->simVoltage == UNKNOWN_VOLTAGE ) continue;  // skip non power
1413 			voltage_t myVoltage = myNmosSourcePower_p->simVoltage;
1414 			for ( int nextMos_it = mos_it+1; nextMos_it < myNmosCount; nextMos_it++ ) {
1415 				CPower * myNextNmosSourcePower_p = netVoltagePtr_v[myNmosData_v[nextMos_it].source].full;
1416 				if ( ! myNextNmosSourcePower_p || myNextNmosSourcePower_p->simVoltage == UNKNOWN_VOLTAGE ) continue;  // skip non power
1417 				voltage_t myNextVoltage = myNextNmosSourcePower_p->simVoltage;
1418 				if ( myVoltage == myNextVoltage && IsOppositeLogic(myNmosData_v[mos_it].gate, myNmosData_v[nextMos_it].gate) ) {  // same source, opposite gate
1419 					myNmosVoltage = myVoltage;
1420 					myNmosPowerName = NetName(myNmosData_v[mos_it].source);
1421 					myNmosPowerAlias = myNmosSourcePower_p->powerAlias();
1422 					mySampleNmos = myNmosData_v[mos_it].id;
1423 				}
1424 			}
1425 		}
1426 		for ( int mos_it = 0; mos_it < myPmosCount-1; mos_it++ ) {
1427 			CPower * myPmosSourcePower_p = netVoltagePtr_v[myPmosData_v[mos_it].source].full;
1428 			if ( ! myPmosSourcePower_p || myPmosSourcePower_p->simVoltage == UNKNOWN_VOLTAGE ) continue;  // skip non power
1429 			voltage_t myVoltage = myPmosSourcePower_p->simVoltage;
1430 			for ( int nextMos_it = mos_it+1; nextMos_it < myPmosCount; nextMos_it++ ) {
1431 				CPower * myNextPmosSourcePower_p = netVoltagePtr_v[myPmosData_v[nextMos_it].source].full;
1432 				if ( ! myNextPmosSourcePower_p || myNextPmosSourcePower_p->simVoltage == UNKNOWN_VOLTAGE ) continue;  // skip non power
1433 				voltage_t myNextVoltage = myNextPmosSourcePower_p->simVoltage;
1434 				if ( myVoltage == myNextVoltage && IsOppositeLogic(myPmosData_v[mos_it].gate, myPmosData_v[nextMos_it].gate) ) {  // same source, opposite gate
1435 					myPmosVoltage = myVoltage;
1436 					myPmosPowerName = NetName(myPmosData_v[mos_it].source);
1437 					myPmosPowerAlias = myPmosSourcePower_p->powerAlias();
1438 				}
1439 			}
1440 		}
1441 		if ( myNmosVoltage != UNKNOWN_VOLTAGE && myPmosVoltage != UNKNOWN_VOLTAGE && myNmosVoltage != myPmosVoltage ) {
1442 			if ( cvcParameters.cvcCircuitErrorLimit == 0 || IncrementDeviceError(mySampleNmos, LEAK) < cvcParameters.cvcCircuitErrorLimit ) {
1443 				CFullConnection myConnections;
1444 				MapDeviceNets(mySampleNmos, myConnections);
1445 				errorFile << "! Short Detected: " << PrintVoltage(myNmosVoltage) << " to " << PrintVoltage(myPmosVoltage) << " at n/pmux" << endl;
1446 				PrintDeviceWithAllConnections(deviceParent_v[mySampleNmos], myConnections, errorFile);
1447 				errorFile << endl;
1448 			}
1449 			continue;  // don't propagate non-matching power
1450 		}
1451 		CPower * myPower_p = netVoltagePtr_v[net_it].full;
1452 		if ( myNmosVoltage != UNKNOWN_VOLTAGE ) {
1453 			if ( myPower_p ) {  // just add sim voltage
1454 				assert(myPower_p->simVoltage == UNKNOWN_VOLTAGE);
1455 				myPower_p->simVoltage = myNmosVoltage;
1456 			} else {
1457 				netVoltagePtr_v[net_it].full = new CPower(net_it, myNmosVoltage, true);
1458 				netVoltagePtr_v[net_it].full->extraData->powerSignal = myNmosPowerAlias;
1459 				netVoltagePtr_v[net_it].full->extraData->powerAlias = myNmosPowerAlias;
1460 				cvcParameters.cvcPowerPtrList.push_back(netVoltagePtr_v[net_it].full);
1461 			}
1462 			myLatchCount++;
1463 			debugFile << "Added latch for " << NetName(net_it) << endl;
1464 			theNewNetSet.insert(net_it);
1465 		} else if ( myPmosVoltage != UNKNOWN_VOLTAGE ) {
1466 			if ( myPower_p ) {
1467 				assert(myPower_p->simVoltage == UNKNOWN_VOLTAGE);
1468 				myPower_p->simVoltage = myPmosVoltage;
1469 			} else {
1470 				netVoltagePtr_v[net_it].full = new CPower(net_it, myPmosVoltage, true);
1471 				netVoltagePtr_v[net_it].full->extraData->powerSignal = myPmosPowerAlias;
1472 				netVoltagePtr_v[net_it].full->extraData->powerAlias = myPmosPowerAlias;
1473 				cvcParameters.cvcPowerPtrList.push_back(netVoltagePtr_v[net_it].full);
1474 			}
1475 			myLatchCount++;
1476 			debugFile << "Added latch for " << NetName(net_it) << endl;
1477 			theNewNetSet.insert(net_it);
1478 		}
1479 	}
1480 	reportFile << "Added " << myLatchCount << " latch voltages" << endl;
1481 	return (myLatchCount > 0);
1482 }
1483 
FindLatchDevices(netId_t theNetId,mosData_t theNmosData_v[],mosData_t thePmosData_v[],int & theNmosCount,int & thePmosCount,voltage_t theMinVoltage,voltage_t theMaxVoltage,CDeviceIdVector & theFirstDrain_v,CDeviceIdVector & theNextDrain_v,CNetIdVector & theSourceNet_v)1484 void CCvcDb::FindLatchDevices(netId_t theNetId, mosData_t theNmosData_v[], mosData_t thePmosData_v[], int & theNmosCount, int & thePmosCount,
1485 	voltage_t theMinVoltage, voltage_t theMaxVoltage,
1486 	CDeviceIdVector & theFirstDrain_v, CDeviceIdVector & theNextDrain_v, CNetIdVector & theSourceNet_v) {
1487 	for ( deviceId_t device_it = theFirstDrain_v[theNetId]; device_it != UNKNOWN_DEVICE; device_it = theNextDrain_v[device_it] ) {
1488 		if ( theSourceNet_v[device_it] == gateNet_v[device_it] && netVoltagePtr_v[theSourceNet_v[device_it]].full ) continue; // skip ESD mos
1489 		netId_t mySource = simNet_v[theSourceNet_v[device_it]].finalNetId;
1490 		netId_t myGate = simNet_v[gateNet_v[device_it]].finalNetId;
1491 		voltage_t myGateVoltage = UNKNOWN_VOLTAGE;
1492 		CPower * myGatePower_p = netVoltagePtr_v[myGate].full;
1493 		if ( myGatePower_p && ! myGatePower_p->type[SIM_CALCULATED_BIT] ) {
1494 			myGateVoltage = myGatePower_p->simVoltage;
1495 		}
1496 		if ( IsNmos_(deviceType_v[device_it]) ) {
1497 			if ( myGateVoltage == UNKNOWN_VOLTAGE ) {
1498 				theNmosData_v[theNmosCount].source = mySource;
1499 				theNmosData_v[theNmosCount].gate = myGate;
1500 				theNmosData_v[theNmosCount].id = device_it;
1501 				theNmosCount++;
1502 			} else if ( myGateVoltage >= theMaxVoltage ) {  // device is on (assumes maxVoltage turns on nmos)
1503 				deviceId_t myNextDevice = GetSeriesConnectedDevice(device_it, mySource);
1504 				if ( myNextDevice != UNKNOWN_DEVICE ) {
1505 					// this section uses the instance sourceNet_v
1506 					if ( simNet_v[sourceNet_v[myNextDevice]].finalNetId == mySource ) {
1507 						theNmosData_v[theNmosCount].source = simNet_v[drainNet_v[myNextDevice]].finalNetId;
1508 					} else {
1509 						theNmosData_v[theNmosCount].source = simNet_v[sourceNet_v[myNextDevice]].finalNetId;
1510 					}
1511 					theNmosData_v[theNmosCount].gate = simNet_v[gateNet_v[myNextDevice]].finalNetId;
1512 					theNmosData_v[theNmosCount].id = myNextDevice;
1513 					theNmosCount++;
1514 				}
1515 			}
1516 		}
1517 		if ( IsPmos_(deviceType_v[device_it]) ) {
1518 			if ( myGateVoltage == UNKNOWN_VOLTAGE ) {
1519 				thePmosData_v[thePmosCount].source = mySource;
1520 				thePmosData_v[thePmosCount].gate = myGate;
1521 				thePmosData_v[thePmosCount].id = device_it;
1522 				thePmosCount++;
1523 			} else if ( myGateVoltage <= theMinVoltage ) {  // device is on (assumes minVoltage turns on pmos)
1524 				deviceId_t myNextDevice = GetSeriesConnectedDevice(device_it, mySource);
1525 				if ( myNextDevice != UNKNOWN_DEVICE ) {
1526 					// this section uses the instance sourceNet_v
1527 					if ( simNet_v[sourceNet_v[myNextDevice]].finalNetId == mySource ) {
1528 						thePmosData_v[thePmosCount].source = simNet_v[drainNet_v[myNextDevice]].finalNetId;
1529 					} else {
1530 						thePmosData_v[thePmosCount].source = simNet_v[sourceNet_v[myNextDevice]].finalNetId;
1531 					}
1532 					thePmosData_v[thePmosCount].gate = simNet_v[gateNet_v[myNextDevice]].finalNetId;
1533 					thePmosData_v[thePmosCount].id = myNextDevice;
1534 					thePmosCount++;
1535 				}
1536 			}
1537 		}
1538 	}
1539 }
1540 
IsOppositeLogic(netId_t theFirstNet,netId_t theSecondNet)1541 bool CCvcDb::IsOppositeLogic(netId_t theFirstNet, netId_t theSecondNet) {
1542 	return (inverterNet_v[theFirstNet] == theSecondNet || theFirstNet == inverterNet_v[theSecondNet]);
1543 }
1544 
PrintInputNetsWithMinMaxSuggestions(netId_t theNetId)1545 void CCvcDb::PrintInputNetsWithMinMaxSuggestions(netId_t theNetId) {
1546 	bool mySearchingFlag = true;
1547 	CPower * myLowPower_p = NULL;
1548 	CPower * myHighPower_p = NULL;
1549 	for ( deviceId_t device_it = firstGate_v[theNetId]; device_it != UNKNOWN_DEVICE && mySearchingFlag; device_it = nextGate_v[device_it] ) {
1550 		if ( IsNmos_(deviceType_v[device_it]) && ! myLowPower_p && sourceNet_v[device_it] != UNKNOWN_NET ) {
1551 			netId_t mySourceId = minNet_v[GetEquivalentNet(sourceNet_v[device_it])].finalNetId;
1552 			if ( netVoltagePtr_v.powerPtrType_v[mySourceId] == FULL_POWER_PTR ) {
1553 				myLowPower_p = netVoltagePtr_v[mySourceId].full;
1554 			}
1555 		} else if ( IsPmos_(deviceType_v[device_it]) && ! myHighPower_p && drainNet_v[device_it] != UNKNOWN_NET ) {
1556 			netId_t mySourceId = maxNet_v[GetEquivalentNet(sourceNet_v[device_it])].finalNetId;
1557 			if ( netVoltagePtr_v.powerPtrType_v[mySourceId] == FULL_POWER_PTR ) {
1558 			myHighPower_p = netVoltagePtr_v[mySourceId].full;
1559 			}
1560 		}
1561 		mySearchingFlag = ( myLowPower_p == NULL || myHighPower_p == NULL );
1562 	}
1563 	if ( mySearchingFlag ) {   // could not find power
1564 		reportFile << NetName(theNetId, PRINT_CIRCUIT_ON) << endl;
1565 	} else {  // found power
1566 		reportFile << NetName(theNetId, PRINT_CIRCUIT_ON) << " " << myLowPower_p->powerSignal() << " " << myHighPower_p->powerSignal() << endl;
1567 	}
1568 }
1569 
PrintNetSuggestions()1570 void CCvcDb::PrintNetSuggestions() {
1571 	reportFile << "CVC: Possible power definitions" << endl;
1572 	unordered_map<netId_t, pair<deviceId_t, deviceId_t>> myBulkCount;
1573 	CDeviceIdVector myNextBulk_v;
1574 	ResetVector<CDeviceIdVector>(myNextBulk_v, deviceCount, UNKNOWN_DEVICE);
1575 	for (deviceId_t device_it = 0; device_it < deviceCount; device_it++) {
1576 		if ( bulkNet_v[device_it] == UNKNOWN_NET ) continue;
1577 		if ( IsMos_(deviceType_v[device_it]) && sourceNet_v[device_it] != drainNet_v[device_it] ) {  // only count non-capacitor mosfet
1578 			if ( myBulkCount[bulkNet_v[device_it]].first++ > 0 ) {
1579 				myNextBulk_v[device_it] = myBulkCount[bulkNet_v[device_it]].second;
1580 			}
1581 			myBulkCount[bulkNet_v[device_it]].second = device_it;
1582 		}
1583 	}
1584 	map<string, deviceId_t> myDeviceCount;
1585 	for (CModelListMap::iterator keyModelListPair_pit = cvcParameters.cvcModelListMap.begin(); keyModelListPair_pit != cvcParameters.cvcModelListMap.end(); keyModelListPair_pit++) {
1586 		for (CModelList::iterator model_pit = keyModelListPair_pit->second.begin(); model_pit != keyModelListPair_pit->second.end(); model_pit++) {
1587 			myDeviceCount[model_pit->name] = 0;
1588 		}
1589 	}
1590 	reportFile << "CVC SETUP: bulk > SD" << endl << endl;
1591 	for( netId_t net_it = 0; net_it < netCount; net_it++ ) {
1592 		if ( netVoltagePtr_v[net_it].full ) continue;
1593 		if ( myBulkCount.count(net_it)
1594 				&& ( myBulkCount[net_it].first > connectionCount_v[net_it].SourceDrainCount()
1595 						|| ( net_it < topCircuit_p->portCount  // for top ports, also flag bulk = source counts
1596 								&& myBulkCount[net_it].first == connectionCount_v[net_it].SourceDrainCount() ) ) ) {
1597 			reportFile << NetName(net_it, PRINT_CIRCUIT_ON) << "    SD/bulk " << connectionCount_v[net_it].SourceDrainCount() << "/" << myBulkCount[net_it].first;
1598 			for ( auto count_pit = myDeviceCount.begin(); count_pit != myDeviceCount.end(); count_pit++ ) {
1599 				count_pit->second = 0;
1600 			}
1601 			deviceId_t device_it = myBulkCount[net_it].second;
1602 			while ( device_it != UNKNOWN_DEVICE ) {
1603 				CInstance * myInstance_p = instancePtr_v[deviceParent_v[device_it]];
1604 				deviceId_t myDeviceOffset = device_it - myInstance_p->firstDeviceId;
1605 				myDeviceCount[myInstance_p->master_p->devicePtr_v[myDeviceOffset]->model_p->name]++;
1606 				device_it = myNextBulk_v[device_it];
1607 			}
1608 			for ( auto count_pit = myDeviceCount.begin(); count_pit != myDeviceCount.end(); count_pit++ ) {
1609 				if ( count_pit->second > 0 ) {
1610 					reportFile << " " << count_pit->first << "(" << count_pit->second << ")";
1611 				}
1612 			}
1613 			reportFile << endl;
1614 		}
1615 	}
1616 	reportFile << endl;
1617 	reportFile << "CVC SETUP: input ports" << endl << endl;
1618 	for( netId_t net_it = 0; net_it < topCircuit_p->portCount; net_it++ ) {
1619 		if ( netVoltagePtr_v[net_it].full ) continue;
1620 		if ( net_it != GetEquivalentNet(net_it) ) continue;  // skip shorted nets
1621 		unordered_set<netId_t> myCheckedNets;
1622 		unordered_set<netId_t> myUncheckedNets;
1623 		myUncheckedNets.insert(net_it);
1624 		bool myIsPossibleInput = true;
1625 		bool myHasGateConnection = false;
1626 		if ( firstGate_v[net_it] == UNKNOWN_DEVICE && firstSource_v[net_it] == UNKNOWN_DEVICE && firstDrain_v[net_it] == UNKNOWN_DEVICE ) {
1627 			reportFile << NetName(net_it, PRINT_CIRCUIT_ON) << " NO_CONNECTIONS" << endl;
1628 		}
1629 		while( ! myUncheckedNets.empty() && myUncheckedNets.size() < 10 && myIsPossibleInput ) {  // 10 is arbitrary limit to prevent runaway
1630 			netId_t myCheckNet = *(myUncheckedNets.begin());
1631 			myCheckedNets.insert(myCheckNet);
1632 			myUncheckedNets.erase(myUncheckedNets.begin());
1633 			if ( firstGate_v[myCheckNet] != UNKNOWN_DEVICE ) {
1634 				myHasGateConnection = true;
1635 			}
1636 			for ( deviceId_t device_it = firstSource_v[myCheckNet]; device_it != UNKNOWN_DEVICE && myIsPossibleInput; device_it = nextSource_v[device_it] ) {
1637 				netId_t mySearchNet = drainNet_v[device_it];
1638 				if ( ( IsMos_(deviceType_v[device_it]) && mySearchNet != gateNet_v[device_it] )
1639 						|| ( ! IsMos_(device_it) && netVoltagePtr_v[mySearchNet].full ) ) {
1640 					myIsPossibleInput = false;
1641 				} else if ( ! IsMos_(deviceType_v[device_it]) ) {
1642 					if ( myCheckedNets.count(mySearchNet) == 0 && myUncheckedNets.count(mySearchNet) == 0 ) {
1643 						if ( myUncheckedNets.size() < 10 ) {
1644 							myUncheckedNets.insert(mySearchNet);
1645 						} else {
1646 							myIsPossibleInput = false;
1647 						}
1648 					}
1649 				}
1650 			}
1651 			for ( deviceId_t device_it = firstDrain_v[myCheckNet]; device_it != UNKNOWN_DEVICE && myIsPossibleInput; device_it = nextDrain_v[device_it] ) {
1652 				netId_t mySearchNet = sourceNet_v[device_it];
1653 				if ( ( IsMos_(deviceType_v[device_it]) && mySearchNet != gateNet_v[device_it] )
1654 						|| ( ! IsMos_(device_it) && netVoltagePtr_v[mySearchNet].full ) ) {
1655 					myIsPossibleInput = false;
1656 				} else if ( ! IsMos_(deviceType_v[device_it]) ) {
1657 					if ( myCheckedNets.count(mySearchNet) == 0 && myUncheckedNets.count(mySearchNet) == 0 ) {
1658 						if ( myUncheckedNets.size() < 10 ) {
1659 							myUncheckedNets.insert(mySearchNet);
1660 						} else {
1661 							myIsPossibleInput = false;
1662 						}
1663 					}
1664 				}
1665 			}
1666 		}
1667 		if ( myIsPossibleInput && myHasGateConnection ) {
1668 			PrintInputNetsWithMinMaxSuggestions(net_it);
1669 		}
1670 	}
1671 	reportFile << endl;
1672 }
1673 
LoadCellErrorLimits()1674 returnCode_t CCvcDb::LoadCellErrorLimits() {
1675 	if ( IsEmpty(cvcParameters.cvcCellErrorLimitFile) ) return OK;
1676 	igzstream myCellErrorLimitFile;
1677 	myCellErrorLimitFile.open(cvcParameters.cvcCellErrorLimitFile);
1678 	if ( myCellErrorLimitFile.fail() ) {
1679 		throw EFatalError("Could not open cell error limit file '" + cvcParameters.cvcCellErrorLimitFile + "'");
1680 		exit(1);
1681 	}
1682 	string myInput;
1683 
1684 	reportFile << "CVC: Reading cell error limit settings..." << endl;
1685 	string myCellName;
1686 	try {
1687 		while ( getline(myCellErrorLimitFile, myInput) ) {
1688 			int myCellNameStart = myInput.find_first_not_of(" \t\n");
1689 			int myCellNameEnd = myInput.find_first_of(" \t\n", myCellNameStart);
1690 			myCellName = myInput.substr(myCellNameStart, myCellNameEnd - myCellNameStart);
1691 			int myErrorLimit = from_string<int>(myInput.substr(myCellNameEnd));
1692 			CCircuit * theMaster_p = cvcCircuitList.FindCircuit(myCellName);
1693 			theMaster_p->errorLimit = myErrorLimit;
1694 			reportFile << "INFO: error limit for " << myCellName << " is " << myErrorLimit << endl;
1695 		}
1696 	}
1697 	catch (...) {
1698 		reportFile << "ERROR: Could not find error limit cell " << myCellName << " in netlist" << endl;
1699 		return FAIL;
1700 	}
1701 	myCellErrorLimitFile.close();
1702 	return OK;
1703 }
1704 
LoadCellChecksums()1705 void CCvcDb::LoadCellChecksums() {
1706 	if ( IsEmpty(cvcParameters.cvcCellChecksumFile) ) return;
1707 	igzstream myCellChecksumFile;
1708 	myCellChecksumFile.open(cvcParameters.cvcCellChecksumFile);
1709 	if ( myCellChecksumFile.fail() ) {
1710 		throw EFatalError("Could not open cell checksum file: '" + cvcParameters.cvcCellChecksumFile + "'");
1711 		exit(1);
1712 	}
1713 	string myInput;
1714 
1715 	reportFile << "CVC: Reading cell checksums..." << endl;
1716 	string myCellName;
1717 	while ( getline(myCellChecksumFile, myInput) ) {
1718 		if ( myInput.substr(0, 1) == "#" ) continue;
1719 		int myCellNameStart = myInput.find_last_of(" ");
1720 		myCellName = myInput.substr(myCellNameStart + 1);
1721 		try {
1722 			CCircuit * theMaster_p = cvcCircuitList.FindCircuit(myCellName);
1723 			theMaster_p->checksum = myInput.substr(0, myCellNameStart);
1724 			if (gDebug_cvc) debugFile << "INFO: checksum for " << myCellName << " is " << theMaster_p->checksum << endl;
1725 		}
1726 		catch (...) {
1727 			if (gDebug_cvc) logFile << "Warning: Could not find checksum cell " << myCellName << " in netlist" << endl;
1728 		}
1729 	}
1730 	for ( auto circuit_ppit = cvcCircuitList.begin(); circuit_ppit != cvcCircuitList.end(); circuit_ppit++ ) {
1731 		if ( (*circuit_ppit)->checksum.empty() ) {
1732 			reportFile << "Warning: Could not find checksum for netlist cell " << (*circuit_ppit)->name << endl;
1733 		}
1734 	}
1735 	myCellChecksumFile.close();
1736 }
1737 
LoadNetChecks()1738 void CCvcDb::LoadNetChecks() {
1739 	/// Load net checks from file.
1740 	///
1741 	/// Currently supports:
1742 	/// "inverter_input=output": check to verify inverter output ground/power are the same as input ground/power
1743 	/// "opposite_logic": verify that 2 nets are logically opposite
1744 	if ( IsEmpty(cvcParameters.cvcNetCheckFile) ) return;
1745 
1746 	igzstream myNetCheckFile;
1747 	myNetCheckFile.open(cvcParameters.cvcNetCheckFile);
1748 	if ( myNetCheckFile.fail() ) {
1749 		throw EFatalError("Could not open level shifter file: '" + cvcParameters.cvcNetCheckFile + "'");
1750 		exit(1);
1751 
1752 	}
1753 	string myInput;
1754 	reportFile << "CVC: Reading net checks..." << endl;
1755 	while ( getline(myNetCheckFile, myInput) ) {
1756 		if ( myInput.substr(0, 1) == "#" ) continue;  // ignore comments
1757 
1758 		size_t myStringBegin = myInput.find_first_not_of(" \t");
1759 		size_t myStringEnd = myInput.find_first_of(" \t", myStringBegin);
1760 		string myNetName = myInput.substr(myStringBegin, myStringEnd - myStringBegin);
1761 		set<netId_t> * myNetIdList = FindUniqueNetIds(myNetName); // expands buses and hierarchy
1762 		if ( myNetIdList->empty() ) {
1763 			reportFile << "ERROR: Could not expand net " << myNetName << endl;
1764 		}
1765 		myStringBegin = myInput.find_first_not_of(" \t", myStringEnd);
1766 		myStringEnd = myInput.find_first_of(" \t", myStringBegin);
1767 		string myOperation = myInput.substr(myStringBegin, myStringEnd - myStringBegin);
1768 		if ( myOperation == "inverter_input=output" ) {
1769 			inverterInputOutputCheckList.push_front(myNetName);
1770 		} else if ( myOperation == "opposite_logic" ) {
1771 			myStringBegin = myInput.find_first_not_of(" \t", myStringEnd);
1772 			myStringEnd = myInput.find_first_of(" \t", myStringBegin);
1773 			string myOpposite = myInput.substr(myStringBegin, myStringEnd - myStringBegin);
1774 			size_t myDelimiter = myNetName.find_last_of(HIERARCHY_DELIMITER);
1775 			if ( myDelimiter < myNetName.npos ) {
1776 				myOpposite = myNetName.substr(0, myDelimiter) + HIERARCHY_DELIMITER + myOpposite;
1777  			}
1778 			oppositeLogicList.push_front(make_pair(myNetName, myOpposite));
1779 		} else {
1780 			reportFile << "ERROR: unknown check " << myInput << endl;
1781 		}
1782 	}
1783 	myNetCheckFile.close();
1784 }
1785 
LoadModelChecks()1786 void CCvcDb::LoadModelChecks() {
1787 	/// Load model checks from file.
1788 	///
1789 	/// Currently supports:
1790 	/// "Vb": check bulk voltage
1791 	if ( IsEmpty(cvcParameters.cvcModelCheckFile) ) return;
1792 
1793 	igzstream myModelCheckFile;
1794 	myModelCheckFile.open(cvcParameters.cvcModelCheckFile);
1795 	if ( myModelCheckFile.fail() ) {
1796 		throw EFatalError("Could not open model check file: '" + cvcParameters.cvcModelCheckFile + "'");
1797 		exit(1);
1798 
1799 	}
1800 	string myInput;
1801 	reportFile << "CVC: Reading model checks..." << endl;
1802 	while ( getline(myModelCheckFile, myInput) ) {
1803 		if ( myInput.substr(0, 1) == "#" ) continue;  // ignore comments
1804 
1805 		size_t myStringBegin = myInput.find_first_not_of(" \t");
1806 		size_t myStringEnd = myInput.find_first_of(" \t", myStringBegin);
1807 		string myModelName = myInput.substr(myStringBegin, myStringEnd - myStringBegin);
1808 		CModelList * myModelList_p = cvcParameters.cvcModelListMap.FindModelList(myModelName);
1809 		if ( ! myModelList_p ) {
1810 			reportFile << "WARNING: could not find model " << myModelName << " for model check '" << myInput << "'" << endl;
1811 			continue;
1812 
1813 		}
1814 		myStringBegin = myInput.find_first_not_of(" \t", myStringEnd);
1815 		myStringEnd = myInput.find_first_of(" \t", myStringBegin);
1816 		string myCheck = myInput.substr(myStringBegin, myStringEnd - myStringBegin);
1817 		myStringEnd = myInput.find_first_of(" \t=<>", myStringBegin);
1818 		string myParameter = myInput.substr(myStringBegin, myStringEnd - myStringBegin);
1819 		myStringBegin = myInput.find_first_of("=<>", myStringEnd);
1820 		myStringEnd = myInput.find_first_not_of("=<>", myStringBegin);
1821 		string myOperation = myInput.substr(myStringBegin, myStringEnd - myStringBegin);
1822 		myStringBegin = myInput.find_first_not_of("=<>", myStringEnd);
1823 		myStringEnd = myInput.find_first_of(" \t", myStringBegin);
1824 		string myValue = myInput.substr(myStringBegin, myStringEnd - myStringBegin);
1825 		if ( myParameter == "Vb" ) {
1826 			if ( myOperation != "=" ) {
1827 				reportFile << "WARNING: unknown operation '" << myOperation << "' in model check '" << myInput << "'" << endl;
1828 				continue;
1829 
1830 			}
1831 			for ( auto model_pit = myModelList_p->begin(); model_pit != myModelList_p->end(); model_pit++ ) {
1832 				model_pit->checkList.push_front(CModelCheck(myCheck, "Vb", myValue, "", myValue, ""));
1833 			}
1834 		} else {
1835 			reportFile << "WARNING: unknown parameter '" << myParameter << "' in model check '" << myInput << "'" << endl;
1836 		}
1837 	}
1838 	myModelCheckFile.close();
1839 }
1840 
1841