1 /*
2  * CCvcDb_interactive.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 <bitset>
25 #include <cstddef>
26 #include <cstdint>
27 #include <list>
28 #include <map>
29 #include <memory>
30 #include <set>
31 #include <string>
32 #include <vector>
33 #include <regex>
34 
35 
36 #include "CCircuit.hh"
37 #include "CConnection.hh"
38 #include "CCvcDb.hh"
39 #include "CCvcExceptions.hh"
40 #include "CCvcParameters.hh"
41 #include "CDevice.hh"
42 #include "CEventQueue.hh"
43 #include "CInstance.hh"
44 #include "CModel.hh"
45 #include "CPower.hh"
46 #include "Cvc.hh"
47 #include "CvcTypes.hh"
48 #include "CVirtualNet.hh"
49 #include "gzstream.h"
50 
51 //#include "readline.h"
52 #include <readline/readline.h>
53 // extern char * readline(const char * thePrompt);
54 #include <readline/history.h>
55 // extern void add_history(char * line_read);
56 
57 extern int gContinueCount;
58 
59 /* A static variable for holding the line. */
60 static char *line_read = (char *)NULL;
61 
62 /* Read a string, and return a pointer to it.  Returns NULL on EOF. */
63 char *
rl_gets(string thePrompt)64 rl_gets (string thePrompt) {
65 	/* If the buffer has already been allocated, return the memory to the free pool. */
66 	if (line_read) {
67 		free (line_read);
68 		line_read = (char *)NULL;
69 	}
70 
71 	/* Get a line from the user. */
72 	line_read = readline (thePrompt.c_str());
73 
74 	/* If the line has any text in it, save it on the history. */
75 	if (line_read && *line_read) add_history (line_read);
76 
77 	return (line_read);
78 }
79 
FindInstances(string theSubcircuit,bool thePrintCircuitFlag)80 void CCvcDb::FindInstances(string theSubcircuit, bool thePrintCircuitFlag) {
81 	size_t myInstanceCount = 0;
82 	try {
83 		CCircuit * myCircuit_p = cvcCircuitList.FindCircuit(theSubcircuit);
84 		for ( auto instance_pit = myCircuit_p->instanceId_v.begin(); instance_pit != myCircuit_p->instanceId_v.end(); instance_pit++ ) {
85 			int myMFactor = CalculateMFactor(*instance_pit);
86 			reportFile << HierarchyName(*instance_pit, thePrintCircuitFlag);
87 			if ( myMFactor > 1 ) {
88 				reportFile << " {m=" <<  myMFactor << "}";
89 				myInstanceCount += myMFactor;
90 			} else if ( instancePtr_v[*instance_pit]->IsParallelInstance() ) {
91 				reportFile << " {parallel}";
92 			} else {
93 				myInstanceCount++;
94 			}
95 			reportFile << endl;
96 		}
97 		reportFile << "found " << myInstanceCount << " instances" << endl;
98 	}
99 	catch (const out_of_range& oor_exception) {
100 		reportFile << "Searching for subcircuits matching " << theSubcircuit << endl;
101 		size_t myMatchCount = 0;
102 		vector<string> mySearchList;
103 		try {
104 			regex mySearchPattern(FuzzyFilter(theSubcircuit));
105 			mySearchList.reserve(cvcParameters.cvcSearchLimit);
106 			for( auto circuit_ppit = cvcCircuitList.begin(); circuit_ppit != cvcCircuitList.end(); circuit_ppit++) {
107 				if ( regex_match((*circuit_ppit)->name, mySearchPattern) ) {
108 					if ( myMatchCount++ < cvcParameters.cvcSearchLimit ) {
109 						mySearchList.push_back(string((*circuit_ppit)->name) + " #instances: " + to_string<uintmax_t>((*circuit_ppit)->instanceCount));
110 					}
111 				}
112 			}
113 			if ( myMatchCount == 0 ) {
114 				reportFile << "Could not find any subcircuits matching " << theSubcircuit << endl;
115 			} else {
116 				sort(mySearchList.begin(), mySearchList.end());
117 				for ( size_t myIndex = 0; myIndex < mySearchList.size(); myIndex++ ) {
118 					reportFile << mySearchList[myIndex] << endl;
119 				}
120 				reportFile << "Displayed " << mySearchList.size() << "/" << myMatchCount << " matches" << endl;
121 			}
122 		}
123 		catch (const regex_error& myError) {
124 			reportFile << "regex_error: " << RegexErrorString(myError.code()) << endl;
125 		}
126 	}
127 }
128 
FindNets(string theName,instanceId_t theInstanceId,bool thePrintCircuitFlag)129 void CCvcDb::FindNets(string theName, instanceId_t theInstanceId, bool thePrintCircuitFlag) {
130 	size_t myNetCount = 0;
131 	cout << "Searching..." << endl;
132 	gInterrupted = false;
133 	regex mySearchPattern(FuzzyFilter(theName));
134 	ShowNets(myNetCount, mySearchPattern, theInstanceId, thePrintCircuitFlag);
135 	if ( gInterrupted ) cout << "Search cancelled" << endl;
136 	reportFile << "Displayed " << ((myNetCount < cvcParameters.cvcSearchLimit) ? myNetCount : cvcParameters.cvcSearchLimit);
137 	reportFile << "/" << myNetCount << " matches." << endl;
138 }
139 
ShowNets(size_t & theNetCount,regex & theSearchPattern,instanceId_t theInstanceId,bool thePrintCircuitFlag)140 void CCvcDb::ShowNets(size_t & theNetCount, regex & theSearchPattern, instanceId_t theInstanceId, bool thePrintCircuitFlag) {
141 	// updates theNetCount
142 	if ( instancePtr_v[theInstanceId] == NULL ) return;
143 	if ( instancePtr_v[theInstanceId]->IsParallelInstance() ) return;
144 	CInstance * myInstance_p = instancePtr_v[theInstanceId];
145 	if ( myInstance_p->master_p->subcircuitPtr_v.size() == 0 && myInstance_p->master_p->devicePtr_v.size() == 0 ) return;
146 	for( auto signalMap_pit = myInstance_p->master_p->localSignalIdMap.begin(); signalMap_pit != myInstance_p->master_p->localSignalIdMap.end(); signalMap_pit++ ) {
147 		if ( gInterrupted ) return;
148 		if ( regex_match(signalMap_pit->first, theSearchPattern) ) {
149 			if ( theNetCount++ < cvcParameters.cvcSearchLimit ) {
150 				string myLowerNet = HierarchyName(theInstanceId, thePrintCircuitFlag) + "/" + signalMap_pit->first;
151 				netId_t myNetId = myInstance_p->localToGlobalNetId_v[signalMap_pit->second];
152 				netId_t myEquivalentNetId = (isFixedEquivalentNet) ? GetEquivalentNet(myNetId) : myNetId;
153 				string myTopNet = NetName(myEquivalentNetId, thePrintCircuitFlag);
154 				reportFile << myLowerNet;
155 				if ( myLowerNet != myTopNet ) {
156 					reportFile << " -> " << myTopNet;
157 				}
158 				reportFile << endl;
159 			}
160 		}
161 	}
162 	for( size_t instance_it = 0; instance_it != myInstance_p->master_p->subcircuitPtr_v.size(); instance_it++ ) {
163 		ShowNets(theNetCount, theSearchPattern, myInstance_p->firstSubcircuitId + instance_it, thePrintCircuitFlag);
164 	}
165 }
166 
FindSubcircuit(string theSubcircuit)167 CCircuit * CCvcDb::FindSubcircuit(string theSubcircuit) {
168 	try {
169 		return(cvcCircuitList.FindCircuit(theSubcircuit));
170 	}
171 	catch (const out_of_range& oor_exception) {
172 		reportFile << "Could not find subcircuit " << theSubcircuit << endl;
173 		return(NULL);
174 	}
175 }
176 
PrintSubcircuitCdl(string theSubcircuit)177 void CCvcDb::PrintSubcircuitCdl(string theSubcircuit) {
178 
179 	CCircuit * myCircuit = FindSubcircuit(theSubcircuit);
180 	if ( myCircuit == NULL ) return;
181 
182 	string myFileName = theSubcircuit + ".cdl";
183 	ofstream myCdlFile(myFileName);
184 	if (myCdlFile.fail()) {
185 		reportFile << "Could not open " << myFileName << endl;
186 		return;
187 	}
188 	unordered_set<text_t> myPrintedList;
189 	PrintHierarchicalCdl(myCircuit, myPrintedList, myCdlFile);
190 	myCdlFile << endl;
191 	reportFile << "Wrote subcircuit " << theSubcircuit << " to " << theSubcircuit << ".cdl" << endl;
192 	myCdlFile.close();
193 }
194 
FindHierarchy(instanceId_t theCurrentInstanceId,string theHierarchy,bool theAllowPartialMatch,bool thePrintUnmatchFlag)195 instanceId_t CCvcDb::FindHierarchy(instanceId_t theCurrentInstanceId, string theHierarchy, bool theAllowPartialMatch, bool thePrintUnmatchFlag) {
196 	// HIERARCHY_DELIMITER is only used to delimit hierarchy
197 	if ( theHierarchy.find_first_of(cvcParameters.cvcHierarchyDelimiters, 0) == 0 ) {  // starts with delimiter
198 		theCurrentInstanceId = 0;
199 		theHierarchy = theHierarchy.substr(1);
200 	}
201 	size_t myStringBegin = 0;
202 	size_t myStringEnd;
203 	string myInstanceName;
204 	string myUnmatchedHierarchy = "";
205 	instanceId_t myLocalInstanceId;
206 	while ( myStringBegin <= theHierarchy.length() ) {
207 		try {
208 			myStringEnd = theHierarchy.find_first_of(cvcParameters.cvcHierarchyDelimiters, myStringBegin);
209 			myInstanceName = theHierarchy.substr(myStringBegin, myStringEnd - myStringBegin);
210 			try {
211 				myInstanceName = myInstanceName.erase(myInstanceName.find_first_of("("));
212 			}
213 			catch (...) {
214 			}
215 			if ( ! IsEmpty(myUnmatchedHierarchy) ) {
216 				myInstanceName = myUnmatchedHierarchy + HIERARCHY_DELIMITER + myInstanceName;
217 			}
218 			if ( myInstanceName == ".." ) {
219 				theCurrentInstanceId = instancePtr_v[theCurrentInstanceId]->parentId;
220 			} else {
221 				myLocalInstanceId = instancePtr_v[theCurrentInstanceId]->master_p->GetLocalSubcircuitId(cvcCircuitList.cdlText.GetTextAddress(myInstanceName));
222 				theCurrentInstanceId = instancePtr_v[theCurrentInstanceId]->firstSubcircuitId + myLocalInstanceId;
223 			}
224 			myUnmatchedHierarchy = "";
225 		}
226 		catch (const out_of_range& oor_exception) {
227 			myUnmatchedHierarchy = myInstanceName;
228 		}
229 		myStringBegin = theHierarchy.find_first_not_of(cvcParameters.cvcHierarchyDelimiters, myStringEnd);
230 	}
231 	if ( IsEmpty(myUnmatchedHierarchy) || theAllowPartialMatch ) {
232 		;  // For next searches, the last hierarchy may be part of a flattened hierarchy
233 	} else {
234 		theCurrentInstanceId = UNKNOWN_INSTANCE;
235 		if ( thePrintUnmatchFlag ) {
236 			reportFile << "Could not find instance " << myInstanceName << endl;
237 		}
238 	}
239 	return ( theCurrentInstanceId );
240 }
241 
ShortString(netId_t theNetId,bool thePrintSubcircuitNameFlag)242 string CCvcDb::ShortString(netId_t theNetId, bool thePrintSubcircuitNameFlag) {
243 	string myShortString = "";
244 	if ( netVoltagePtr_v[theNetId].full ) {
245 		string myStandardDefinition = netVoltagePtr_v[theNetId].full->StandardDefinition();
246 		if ( IsCalculatedVoltage_(netVoltagePtr_v[theNetId].full) ) {
247 			myShortString += " calculated as";
248 		} else {
249 			myShortString += " defined as ";
250 		}
251 		if ( string(netVoltagePtr_v[theNetId].full->definition) != myStandardDefinition ) {
252 			myShortString = myShortString + netVoltagePtr_v[theNetId].full->definition + " => ";
253 		}
254 		myShortString += myStandardDefinition;
255 	}
256 	return myShortString;
257 }
258 
LeakShortString(netId_t theNetId,bool thePrintSubcircuitNameFlag)259 string CCvcDb::LeakShortString(netId_t theNetId, bool thePrintSubcircuitNameFlag) {
260 	string myShortString = "";
261 	CPower * myLeakPower_p = leakVoltagePtr_v[theNetId].full;
262 	if ( myLeakPower_p ) {
263 		string myStandardDefinition = myLeakPower_p->StandardDefinition();
264 		if ( IsCalculatedVoltage_(myLeakPower_p) ) {
265 				myShortString += " calculated as";
266 		} else {
267 				myShortString += " defined as ";
268 		}
269 		if ( string(myLeakPower_p->definition) != myStandardDefinition ) {
270 				myShortString = myShortString + myLeakPower_p->definition + " => ";
271 		}
272 		myShortString += myStandardDefinition;
273 	}
274 	return myShortString;
275 }
276 
PrintParallelInstance(instanceId_t theInstanceId,bool thePrintSubcircuitNameFlag)277 void CCvcDb::PrintParallelInstance(instanceId_t theInstanceId, bool thePrintSubcircuitNameFlag) {
278 	reportFile << "Parallel Instance: " << HierarchyName(theInstanceId, thePrintSubcircuitNameFlag) << endl;
279 	if  ( instancePtr_v[theInstanceId]->parallelInstanceId != 0 ) {
280 		reportFile << "Merged with: " << HierarchyName(instancePtr_v[theInstanceId]->parallelInstanceId, thePrintSubcircuitNameFlag) << endl;
281 	} else {
282 		instanceId_t myInstanceId = theInstanceId;
283 		while ( instancePtr_v[myInstanceId]->IsParallelInstance() && instancePtr_v[myInstanceId]->parallelInstanceId == 0 ) {
284 			myInstanceId = instancePtr_v[myInstanceId]->parentId;
285 		}
286 		reportFile << "Merged at: " << HierarchyName(instancePtr_v[myInstanceId]->parallelInstanceId, thePrintSubcircuitNameFlag) << endl;
287 	}
288 }
289 
PrintNets(instanceId_t theCurrentInstanceId,string theFilter,bool thePrintSubcircuitNameFlag,bool theIsValidPowerFlag)290 void CCvcDb::PrintNets(instanceId_t theCurrentInstanceId, string theFilter, bool thePrintSubcircuitNameFlag, bool theIsValidPowerFlag) {
291 	if ( instancePtr_v[theCurrentInstanceId]->IsParallelInstance() ) {
292 		PrintParallelInstance(theCurrentInstanceId, thePrintSubcircuitNameFlag);
293 		return;
294 	}
295 	CCircuit * myMasterCircuit_p = instancePtr_v[theCurrentInstanceId]->master_p;
296 	CTextVector mySignal_v;
297 	stringstream myNetString;
298 	netId_t myGlobalNetId;
299 	vector<string> mySearchList;
300 	size_t myMatchCount = 0;
301 	try {
302 		regex mySearchPattern(FuzzyFilter(theFilter));
303 		mySignal_v.reserve(myMasterCircuit_p->localSignalIdMap.size());
304 		mySearchList.reserve(mySignal_v.capacity());
305 		for ( auto pair_pit = myMasterCircuit_p->localSignalIdMap.begin(); pair_pit != myMasterCircuit_p->localSignalIdMap.end(); pair_pit++ ) {
306 			mySignal_v[pair_pit->second] = pair_pit->first;
307 		}
308 		for ( netId_t net_it = 0; net_it < myMasterCircuit_p->localSignalIdMap.size(); net_it++ ) {
309 			if ( net_it == myMasterCircuit_p->portCount && net_it != 0 ) {
310 				reportFile << "Ports:" << endl;
311 				sort(mySearchList.begin(), mySearchList.end());
312 				for ( size_t myIndex = 0; myIndex < mySearchList.size(); myIndex++ ) {
313 					reportFile << mySearchList[myIndex] << endl;
314 				}
315 				reportFile << "Displayed " << mySearchList.size() << "/" << myMatchCount << " matches" << endl;
316 				myMatchCount = 0;
317 				mySearchList.clear();
318 			}
319 			myGlobalNetId = instancePtr_v[theCurrentInstanceId]->localToGlobalNetId_v[net_it];
320 			string	myGlobalNet = "";
321 			if ( thePrintSubcircuitNameFlag ) {
322 				myGlobalNet = "(";
323 				myGlobalNet += NetName(myGlobalNetId, false);
324 				myGlobalNet += ")";
325 			}
326 			myNetString.str("");
327 			myNetString << mySignal_v[net_it] << myGlobalNet << ((theIsValidPowerFlag) ? ShortString(myGlobalNetId, thePrintSubcircuitNameFlag) : "");
328 			if ( IsEmpty(theFilter) || regex_match(mySignal_v[net_it], mySearchPattern) ) {
329 				if ( myMatchCount++ < cvcParameters.cvcSearchLimit ) {
330 					mySearchList.push_back(myNetString.str());
331 				}
332 			}
333 		}
334 		reportFile << "Internal nets:" << endl;
335 		sort(mySearchList.begin(), mySearchList.end());
336 		for ( size_t myIndex = 0; myIndex < mySearchList.size(); myIndex++ ) {
337 			reportFile << mySearchList[myIndex] << endl;
338 		}
339 		reportFile << "Displayed " << mySearchList.size() << "/" << myMatchCount << " matches" << endl;
340 	}
341 	catch (const regex_error& myError) {
342 		reportFile << "regex_error: " << RegexErrorString(myError.code()) << endl;
343 	}
344 
345 }
346 
PrintDevices(instanceId_t theCurrentInstanceId,string theFilter,bool thePrintSubcircuitNameFlag,bool theIsValidModelFlag)347 void CCvcDb::PrintDevices(instanceId_t theCurrentInstanceId, string theFilter, bool thePrintSubcircuitNameFlag, bool theIsValidModelFlag) {
348 	if ( instancePtr_v[theCurrentInstanceId]->IsParallelInstance() ) {
349 		PrintParallelInstance(theCurrentInstanceId, thePrintSubcircuitNameFlag);
350 		return;
351 	}
352 	string	myParameters = "";
353 	stringstream myDeviceString;
354 	vector<string> mySearchList;
355 	size_t myMatchCount = 0;
356 	try {
357 		regex mySearchPattern(FuzzyFilter(theFilter));
358 		CCircuit * myMasterCircuit_p = instancePtr_v[theCurrentInstanceId]->master_p;
359 		mySearchList.reserve(myMasterCircuit_p->devicePtr_v.size());
360 		for ( auto device_ppit = myMasterCircuit_p->devicePtr_v.begin();
361 				device_ppit != myMasterCircuit_p->devicePtr_v.end(); device_ppit++ ) {
362 			if ( thePrintSubcircuitNameFlag ) {
363 				myParameters = "(";
364 				myParameters += (*device_ppit)->parameters;
365 				myParameters += ")";
366 			}
367 			myDeviceString.str("");
368 			myDeviceString << (*device_ppit)->name << myParameters << " " << ((theIsValidModelFlag) ? (*device_ppit)->model_p->definition : "" );
369 			if ( IsEmpty(theFilter) || regex_match((*device_ppit)->name, mySearchPattern) ) {
370 				if ( myMatchCount++ < cvcParameters.cvcSearchLimit ) {
371 					mySearchList.push_back(myDeviceString.str());
372 				}
373 			}
374 		}
375 		sort(mySearchList.begin(), mySearchList.end());
376 		for ( size_t myIndex = 0; myIndex < mySearchList.size(); myIndex++ ) {
377 			reportFile << mySearchList[myIndex] << endl;
378 		}
379 		reportFile << "Displayed " << mySearchList.size() << "/" << myMatchCount << " matches" << endl;
380 	}
381 	catch (const regex_error& myError) {
382 		reportFile << "regex_error: " << RegexErrorString(myError.code()) << endl;
383 	}
384 }
385 
PrintInstances(instanceId_t theCurrentInstanceId,string theFilter,bool thePrintSubcircuitNameFlag)386 void CCvcDb::PrintInstances(instanceId_t theCurrentInstanceId, string theFilter, bool thePrintSubcircuitNameFlag) {
387 	if ( instancePtr_v[theCurrentInstanceId]->IsParallelInstance() ) {
388 		PrintParallelInstance(theCurrentInstanceId, thePrintSubcircuitNameFlag);
389 		return;
390 	}
391 	string	myMasterName = "";
392 	stringstream myInstanceString;
393 	vector<string> mySearchList;
394 	size_t myMatchCount = 0;
395 	try {
396 		regex mySearchPattern(FuzzyFilter(theFilter));
397 		CCircuit * myMasterCircuit_p = instancePtr_v[theCurrentInstanceId]->master_p;
398 		mySearchList.reserve(myMasterCircuit_p->subcircuitPtr_v.size());
399 		for ( auto subcircuit_ppit = myMasterCircuit_p->subcircuitPtr_v.begin();
400 				subcircuit_ppit != myMasterCircuit_p->subcircuitPtr_v.end(); subcircuit_ppit++ ) {
401 			if ( thePrintSubcircuitNameFlag ) {
402 				myMasterName = "(";
403 				myMasterName += (*subcircuit_ppit)->masterName;
404 				myMasterName += ")";
405 			}
406 			myInstanceString.str("");
407 			myInstanceString << (*subcircuit_ppit)->name << myMasterName;
408 			if ( IsEmpty(theFilter) || regex_match((*subcircuit_ppit)->name, mySearchPattern) ) {
409 				if ( myMatchCount++ < cvcParameters.cvcSearchLimit ) {
410 					mySearchList.push_back(myInstanceString.str());
411 				}
412 			}
413 		}
414 		sort(mySearchList.begin(), mySearchList.end());
415 		for ( size_t myIndex = 0; myIndex < mySearchList.size(); myIndex++ ) {
416 			reportFile << mySearchList[myIndex] << endl;
417 		}
418 		reportFile << "Displayed " << mySearchList.size() << "/" << myMatchCount << " matches" << endl;
419 	}
420 	catch (const regex_error& myError) {
421 		reportFile << "regex_error: " << RegexErrorString(myError.code()) << endl;
422 	}
423 }
424 
425 /*
426 void CCvcDb::ReadShorts(string theShortFileName) {
427 	// TODO: make sure short output applies to current data base
428 	igzstream myShortFile(theShortFileName);
429 	if ( myShortFile.fail() ) {
430 		reportFile << "ERROR: Could not open " << theShortFileName << endl;
431 		return;
432 	}
433 	string	myInputLine;
434 	char	myValue[256];
435 	netId_t myNetId, myShortId;
436 //	voltage_t myVoltage;
437 //	resistance_t myResistance;
438 	int myInputCount;
439 	try {
440 		while ( getline(myShortFile, myInputLine) ) {
441 			myValue[0] = '\0';
442 			myInputCount = sscanf(myInputLine.c_str(), "%u->%u%s", &myNetId, &myShortId, myValue);
443 			if ( myInputCount == 1 ) {
444 				myInputCount = sscanf(myInputLine.c_str(), "%u%s", &myNetId, myValue);
445 				myShortId = myNetId;
446 			}
447 			if ( myNetId >= netCount ) throw EShortFileError();
448 			short_v[myNetId].first = myShortId;
449 			short_v[myNetId].second = myValue;
450 		}
451 		isValidShortData = true;
452 	}
453 	catch (exception& e) {
454 		reportFile << "Error reading short file" << endl;
455 		isValidShortData = false;
456 		ResetVector<CShortVector>(short_v, netCount);
457 	}
458 }
459 */
460 
FindNet(instanceId_t theCurrentInstanceId,string theNetName,bool theDisplayErrorFlag)461 netId_t CCvcDb::FindNet(instanceId_t theCurrentInstanceId, string theNetName, bool theDisplayErrorFlag) {
462 	instanceId_t myCurrentInstanceId;
463 	string myInitialHierarchy;
464 	string mySearchHierarchy;
465 	if (theNetName.length() > theNetName.find_last_of(cvcParameters.cvcHierarchyDelimiters) ) {
466 		mySearchHierarchy = theNetName.substr(0, theNetName.find_last_of(cvcParameters.cvcHierarchyDelimiters));
467 	} else {
468 		mySearchHierarchy = "";
469 	}
470 	string myNetName;
471 	try {
472 		if ( theNetName.find_first_of(cvcParameters.cvcHierarchyDelimiters, 0) == 0 ) {  // starts with delimiter
473 			myInitialHierarchy = "";
474 			myCurrentInstanceId = FindHierarchy(0, mySearchHierarchy, true, false);
475 		} else {
476 			myInitialHierarchy = HierarchyName(theCurrentInstanceId, false) + HIERARCHY_DELIMITER;
477 			myCurrentInstanceId = FindHierarchy(theCurrentInstanceId, mySearchHierarchy, true, false);
478 		}
479 		if ( myCurrentInstanceId == UNKNOWN_INSTANCE ) throw out_of_range("not found");
480 		if ( instancePtr_v[theCurrentInstanceId]->IsParallelInstance() ) {
481 			PrintParallelInstance(theCurrentInstanceId, false);
482 			return ( UNKNOWN_NET );
483 		}
484 		CCircuit * myCircuit_p = instancePtr_v[myCurrentInstanceId]->master_p;
485 		string myParentName = HierarchyName(myCurrentInstanceId, false) + HIERARCHY_DELIMITER;
486 		myNetName = theNetName.substr(myParentName.length() - myInitialHierarchy.length());
487 		return instancePtr_v[myCurrentInstanceId]->localToGlobalNetId_v[myCircuit_p->localSignalIdMap.at(cvcCircuitList.cdlText.GetTextAddress(myNetName))];
488 	}
489 	catch (const out_of_range& oor_exception) {
490 		if ( theDisplayErrorFlag ) {
491 			reportFile << "Could not find net " << myInitialHierarchy << myNetName << endl;
492 		}
493 	}
494 	return ( UNKNOWN_NET );
495 }
496 
FindDevice(instanceId_t theCurrentInstanceId,string theDeviceName)497 deviceId_t CCvcDb::FindDevice(instanceId_t theCurrentInstanceId, string theDeviceName) {
498 	instanceId_t myCurrentInstanceId;
499 	string myInitialHierarchy;
500 	string mySearchHierarchy;
501 	if (theDeviceName.length() > theDeviceName.find_last_of(cvcParameters.cvcHierarchyDelimiters) ) {
502 		mySearchHierarchy = theDeviceName.substr(0, theDeviceName.find_last_of(cvcParameters.cvcHierarchyDelimiters));
503 	} else {
504 		mySearchHierarchy = "";
505 	}
506 	string myDeviceName;
507 	try {
508 		if ( theDeviceName.find_first_of(cvcParameters.cvcHierarchyDelimiters, 0) == 0 ) {  // starts with delimiter
509 			myInitialHierarchy = "";
510 			myCurrentInstanceId = FindHierarchy(0, mySearchHierarchy, true, false);
511 		} else {
512 			myInitialHierarchy = HierarchyName(theCurrentInstanceId, false) + HIERARCHY_DELIMITER;
513 			myCurrentInstanceId = FindHierarchy(theCurrentInstanceId, mySearchHierarchy, true, false);
514 		}
515 		if ( myCurrentInstanceId == UNKNOWN_INSTANCE ) throw out_of_range("not found");
516 		if ( instancePtr_v[theCurrentInstanceId]->IsParallelInstance() ) {
517 			PrintParallelInstance(theCurrentInstanceId, false);
518 			return ( UNKNOWN_DEVICE );
519 		}
520 		CCircuit * myCircuit_p = instancePtr_v[myCurrentInstanceId]->master_p;
521 		string myParentName = HierarchyName(myCurrentInstanceId, false) + HIERARCHY_DELIMITER;
522 		myDeviceName = theDeviceName.substr(myParentName.length() - myInitialHierarchy.length());
523 		return instancePtr_v[myCurrentInstanceId]->firstDeviceId + myCircuit_p->GetLocalDeviceId(cvcCircuitList.cdlText.GetTextAddress(myDeviceName));
524 	}
525 	catch (const out_of_range& oor_exception) {
526 		reportFile << "Could not find device " << HierarchyName(myCurrentInstanceId) << HIERARCHY_DELIMITER << myDeviceName << endl;
527 	}
528 	return ( UNKNOWN_DEVICE );
529 }
530 
InteractiveCvc(int theCurrentStage)531 returnCode_t CCvcDb::InteractiveCvc(int theCurrentStage) {
532 	string	myInputLine;
533 	char *	myInput;
534 	char myInputBuffer[1024];
535 	istringstream myInputStream;
536 	string	myCommand;
537 	string	myOption;
538 	string	myHierarchy;
539 	string	myFilter;
540 	string	mySubcircuit;
541 	string	myFileName;
542 	string	myName;
543 	string	myNumberString;
544 	string	myCommandMode = "";
545 	list<streambuf *> mySavedBufferStack;
546 	ifstream *myBatchFile;
547 	bool myIsBatchInput = false;
548 	int mySearchLimit;
549 	static instanceId_t myCurrentInstanceId = 0;
550 	bool	myPrintSubcircuitNameFlag = false;
551 	size_t	myNumber;
552 	returnCode_t		myReturnCode = UNKNOWN_RETURN_CODE;
553 	stringstream	myPrompt;
554 
555 	while ( myReturnCode == UNKNOWN_RETURN_CODE ) {
556 		reportFile.flush();
557 		myPrompt.clear();
558 		myPrompt.str("");
559 		if ( myCommandMode == "fs" ) {
560 			myPrompt << "--> find subcircuit (^D to exit) ?> ";
561 		} else if ( myCommandMode == "fn" ) {
562 				myPrompt << "--> find net (^D to exit) ?> ";
563 		} else if ( myCommandMode == "pd" ) {
564 			myPrompt << "--> print device (^D to exit) ?> ";
565 		} else if ( myCommandMode == "ph" ) {
566 			myPrompt << "--> print hierarchy (^D to exit) ?> ";
567 		} else if ( myCommandMode == "pi" ) {
568 			myPrompt << "--> print instance (^D to exit) ?> ";
569 		} else if ( myCommandMode == "pn" ) {
570 			myPrompt << "--> print net (^D to exit) ?> ";
571 		} else if ( myCommandMode == "gd" ) {
572 			myPrompt << "--> get device (^D to exit) ?> ";
573 		} else if ( myCommandMode == "gh" ) {
574 			myPrompt << "--> get hierarchy (^D to exit) ?> ";
575 		} else if ( myCommandMode == "gi" ) {
576 			myPrompt << "--> get instance (^D to exit) ?> ";
577 		} else if ( myCommandMode == "gn" ) {
578 			myPrompt << "--> get net (^D to exit) ?> ";
579 		} else if ( myCommandMode == "en" ) {
580 			myPrompt << "--> expand net (^D to exit) ?> ";
581 		} else if ( myCommandMode == "ed" ) {
582 			myPrompt << "--> expand device (^D to exit) ?> ";
583 		} else if ( myCommandMode == "ei" ) {
584 			myPrompt << "--> expand instance (^D to exit) ?> ";
585 		} else {
586 			myPrompt << "** Stage " << theCurrentStage << "/" << STAGE_COMPLETE << ": Enter command ?> ";
587 		}
588 		if ( myIsBatchInput ) {
589 			cin.getline(myInputBuffer, 1024);
590 			if ( cin.eof() ) {
591 				myInput = NULL;
592 			} else {
593 				myInput = myInputBuffer;
594 			}
595 		} else {
596 			myInput = rl_gets(myPrompt.str());
597 		}
598 		if ( myInput == NULL ) { // eof
599 			if ( myIsBatchInput ) {
600 				reportFile << "finished source. Depth " << mySavedBufferStack.size() << endl;
601 				cin.rdbuf(mySavedBufferStack.front());
602 				mySavedBufferStack.pop_front();
603 				myCommandMode = "";
604 				if ( mySavedBufferStack.empty() ) {
605 					myIsBatchInput = false;
606 				}
607 			} else if ( IsEmpty(myCommandMode) ){
608 				gInteractive_cvc = false;
609 				cin.clear();
610 				myReturnCode = OK;
611 			} else {
612 				myCommandMode = "";
613 			}
614 			reportFile << endl;
615 			continue;
616 		}
617 		reportFile << endl << "> " << myInput << endl;
618 		try {
619 			myInputLine = myInput;
620 			myInputStream.str(myInputLine);
621 			myInputStream.clear();
622 			if ( IsEmpty(myCommandMode) ) {
623 				if ( ! (myInputStream >> myCommand) ) continue;
624 			} else {
625 				myCommand = myCommandMode;
626 			}
627 			if ( myCommand == "findsubcircuit" || myCommand == "fs" ) {
628 				if ( myInputStream >> mySubcircuit ) {
629 					FindInstances(mySubcircuit, myPrintSubcircuitNameFlag);
630 				} else {
631 					myCommandMode = "fs";
632 				}
633 			} else if ( myCommand == "findnet" || myCommand == "fn" ) {
634 				if ( myInputStream >> myName ) {
635 					FindNets(myName, myCurrentInstanceId, myPrintSubcircuitNameFlag);
636 				} else {
637 					myCommandMode = "fn";
638 				}
639 			} else if ( myCommand == "goto" || myCommand == "g" || myCommand == "cd" ) {
640 				myHierarchy = "/"; // default returns to top
641 				myInputStream >> myHierarchy;
642 				instanceId_t myNewInstanceId = FindHierarchy(myCurrentInstanceId, RemoveCellNames(myHierarchy));
643 				if ( myNewInstanceId == UNKNOWN_INSTANCE ) {
644 					cout << "Could not find instance " << myHierarchy << endl;
645 				} else {
646 					myCurrentInstanceId = myNewInstanceId;
647 				}
648 			} else if ( myCommand == "help" || myCommand == "h" ) {
649 				cout << "Available commands are:" << endl;
650 				cout << "<ctrl-d> switch to automatic (i.e. end interactive)" << endl;
651 				cout << "searchlimit<sl> [limit]: set search limit" << endl;
652 				cout << "hierarchydelimiter<hd> [character]: set interactive hierarchy delimiter" << endl;
653 				cout << "goto<g|cd> <hierarchy>: goto hierarchy" << endl;
654 				cout << "currenthierarchy<ch|pwd>: print current hierarchy" << endl;
655 				cout << "printhierarchy<ph> hierarchynumber: print hierarchy name" << endl;
656 				cout << "printdevice<pd> devicenumber: print device name" << endl;
657 				cout << "printnet<pn> netnumber: print net name" << endl;
658 				cout << "listnet|listdevice|listinstance<ln|ld|li> filter: list net|device|instances in current subcircuit filtered by filter" << endl;
659 				cout << "getnet|getdevice|getinstance<gn|gd|gi> name: get net|device|instance number for name" << endl;
660 				cout << "expandnet|expanddevice|expandinstance<en|ed|ei> name: expand net|device|instance to top level" << endl;
661 				cout << "getsim name: expand nets and print sim value" << endl;
662 				cout << "dumpfuse<df> filename: dump fuse to filename" << endl;
663 				cout << "dumpanalognets<dan> filename: dump analog nets to filename" << endl;
664 				cout << "dumpunknownlogicalnets<duln> filename: dump unknown logical nets to filename" << endl;
665 				cout << "dumpunknownlogicalports<dulp> filter filename: dump unknown logical ports matching filter in current hierarchy to filename" << endl;
666 				cout << "dumplevelshifter<dls> filename: dump level shifters to filename" << endl;
667 				cout << "traceinverter<ti> name: trace signal as inverter output for name" << endl;
668 				cout << "findsubcircuit<fs> subcircuit: list all instances of subcircuit or if regex, subcircuits that match" << endl;
669 				cout << "findnet<fn> net: list all nets that match in lower subcircuits." << endl;
670 				cout << "printcdl<pc> subcircuit: print subcircuit as subcircuit.cdl" << endl;
671 				cout << "printenvironment<pe>: print simulation environment" << endl;
672 				cout << "togglename<n>: toggle subcircuit names" << endl;
673 //				cout << "shortfile<s> file: use file as shorts" << endl;
674 				cout << "setpower<sp> file: use file as power" << endl;
675 				cout << "setmodel<sm> file: use file as model" << endl;
676 				cout << "setfuse<sf> file: use file as fuse overrides" << endl;
677 				cout << "printpower<pp>: print power settings" << endl;
678 				cout << "printmodel<pm>: print model statistics" << endl;
679 				cout << "source file: read commands from file" << endl;
680 				cout << "debug instance id: create debug.cvcrc.id file for debugging instance" << endl;
681 				cout << "noerror: skip error processing (just propagation)" << endl;
682 				cout << "skip: skip this cvcrc and use next one" << endl;
683 				cout << "rerun: rerun this cvcrc" << endl;
684 				cout << "continue<c>: continue" << endl;
685 				cout << "help<h>: help" << endl;
686 				cout << "quit<q>: quit" << endl;
687 			} else if ( myCommand == "source" ) {
688 				myFileName = "";
689 				myInputStream >> myFileName;
690 				myBatchFile = new ifstream(myFileName);
691 				if ( myBatchFile && myBatchFile->good() ) {
692 					myIsBatchInput = true;
693 					mySavedBufferStack.push_front(cin.rdbuf());
694 					cout << "sourcing from " << myFileName << ". Depth " << mySavedBufferStack.size() << endl;
695 					cin.rdbuf(myBatchFile->rdbuf());
696 				} else {
697 					reportFile << "Could not open " << myFileName << endl;
698 				}
699 			} else if ( myCommand == "debug" ) {
700 				if ( theCurrentStage < STAGE_FIRST_SIM ) {
701 					reportFile << "ERROR: Can only debug after final sim." << endl;
702 					continue;
703 				}
704 				string myInstanceName = "";
705 				myInputStream >> myInstanceName;
706 				instanceId_t myInstanceId = FindHierarchy(myCurrentInstanceId, RemoveCellNames(myInstanceName));
707 				if ( myInstanceId == UNKNOWN_INSTANCE ) {
708 					cout << "ERROR: Could not find " << myInstanceName << endl;
709 					continue;
710 				}
711 				string myCell = "";
712 				myInputStream >> myCell;
713 				string myDebugCvcrcName = "debug.cvcrc." + myCell + "." + cvcParameters.cvcMode;
714 				ofstream myDebugCvcrcFile(myDebugCvcrcName);
715 				if ( myDebugCvcrcFile && myDebugCvcrcFile.good() ) {
716 					CreateDebugCvcrcFile(myDebugCvcrcFile, myInstanceId, myCell, theCurrentStage);
717 					cout << "Wrote debug cvcrc file " << myDebugCvcrcName << endl;
718 				} else {
719 					cout << "ERROR: Could not create cvcrc file " << myDebugCvcrcName << endl;
720 				}
721 			} else if ( myCommand == "noerror" ) {
722 				cout << "WARNING: Ignoring errors." << endl;
723 				errorFile << "WARNING: ERROR DETECTION HALTED" << endl;
724 				detectErrorFlag = false;
725 			} else if ( myCommand == "setmodel" || myCommand == "sm" ) {
726 				if ( theCurrentStage != STAGE_START ) {
727 					reportFile << "ERROR: Can only change model file at stage 1." << endl;
728 					continue;
729 				}
730 				myFileName = "";
731 				myInputStream >> myFileName;
732 				cvcParameters.cvcModelFilename = myFileName;
733 				if ( ( modelFileStatus = cvcParameters.LoadModels() ) == OK ) {
734 					powerFileStatus = SetModePower();
735 					modelFileStatus = SetDeviceModels();
736 				}
737 				if ( modelFileStatus == OK ) {
738 					fuseFileStatus = CheckFuses();
739 				} else if ( ! IsEmpty(cvcParameters.cvcFuseFilename) ){
740 					reportFile << "WARNING: fuse file not checked due to invalid model file" << endl;
741 					fuseFileStatus = SKIP;
742 				}
743 			} else if ( myCommand == "setpower" || myCommand == "sp" ) {
744 				if ( theCurrentStage != 1 ) {
745 					reportFile << "ERROR: Can only change power file at stage 1." << endl;
746 					continue;
747 				}
748 				myFileName = "";
749 				myInputStream >> myFileName;
750 				cvcParameters.cvcPowerFilename = myFileName;
751 				if ( ( powerFileStatus = cvcParameters.LoadPower() ) == OK ) {
752 					powerFileStatus = SetModePower();
753 					modelFileStatus = SetDeviceModels();
754 				}
755 			} else if ( myCommand == "setfuse" || myCommand == "sf" ) {
756 				if ( theCurrentStage != 1 ) {
757 					reportFile << "ERROR: Can only change fuse file at stage 1." << endl;
758 					continue;
759 				}
760 				myFileName = "";
761 				myInputStream >> myFileName;
762 				cvcParameters.cvcFuseFilename = myFileName;
763 				if ( modelFileStatus == OK ) {
764 					fuseFileStatus = CheckFuses();
765 				} else if ( ! IsEmpty(cvcParameters.cvcFuseFilename) ){
766 					reportFile << "WARNING: fuse file not checked due to invalid model file" << endl;
767 					fuseFileStatus = SKIP;
768 				}
769 			} else if ( myCommand == "searchlimit" || myCommand == "sl" ) {
770 				if ( myInputStream >> mySearchLimit ) {
771 					cvcParameters.cvcSearchLimit = mySearchLimit;
772 					reportFile << "Search limit set to: " << cvcParameters.cvcSearchLimit << endl;
773 				} else {
774 					reportFile << "Current search limit: " << cvcParameters.cvcSearchLimit << endl;
775 				}
776 			} else if ( myCommand == "hierarchydelimiter" || myCommand == "hd" ) {
777 				string myHierarchyDelimiters;
778 				if ( myInputStream >> myHierarchyDelimiters ) {
779 					cvcParameters.cvcHierarchyDelimiters = myHierarchyDelimiters;
780 					reportFile << "Hierarchy delimiter(s) set to: '" << cvcParameters.cvcHierarchyDelimiters << "'" << endl;
781 				} else {
782 					reportFile << "Current hierarchy delimiter(s): '" << cvcParameters.cvcHierarchyDelimiters << "'" << endl;
783 				}
784 			} else if ( myCommand == "printmodel" || myCommand == "pm" ) {
785 				cvcParameters.cvcModelListMap.Print(reportFile);
786 			} else if ( myCommand == "printpower" || myCommand == "pp" ) {
787 				PrintPowerList(reportFile);
788 			} else if ( myCommand == "printcdl" || myCommand == "pc" ) {
789 				mySubcircuit = "";
790 				myInputStream >> mySubcircuit;
791 				PrintSubcircuitCdl(mySubcircuit);
792 			} else if ( myCommand == "printenvironment" || myCommand == "pe" ) {
793 				cvcParameters.PrintEnvironment(reportFile);
794 			} else if ( myCommand == "listnet" || myCommand == "ln" ) {
795 				if ( myInputStream >> myFilter ) {
796 					PrintNets(myCurrentInstanceId, myFilter, myPrintSubcircuitNameFlag, powerFileStatus == OK);
797 				} else {
798 					PrintNets(myCurrentInstanceId, "", myPrintSubcircuitNameFlag, powerFileStatus == OK);
799 				}
800 			} else if ( myCommand == "listdevice" || myCommand == "ld" ) {
801 				if ( myInputStream >> myFilter ) {
802 					PrintDevices(myCurrentInstanceId, myFilter, myPrintSubcircuitNameFlag, modelFileStatus == OK);
803 				} else {
804 					PrintDevices(myCurrentInstanceId, "", myPrintSubcircuitNameFlag, modelFileStatus == OK);
805 				}
806 			} else if ( myCommand == "listinstance" || myCommand == "li" ) {
807 				if ( myInputStream >> myFilter ) {
808 					PrintInstances(myCurrentInstanceId, myFilter, myPrintSubcircuitNameFlag);
809 				} else {
810 					PrintInstances(myCurrentInstanceId, "", myPrintSubcircuitNameFlag);
811 				}
812 			} else if ( myCommand == "expandnet" || myCommand == "en" ) {
813 				if ( myInputStream >> myName ) {
814 					set<netId_t> * myNetIdList = FindUniqueNetIds(myName); // expands buses and hierarchy
815 					for (auto netId_pit = myNetIdList->begin(); netId_pit != myNetIdList->end(); netId_pit++) {
816 						  netId_t myEquivalentNetId = (isFixedEquivalentNet) ? GetEquivalentNet(*netId_pit) : *netId_pit;
817 						  string myTopNet = NetName(myEquivalentNetId, myPrintSubcircuitNameFlag);
818 						  reportFile << myTopNet << endl;
819 					}
820 					if ( myNetIdList->empty() ) {
821 						reportFile << "* Could not expand net " << myName << endl;
822 					}
823 				} else {
824 					myCommandMode = "en";
825 				}
826 			} else if ( myCommand == "getsim" ) {
827 				if ( myInputStream >> myName ) {
828 					set<netId_t> * myNetIdList = FindUniqueNetIds(myName); // expands buses and hierarchy
829 					for (auto netId_pit = myNetIdList->begin(); netId_pit != myNetIdList->end(); netId_pit++) {
830 						netId_t myEquivalentNetId = (isFixedEquivalentNet) ? GetEquivalentNet(*netId_pit) : *netId_pit;
831 						string myTopNet = NetName(myEquivalentNetId, myPrintSubcircuitNameFlag);
832 						netId_t myFinalNet = simNet_v[myEquivalentNetId].finalNetId;
833 						reportFile << myTopNet << " ";
834 						if ( netVoltagePtr_v[myFinalNet].full ) {
835 							netVoltagePtr_v[myFinalNet].full->Print(reportFile);
836 						} else {
837 							reportFile << endl;
838 						}
839 					}
840 					if ( myNetIdList->empty() ) {
841 						reportFile << "* Could not expand net " << myName << endl;
842 					}
843 				}
844 			} else if ( myCommand == "expanddevice" || myCommand == "ed" ) {
845 				if ( myInputStream >> myName ) {
846 					reportFile << "expanddevice not yet implemented" << endl;
847 				} else {
848 					myCommandMode = "ed";
849 				}
850 			} else if ( myCommand == "expandinstance" || myCommand == "ei" ) {
851 				if ( myInputStream >> myName ) {
852 					reportFile << "expandinstance not yet implemented" << endl;
853 				} else {
854 					myCommandMode = "ei";
855 				}
856 			} else if ( myCommand == "dumpfuse" || myCommand == "df" ) {
857 				if ( myInputStream >> myFileName ) {
858 					if ( modelFileStatus == OK ) {
859 						DumpFuses(myFileName);
860 					} else {
861 						reportFile << "ERROR: Cannot dump fuses because model file is invalid" << endl;
862 					}
863 				} else {
864 					reportFile << "ERROR: no fuse file name" << endl;
865 				}
866 			} else if ( myCommand == "dumpanalognets" || myCommand == "dan" ) {
867 				if ( myInputStream >> myFileName ) {
868 					if ( theCurrentStage > STAGE_START ) {
869 						DumpAnalogNets(myFileName, myPrintSubcircuitNameFlag);
870 					} else {
871 						reportFile << "ERROR: Can only dump analog nets after second stage" << endl;
872 					}
873 				} else {
874 					reportFile << "ERROR: no analog net file name" << endl;
875 				}
876 			} else if ( myCommand == "dumpunknownlogicalnets" || myCommand == "duln" ) {
877 				if ( myInputStream >> myFileName ) {
878 					if ( theCurrentStage >= STAGE_FIRST_MINMAX ) {
879 						DumpUnknownLogicalNets(myFileName, myPrintSubcircuitNameFlag);
880 					} else {
881 						reportFile << "ERROR: Can only dump unknown logical nets after first min/max stage" << endl;
882 					}
883 				} else {
884 					reportFile << "ERROR: no unknown logical net file name" << endl;
885 				}
886 			} else if ( myCommand == "dumpunknownlogicalports" || myCommand == "dulp" ) {
887 				string myFilter;
888 				if ( myInputStream >> myFilter && myInputStream >> myFileName ) {
889 					if ( theCurrentStage >= STAGE_FIRST_SIM ) {
890 						DumpUnknownLogicalPorts(myCurrentInstanceId, myFilter, myFileName, myPrintSubcircuitNameFlag);
891 					} else {
892 						reportFile << "ERROR: Can only dump unknown logical ports after first sim stage" << endl;
893 					}
894 				} else {
895 					reportFile << "ERROR: no unknown logical port file name" << endl;
896 				}
897 			} else if ( myCommand == "dumplevelshifters" || myCommand == "dls" ) {
898 				if ( myInputStream >> myFileName ) {
899 					if ( theCurrentStage >= STAGE_FIRST_MINMAX ) {
900 						DumpLevelShifters(myFileName, myPrintSubcircuitNameFlag);
901 					} else {
902 						reportFile << "ERROR: Can only dump level shifters after first min/max stage" << endl;
903 					}
904 				} else {
905 					reportFile << "ERROR: no level shifter file name" << endl;
906 				}
907 			} else if ( myCommand == "togglename" || myCommand == "n" ) {
908 				myPrintSubcircuitNameFlag = ! myPrintSubcircuitNameFlag;
909 				reportFile << "Printing subcircuit name option is now " << ((myPrintSubcircuitNameFlag) ? "on" : "off") << endl;
910 			} else if ( myCommand == "currenthierarchy" || myCommand == "ch" || myCommand == "pwd" ) {
911 				reportFile << "Current hierarchy(" << myCurrentInstanceId << "): " << HierarchyName(myCurrentInstanceId, myPrintSubcircuitNameFlag) << endl;
912 			} else if ( myCommand == "printhierarchy" || myCommand == "ph" ) {
913 				myNumberString = "";
914 				if ( myInputStream >> myNumberString ) {
915 					myNumber = from_string<size_t>(myNumberString);
916 					reportFile << "Current hierarchy(" << myNumber << "): " << HierarchyName(myNumber, myPrintSubcircuitNameFlag) << endl;
917 				} else {
918 					myCommandMode = "ph";
919 				}
920 			} else if ( myCommand == "printdevice" || myCommand == "pd" ) {
921 				myNumberString = "";
922 				if ( myInputStream >> myNumberString ) {
923 					myNumber = from_string<size_t>(myNumberString);
924 					if ( myNumber == 0 && myNumberString != "0" ) {
925 						reportFile << "Invalid device number" << endl;
926 					} else {
927 						reportFile << "Device " << myNumber << ": " << DeviceName(myNumber, myPrintSubcircuitNameFlag) << endl;
928 					}
929 				} else {
930 					myCommandMode = "pd";
931 				}
932 			} else if ( myCommand == "printnet" || myCommand == "pn" ) {
933 				myNumberString = "";
934 				if ( myInputStream >> myNumberString ) {
935 					myNumber = from_string<size_t>(myNumberString);
936 					if ( myNumber == 0 && myNumberString != "0" ) {
937 						reportFile << "Invalid net number" << endl;
938 					} else {
939 						reportFile << "Net " << myNumber << ": " << NetName(myNumber, myPrintSubcircuitNameFlag) << endl;
940 					}
941 				} else {
942 					myCommandMode = "pn";
943 				}
944 			} else if ( myCommand == "getinstance" || myCommand == "gi" ) {
945 				if ( myInputStream >> myName ) {
946 					reportFile << "getinstance not yet implemented" << endl;
947 				} else {
948 					myCommandMode = "gi";
949 				}
950 			} else if ( myCommand == "getdevice" || myCommand == "gd" ) {
951 				myName = "";
952 				if ( myInputStream >> myName ) {
953 					netId_t myDeviceId = FindDevice(myCurrentInstanceId, RemoveCellNames(myName));
954 					if ( myDeviceId != UNKNOWN_DEVICE ) {
955 						CInstance * myParent_p = instancePtr_v[deviceParent_v[myDeviceId]];
956 						CDevice * myDevice_p = myParent_p->master_p->devicePtr_v[myDeviceId - myParent_p->firstDeviceId];
957 						reportFile << "Device " << DeviceName(myDeviceId, myPrintSubcircuitNameFlag) << ": " << myDeviceId;
958 						reportFile << " " << myDevice_p->parameters << " R=" << parameterResistanceMap[myDevice_p->parameters] << endl;
959 						reportFile << "  Model " << myDevice_p->model_p->definition << endl;
960 					}
961 				} else {
962 					myCommandMode = "gd";
963 				}
964 			} else if ( myCommand == "traceinverter" || myCommand == "ti" ) {
965 				myName = "";
966 				myInputStream >> myName;
967 				netId_t myNetId = FindNet(myCurrentInstanceId, RemoveCellNames(myName));
968 				if ( myNetId != UNKNOWN_NET ) {
969 					netId_t myEquivalentNetId = (isFixedEquivalentNet) ? GetEquivalentNet(myNetId) : myNetId;
970 					if ( theCurrentStage >= STAGE_FIRST_MINMAX ) {
971 						reportFile << NetName(myNetId, myPrintSubcircuitNameFlag) << endl;
972 						if ( myNetId != myEquivalentNetId ) {
973 							reportFile << " = " << NetName(myEquivalentNetId, myPrintSubcircuitNameFlag) << endl;
974 						}
975 						if ( inverterNet_v[myEquivalentNetId] != UNKNOWN_NET ) {
976 							string myInversion =  ( theCurrentStage < STAGE_COMPLETE ) ? " - " :
977 								(highLow_v[myEquivalentNetId]) ? " + " : " - ";
978 							for( netId_t net_it = inverterNet_v[myEquivalentNetId]; net_it != UNKNOWN_NET; net_it = inverterNet_v[net_it] ) {
979 								reportFile << myInversion << NetName(net_it, myPrintSubcircuitNameFlag) << endl;
980 								myInversion = ( myInversion == " - " ? " + " : " - " );
981 							}
982 						} else {
983 							reportFile << " not an inverter output." << endl;
984 						}
985 					} else {
986 						reportFile << " Inverters have not been processed. Try later stage." << endl;
987 					}
988 				}
989 			} else if ( myCommand == "getnet" || myCommand == "gn" ) {
990 				myName = "";
991 				if ( myInputStream >> myName ) {
992 					netId_t myNetId = FindNet(myCurrentInstanceId, RemoveCellNames(myName));
993 					if ( myNetId != UNKNOWN_NET ) {
994 						reportFile << "Net " << NetName(myNetId, myPrintSubcircuitNameFlag) << ": " << myNetId << endl;
995 						netId_t myEquivalentNetId = (isFixedEquivalentNet) ? GetEquivalentNet(myNetId) : myNetId;
996 						if ( theCurrentStage >= STAGE_LINK ) {
997 							reportFile << " connections: gate " << connectionCount_v[myEquivalentNetId].gateCount;
998 							reportFile << " source " << connectionCount_v[myEquivalentNetId].sourceCount;
999 							reportFile << " drain " << connectionCount_v[myEquivalentNetId].drainCount;
1000 							reportFile << " bulk " << CountBulkConnections(myEquivalentNetId) << endl;
1001 						}
1002 						string mySimpleName = NetName(myEquivalentNetId, PRINT_CIRCUIT_OFF);
1003 						CPower * myLeakPower_p = leakVoltagePtr_v[myEquivalentNetId].full;
1004 						CPower * myPower_p = netVoltagePtr_v[myEquivalentNetId].full;
1005 						if ( leakVoltageSet && myLeakPower_p && myLeakPower_p != myPower_p ) {
1006 							reportFile << " leak definition " << myLeakPower_p->powerSignal()
1007 									<< LeakShortString(myEquivalentNetId, myPrintSubcircuitNameFlag) << endl;
1008 							reportFile << "  default min " << NetName(myLeakPower_p->defaultMinNet) << endl;
1009 							reportFile << "  default sim " << NetName(myLeakPower_p->defaultSimNet) << endl;
1010 							reportFile << "  default max " << NetName(myLeakPower_p->defaultMaxNet) << endl;
1011 						}
1012 						if ( powerFileStatus == OK && netVoltagePtr_v[myEquivalentNetId].full ) {
1013 							if ( myPower_p->powerSignal() != mySimpleName ) {
1014 								reportFile << " base definition " << myPower_p->powerSignal() << endl;
1015 								reportFile << "  default min " << NetName(myPower_p->defaultMinNet) << endl;
1016 								reportFile << "  default sim " << NetName(myPower_p->defaultSimNet) << endl;
1017 								reportFile << "  default max " << NetName(myPower_p->defaultMaxNet) << endl;
1018 							}
1019 							reportFile << ShortString(myEquivalentNetId, myPrintSubcircuitNameFlag) << endl;
1020 						}
1021 						reportFile << endl;
1022 						if ( theCurrentStage >= STAGE_COMPLETE ) {
1023 							if ( minNet_v[myEquivalentNetId].backupNetId != myNetId )
1024 								PrintBackupNet(minNet_v, myNetId, "Initial min path", reportFile);
1025 							if ( maxNet_v[myEquivalentNetId].backupNetId != myNetId )
1026 								PrintBackupNet(maxNet_v, myNetId, "Initial max path", reportFile);
1027 						}
1028 						if ( theCurrentStage >= STAGE_SECOND_SIM ) {
1029 							if ( simNet_v[myEquivalentNetId].backupNetId != myNetId )
1030 								PrintBackupNet(simNet_v, myNetId, "Initial sim path", reportFile);
1031 	/* 3pass
1032 							if ( logicMinNet_v[myNetId].nextNetId != myNetId )
1033 								PrintVirtualNet(logicMinNet_v, myNetId, "Logic min path", cout);
1034 							if ( logicMaxNet_v[myNetId].nextNetId != myNetId )
1035 								PrintVirtualNet(logicMaxNet_v, myNetId, "Logic max path", cout);
1036 							if ( logicSimNet_v[myNetId].nextNetId != myNetId )
1037 								PrintVirtualNet(logicSimNet_v, myNetId, "Logic sim path", cout);
1038 	*/
1039 						}
1040 						if ( theCurrentStage >= STAGE_RESISTANCE ) {
1041 
1042 							if ( minNet_v[myEquivalentNetId].nextNetId != myNetId )
1043 								PrintVirtualNet<CVirtualNetVector>(minNet_v, myNetId, "Min path", reportFile);
1044 							if ( maxNet_v[myEquivalentNetId].nextNetId != myNetId )
1045 								PrintVirtualNet<CVirtualNetVector>(maxNet_v, myNetId, "Max path", reportFile);
1046 							if ( simNet_v[myEquivalentNetId].nextNetId != myNetId )
1047 								PrintVirtualNet<CVirtualNetVector>(simNet_v, myNetId, "Sim path", reportFile);
1048 						}
1049 					}
1050 				} else {
1051 					myCommandMode = "gn";
1052 				}
1053 			} else if ( myCommand == "skip" ) {
1054 				myCurrentInstanceId = 0; // reset saved hierarchy
1055 				myReturnCode = SKIP;
1056 			} else if ( myCommand == "rerun" ) {
1057 				myCurrentInstanceId = 0; // reset saved hierarchy
1058 				cvcArgIndex--;
1059 				logFile.close();
1060 				errorFile.close();
1061 				myReturnCode = SKIP;
1062 //			} else if ( myCommand == "shortfile" || myCommand == "s" ) {
1063 //				myFileName = "";
1064 //				myInputStream >> myFileName;
1065 //				ReadShorts(myFileName);
1066 			} else if ( myCommand == "c" || myCommand == "continue" ) {
1067 				if ( theCurrentStage == STAGE_COMPLETE && cvcArgIndex + 1 >= cvcArgCount ) { // attempt to continue past last cvcrc
1068 					reportFile << "This is the last cvcrc file. Use 'rerun' or 'quit'." << endl;
1069 				} else { // valid continue
1070 					myReturnCode = OK;
1071 					if ( myInputStream >> gContinueCount ) {
1072 						;
1073 					} else {
1074 						gContinueCount = 1;
1075 					}
1076 					cout << "continuing for " << gContinueCount << " step(s)" << endl;
1077 				}
1078 			} else if ( myCommand == "q" || myCommand == "quit" ) {
1079 				RemoveLock();
1080 				Cleanup();
1081 				exit(0);
1082 			} else {
1083 				reportFile << "Unrecognized command '" << myCommand << "'" << endl;
1084 			}
1085 		}
1086 		catch (invalid_argument& e) {
1087 			reportFile << "invalid argument" << endl;
1088 		}
1089 	}
1090 	return(myReturnCode);
1091 }
1092 
DumpFuses(string theFileName)1093 void CCvcDb::DumpFuses(string theFileName) {
1094 	ofstream myDumpFile(theFileName);
1095 	if ( myDumpFile.fail() ) {
1096 		reportFile << "ERROR: Could not open " << theFileName << endl;
1097 		return;
1098 	}
1099 	reportFile << "Dumping fuses to " << theFileName << " ... "; cout.flush();
1100 	size_t myFuseCount = 0;
1101 	for (CModelListMap::iterator keyModelListPair_pit = cvcParameters.cvcModelListMap.begin(); keyModelListPair_pit != cvcParameters.cvcModelListMap.end(); keyModelListPair_pit++) {
1102 		for (CModelList::iterator model_pit = keyModelListPair_pit->second.begin(); model_pit != keyModelListPair_pit->second.end(); model_pit++) {
1103 			if ( model_pit->type == FUSE_ON || model_pit->type == FUSE_OFF ) {
1104 				for (CDevice * device_pit = model_pit->firstDevice_p; device_pit != NULL; device_pit = device_pit->nextDevice_p) {
1105 					CCircuit * myParent_p = device_pit->parent_p;
1106 					for (instanceId_t instance_it = 0; instance_it < myParent_p->instanceId_v.size(); instance_it++) {
1107 						myDumpFile << DeviceName(instancePtr_v[myParent_p->instanceId_v[instance_it]]->firstDeviceId + device_pit->offset) << " " << gModelTypeMap[model_pit->type] << endl;
1108 						myFuseCount++;
1109 					}
1110 				}
1111 			}
1112 		}
1113 	}
1114 	reportFile << "total fuses written: " << myFuseCount << endl;
1115 	myDumpFile.close();
1116 }
1117 
DumpAnalogNets(string theFileName,bool thePrintCircuitFlag)1118 void CCvcDb::DumpAnalogNets(string theFileName, bool thePrintCircuitFlag) {
1119 	ofstream myDumpFile(theFileName);
1120 	if ( myDumpFile.fail() ) {
1121 		reportFile << "ERROR: Could not open " << theFileName << endl;
1122 		return;
1123 	}
1124 	reportFile << "Dumping analog nets to " << theFileName << " ... "; cout.flush();
1125 	size_t myNetCount = 0;
1126 	for ( netId_t net_it = 0; net_it < netCount; net_it++ ) {
1127 		if ( net_it != GetEquivalentNet(net_it) ) continue;  // skip shorted nets
1128 		if ( netVoltagePtr_v[net_it].full && netVoltagePtr_v[net_it].full->type[POWER_BIT] ) continue;  // skip power
1129 		if ( IsAnalogNet(net_it) ) {
1130 			myDumpFile << NetName(net_it, thePrintCircuitFlag) << endl;
1131 			myNetCount++;
1132 		}
1133 	}
1134 	reportFile << "total nets written: " << myNetCount << endl;
1135 	myDumpFile.close();
1136 }
1137 
DumpUnknownLogicalPorts(instanceId_t theCurrentInstanceId,string theFilter,string theFileName,bool thePrintCircuitFlag)1138 void CCvcDb::DumpUnknownLogicalPorts(instanceId_t theCurrentInstanceId, string theFilter, string theFileName, bool thePrintCircuitFlag) {
1139 	// for each port matching theFilter in every instance at or below theCurrentInstanceId,
1140 	// output the highest inverter input at the lowest level that matched the filter
1141 	ofstream myDumpFile(theFileName);
1142 	regex mySearchPattern(FuzzyFilter(theFilter));
1143 	unordered_set<netId_t> myPrintedNets;
1144 	CVirtualNet myMinNet;
1145 	CVirtualNet myMaxNet;
1146 	if ( myDumpFile.fail() ) {
1147 		reportFile << "ERROR: Could not open " << theFileName << endl;
1148 		return;
1149 	}
1150 	reportFile << "Dumping unknown logical ports filtered by " <<  theFilter << " to " << theFileName << " ... " << endl;
1151 	vector<bool> myIsLogicalNet_v;
1152 	myIsLogicalNet_v.resize(netCount, false);
1153 	size_t myNetCount = 0;
1154 	cout << "DEBUG: setting net types ..." << endl;
1155 	for ( netId_t net_it = 0; net_it < netCount; net_it++ ) {
1156 		if ( net_it != GetEquivalentNet(net_it) ) continue;  // skip shorted nets
1157 		CPower * myPower_p = netVoltagePtr_v[net_it].full;
1158 		if ( myPower_p && ( myPower_p->simVoltage != UNKNOWN_VOLTAGE || myPower_p->type[POWER_BIT] ) ) continue;  // skip defined sim voltages and power
1159 		myIsLogicalNet_v[net_it] = ! IsAnalogNet(net_it);
1160 	}
1161 	cout << "DEBUG: searching instances..." << endl;
1162 	for ( instanceId_t instance_it = 0; instance_it < instancePtr_v.size(); instance_it++ ) {
1163 		if ( ! IsSubcircuitOf(instance_it, theCurrentInstanceId) ) continue;  // only process subcircuits
1164 		CInstance * myInstance_p = instancePtr_v[instance_it];
1165 		if ( ! myInstance_p || ! myInstance_p->master_p ) {
1166 			continue;
1167 		}
1168 		CCircuit * myCircuit_p = myInstance_p->master_p;
1169 		for( auto signalMap_pit = myCircuit_p->localSignalIdMap.begin(); signalMap_pit != myCircuit_p->localSignalIdMap.end(); signalMap_pit++ ) {
1170 			netId_t net_it = signalMap_pit->second;
1171 			if ( net_it >= myCircuit_p->portCount && instance_it != theCurrentInstanceId ) continue;  // skip internal signals in subcircuits
1172 			list<tuple<instanceId_t, netId_t, netId_t>> myNetStack;
1173 			netId_t myTopNetId = GetEquivalentNet(myInstance_p->localToGlobalNetId_v[net_it]);
1174 			if ( myPrintedNets.count(myTopNetId) > 0 ) continue;  // ignore already printed
1175 			if ( ! myIsLogicalNet_v[myTopNetId] ) continue;  // ignore analog nets and known logic
1176 			if ( ! regex_match(signalMap_pit->first, mySearchPattern) ) continue;  // ignore non-match
1177 			if ( firstGate_v[myTopNetId] == UNKNOWN_NET ) continue;  // ignore floating outputs (also ignores transfer gate connections)
1178 			netId_t mySourceNet = myTopNetId;
1179 			myNetStack.push_front(tuple<instanceId_t, netId_t, netId_t>(instance_it, net_it, mySourceNet));
1180 			// must be done after second sim so power & override nets are propagated
1181 			while ( inverterNet_v[mySourceNet] != UNKNOWN_NET ) {
1182 				mySourceNet = inverterNet_v[mySourceNet];
1183 				myNetStack.push_front(tuple<instanceId_t, netId_t, netId_t>(UNKNOWN_INSTANCE, UNKNOWN_NET, mySourceNet));
1184 			}
1185 			bool myNetFound = false;
1186 			while ( myNetStack.size() > 0 && ! myNetFound ) {
1187 				tuple<instanceId_t, netId_t, netId_t> mySearchTuple = myNetStack.front();
1188 				myNetStack.pop_front();
1189 				netId_t myNet = get<2>(mySearchTuple);
1190 				if ( ! IsInstanceNet(myNet, theCurrentInstanceId) ) continue;  // ignore nets not in current instance
1191 				instanceId_t mySearchInstance = get<0>(mySearchTuple);
1192 				deviceId_t mySourceDevice = ( firstSource_v[myNet] == UNKNOWN_DEVICE ) ? firstDrain_v[myNet] : firstSource_v[myNet];
1193 				if ( mySourceDevice != UNKNOWN_DEVICE ) {  // use device instance as search
1194 					mySearchInstance = deviceParent_v[mySourceDevice];
1195 				}
1196 				if ( ! IsSubcircuitOf(mySearchInstance, theCurrentInstanceId) ) {  // outside hierarchy
1197 					mySearchInstance = UNKNOWN_INSTANCE;
1198 				}
1199 				if ( mySearchInstance == UNKNOWN_INSTANCE ) {  // source outside hierarchy or input (no source)
1200 					mySearchInstance == FindNetInstance(myNet, theCurrentInstanceId);
1201 				}
1202 				if ( IsInternalNet(myNet, mySearchInstance) ) continue;  // ignore non ports
1203 				netId_t port_it;
1204 				CInstance * mySearchInstance_p;
1205 				CCircuit * mySearchCircuit_p;
1206 				text_t myLocalNetName = NULL;
1207 				while ( mySearchInstance != theCurrentInstanceId && IsSubcircuitOf(mySearchInstance, theCurrentInstanceId) && ! myNetFound ) {
1208 					// unfortunately requires 2 reverse searches. port given global net, and name given port
1209 					mySearchInstance_p = instancePtr_v[mySearchInstance];
1210 					if ( myNet < mySearchInstance_p->firstNetId ) {  // only process ports
1211 						myLocalNetName = GetLocalNetName(mySearchInstance, myNet);
1212 						if ( myLocalNetName != NULL ) {
1213 							//cout << "DEBUG: checking " << myLocalNetName << endl;
1214 							myNetFound = regex_match(myLocalNetName, mySearchPattern);
1215 						}
1216 					}
1217 					if ( ! myNetFound ) {
1218 						mySearchInstance = instancePtr_v[mySearchInstance]->parentId;
1219 					}
1220 				}
1221 				if ( ! myNetFound && mySearchInstance == theCurrentInstanceId ) {  // include internal nets of top level
1222 					mySearchInstance_p = instancePtr_v[theCurrentInstanceId];
1223 					mySearchCircuit_p = mySearchInstance_p->master_p;
1224 					netId_t mySearchLimit = mySearchInstance_p->localToGlobalNetId_v.size();
1225 					myLocalNetName = GetLocalNetName(theCurrentInstanceId, myNet);
1226 					if ( myLocalNetName != NULL ) {
1227 						myNetFound = regex_match(myLocalNetName, mySearchPattern);
1228 					}
1229 				}
1230 				if ( ! myNetFound ) continue;  // couldn't find net
1231 				if ( myPrintedNets.count(myNet) > 0 ) continue;  // already printed
1232 				myMinNet(minNet_v, myNet);
1233 				myMaxNet(maxNet_v, myNet);
1234 				if ( myMinNet.finalNetId == UNKNOWN_NET
1235 					|| myMaxNet.finalNetId == UNKNOWN_NET
1236 					|| myMinNet.finalNetId == myNet
1237 					|| myMaxNet.finalNetId == myNet
1238 					|| myMinNet.finalNetId == myMaxNet.finalNetId ) continue;  // invalid min/max
1239 				myDumpFile << HierarchyName(mySearchInstance, thePrintCircuitFlag) << "/" << myLocalNetName;
1240 				myDumpFile << " min " << NetName(myMinNet.finalNetId, thePrintCircuitFlag);
1241 				myDumpFile << " max " << NetName(myMaxNet.finalNetId, thePrintCircuitFlag) << endl;
1242 				myPrintedNets.insert(myNet);
1243 			}
1244 		}
1245 	}
1246 	reportFile << "total nets written: " << myPrintedNets.size() << endl;
1247 	myDumpFile.close();
1248 }
1249 
DumpUnknownLogicalNets(string theFileName,bool thePrintCircuitFlag)1250 void CCvcDb::DumpUnknownLogicalNets(string theFileName, bool thePrintCircuitFlag) {
1251 	ofstream myDumpFile(theFileName);
1252 	CVirtualNet myMinNet;
1253 	CVirtualNet myMaxNet;
1254 	if ( myDumpFile.fail() ) {
1255 		reportFile << "ERROR: Could not open " << theFileName << endl;
1256 		return;
1257 	}
1258 	reportFile << "Dumping unknown logical nets to " << theFileName << " ... " << endl;
1259 	vector<bool> myIsLogicalNet_v;
1260 	myIsLogicalNet_v.resize(netCount, false);
1261 	size_t myNetCount = 0;
1262 	for ( netId_t net_it = 0; net_it < netCount; net_it++ ) {
1263 		if ( net_it != GetEquivalentNet(net_it) ) continue;  // skip shorted nets
1264 		CPower * myPower_p = netVoltagePtr_v[net_it].full;
1265 		if ( myPower_p && ( myPower_p->simVoltage != UNKNOWN_VOLTAGE || myPower_p->type[POWER_BIT] ) ) continue;  // skip defined sim voltages and power
1266 		myIsLogicalNet_v[net_it] = ! IsAnalogNet(net_it);
1267 	}
1268 	for ( netId_t net_it = 0; net_it < netCount; net_it++ ) {
1269 		if ( ! myIsLogicalNet_v[net_it] ) continue;  // skip shorted, defined, and analog nets
1270 
1271 		if ( simNet_v[net_it].finalNetId != net_it ) continue;  // skip known values
1272 
1273 		if ( inverterNet_v[net_it] != UNKNOWN_NET
1274 				&& inverterNet_v[net_it] >= topCircuit_p->portCount
1275 				&& ! netStatus_v[inverterNet_v[net_it]][ANALOG] ) continue;  // skip inverter output unless inverter input is chip input or analog signal
1276 
1277 		CDeviceCount myDeviceCount(net_it, this);
1278 		if ( myDeviceCount.activePmosCount == 0 || myDeviceCount.activeNmosCount == 0 ) continue;  // skip non logic output
1279 		myMinNet(minNet_v, net_it);
1280 		myMaxNet(maxNet_v, net_it);
1281 		if ( myMinNet.finalNetId == UNKNOWN_NET
1282 			|| myMaxNet.finalNetId == UNKNOWN_NET
1283 			|| myMinNet.finalNetId == net_it
1284 			|| myMaxNet.finalNetId == net_it
1285 			|| myMinNet.finalNetId == myMaxNet.finalNetId ) continue;  // invalid min/max
1286 		myDumpFile << NetName(net_it, thePrintCircuitFlag);
1287 		myDumpFile << " min " << NetName(myMinNet.finalNetId, thePrintCircuitFlag);
1288 		myDumpFile << " max " << NetName(myMaxNet.finalNetId, thePrintCircuitFlag) << endl;
1289 		myNetCount++;
1290 	}
1291 	reportFile << "total nets written: " << myNetCount << endl;
1292 	myDumpFile.close();
1293 }
1294 
DumpLevelShifters(string theFileName,bool thePrintCircuitFlag)1295 void CCvcDb::DumpLevelShifters(string theFileName, bool thePrintCircuitFlag) {
1296 	/// Write a sampling (one per cell/power pair) of possible level shifters to theFileName
1297 	ofstream myDumpFile(theFileName);
1298 	CVirtualNet myMinNmosInputNet;
1299 	CVirtualNet myMinPmosInputNet;
1300 	CVirtualNet myMinOutputNet;
1301 	CVirtualNet myMaxNmosInputNet;
1302 	CVirtualNet myMaxPmosInputNet;
1303 	CVirtualNet myMaxOutputNet;
1304 	if ( myDumpFile.fail() ) {
1305 		reportFile << "ERROR: Could not open " << theFileName << endl;
1306 		return;
1307 	}
1308 	reportFile << "Dumping level shifters to " << theFileName << " ... "; cout.flush();
1309 	vector<bool> myIsLogicalNet_v;
1310 	myIsLogicalNet_v.resize(netCount, false);
1311 	size_t myLevelShifterCount = 0;
1312 	for ( netId_t net_it = 0; net_it < netCount; net_it++ ) {
1313 		if ( net_it != GetEquivalentNet(net_it) ) continue;  // skip shorted nets
1314 		CPower * myPower_p = netVoltagePtr_v[net_it].full;
1315 		if ( myPower_p && ( myPower_p->simVoltage != UNKNOWN_VOLTAGE || myPower_p->type[POWER_BIT] ) ) continue;  // skip defined sim voltages and power
1316 		myIsLogicalNet_v[net_it] = ! IsAnalogNet(net_it);
1317 	}
1318 	set<string> myLevelShifters;
1319 	debugFile << "DEBUG level shifters" << endl;
1320 	for ( netId_t net_it = 0; net_it < netCount; net_it++ ) {
1321 		if ( ! myIsLogicalNet_v[net_it] ) continue;  // skip shorted, defined, and analog nets
1322 
1323 		CDeviceCount myDeviceCount(net_it, this);
1324 		if ( myDeviceCount.activePmosCount == 0 || myDeviceCount.activeNmosCount == 0 ) continue;  // skip non logic output
1325 
1326 		myMinOutputNet(minNet_v, net_it);
1327 		myMaxOutputNet(maxNet_v, net_it);
1328 		CPower * myOutputGround_p = netVoltagePtr_v[myMinOutputNet.finalNetId].full;
1329 		CPower * myOutputPower_p = netVoltagePtr_v[myMaxOutputNet.finalNetId].full;
1330 		if ( myMinOutputNet.finalNetId == UNKNOWN_NET
1331 			|| myMaxOutputNet.finalNetId == UNKNOWN_NET
1332 			|| myMinOutputNet.finalNetId == net_it
1333 			|| myMaxOutputNet.finalNetId == net_it
1334 			|| myMinOutputNet.finalNetId == myMaxOutputNet.finalNetId
1335 			|| ! myOutputGround_p || ! IsPower_(myOutputGround_p)
1336 			|| ! myOutputPower_p || ! IsPower_(myOutputPower_p) ) continue;  // invalid min/max
1337 
1338 		deviceId_t myNmos = GetAttachedDevice(net_it, NMOS, SD);
1339 		deviceId_t myPmos = GetAttachedDevice(net_it, PMOS, SD);
1340 		if ( myNmos == UNKNOWN_DEVICE || myPmos == UNKNOWN_DEVICE ) continue;  // skip if missing NMOS or PMOS
1341 
1342 		if ( deviceParent_v[myNmos] != deviceParent_v[myPmos] ) continue;  // skip if in different subcircuits
1343 
1344 		CInstance * myInstance_p = instancePtr_v[deviceParent_v[myNmos]];
1345 		CCircuit * myMaster_p = myInstance_p->master_p;
1346 		netId_t myNmosGate = GetEquivalentNet(gateNet_v[myNmos]);
1347 		netId_t myPmosGate = GetEquivalentNet(gateNet_v[myPmos]);
1348 		myMinNmosInputNet(minNet_v, myNmosGate);
1349 		myMinPmosInputNet(minNet_v, myPmosGate);
1350 		myMaxNmosInputNet(maxNet_v, myNmosGate);
1351 		myMaxPmosInputNet(maxNet_v, myPmosGate);
1352 //		CPower * myNmosPower_p = netVoltagePtr_v[myNmosGate].full;
1353 //		CPower * myPmosPower_p = netVoltagePtr_v[myPmosGate].full;
1354 		CPower * myNmosGround_p = netVoltagePtr_v[myMinNmosInputNet.finalNetId].full;
1355 		CPower * myNmosPower_p = netVoltagePtr_v[myMaxNmosInputNet.finalNetId].full;
1356 		CPower * myPmosGround_p = netVoltagePtr_v[myMinPmosInputNet.finalNetId].full;
1357 		CPower * myPmosPower_p = netVoltagePtr_v[myMaxPmosInputNet.finalNetId].full;
1358 		if ( ! myNmosGround_p || ! IsPower_(myNmosGround_p) || ! myNmosPower_p || ! IsPower_(myNmosPower_p)
1359 				|| ! myPmosGround_p || ! IsPower_(myPmosGround_p) || ! myPmosPower_p || ! IsPower_(myPmosPower_p) ) continue;  // ignore inputs with non-power min/max
1360 
1361 		if ( ( myMinNmosInputNet.finalNetId == myMaxNmosInputNet.finalNetId  // power
1362 					|| ( myNmosGround_p->powerAlias() == myOutputGround_p->powerAlias()
1363 						&& myNmosPower_p->powerAlias() == myOutputPower_p->powerAlias() ) )
1364 				&& ( myMinPmosInputNet.finalNetId == myMaxPmosInputNet.finalNetId  // power
1365 					|| ( myPmosGround_p->powerAlias() == myOutputGround_p->powerAlias()
1366 							&& myPmosPower_p->powerAlias() == myOutputPower_p->powerAlias() )) ) continue;  // input = output
1367 
1368 		if ( myMinNmosInputNet.finalNetId != myMinOutputNet.finalNetId
1369 				&& myMaxNmosInputNet.finalNetId != myMaxOutputNet.finalNetId
1370 				&& myMinPmosInputNet.finalNetId != myMinOutputNet.finalNetId
1371 				&& myMaxPmosInputNet.finalNetId != myMaxOutputNet.finalNetId ) continue;  // one power must be equal
1372 
1373 		if ( inverterNet_v[myNmosGate] == UNKNOWN_NET && inverterNet_v[myPmosGate] == UNKNOWN_NET ) continue;  // ignore signals not from inverters
1374 
1375 		netId_t myCheckNet;
1376 		deviceId_t myCheckDevice;
1377 		string myInputPower;
1378 		string myOutputPower = NetName(myMinOutputNet.finalNetId, thePrintCircuitFlag) + "/" + NetName(myMaxOutputNet.finalNetId, thePrintCircuitFlag);
1379 		if ( myMinNmosInputNet.finalNetId != myMaxNmosInputNet.finalNetId  // ignore direct connections to power
1380 				&& ( myMinNmosInputNet.finalNetId != myMinOutputNet.finalNetId
1381 					|| myMaxNmosInputNet.finalNetId != myMaxOutputNet.finalNetId ) ) {
1382 			myCheckDevice = myNmos;
1383 			myCheckNet = myNmosGate;
1384 			myInputPower = NetName(myMinNmosInputNet.finalNetId, thePrintCircuitFlag) + "/" + NetName(myMaxNmosInputNet.finalNetId, thePrintCircuitFlag);
1385 		} else if ( myMinPmosInputNet.finalNetId != myMaxPmosInputNet.finalNetId  // ignore direct connections to power
1386 				&& ( myMinPmosInputNet.finalNetId != myMinOutputNet.finalNetId
1387 					|| myMaxPmosInputNet.finalNetId != myMaxOutputNet.finalNetId ) ) {
1388 			myCheckDevice = myPmos;
1389 			myCheckNet = myPmosGate;
1390 			myInputPower = NetName(myMinPmosInputNet.finalNetId, thePrintCircuitFlag) + "/" + NetName(myMaxPmosInputNet.finalNetId, thePrintCircuitFlag);
1391 		} else if ( myMinNmosInputNet.finalNetId != myMaxNmosInputNet.finalNetId
1392 				|| myMinNmosInputNet.finalNetId != myMaxNmosInputNet.finalNetId ) {  // tied to power
1393 			continue;
1394 
1395 		} else {
1396 			myDumpFile << "UNEXPECTED connection at " << DeviceName(myNmos, true);
1397 			myDumpFile << " N " << myNmosGate << " " <<myMinNmosInputNet.finalNetId << "/" << myMaxNmosInputNet.finalNetId;
1398 			myDumpFile << " P " << myPmosGate << " " <<myMinPmosInputNet.finalNetId << "/" << myMaxPmosInputNet.finalNetId;
1399 			myDumpFile << " out " << myMinOutputNet.finalNetId << "/" << myMaxOutputNet.finalNetId << endl;
1400 			continue;
1401 
1402 		}
1403 		if (inverterNet_v[myCheckNet] == UNKNOWN_NET) {
1404 			myDumpFile << "UNEXPECTED non-inverter at " << DeviceName(myCheckDevice, true) << endl;
1405 			continue;
1406 
1407 		}
1408 		deviceId_t myDeviceOffset = myCheckDevice - myInstance_p->firstDeviceId;
1409 		string myCircuitName = myMaster_p->name;
1410 		netId_t myNetOffset = myMaster_p->devicePtr_v[myDeviceOffset]->signalId_v[1];
1411 		debugFile << "DEBUG " << myCircuitName << " " << myDeviceOffset << " " << myNetOffset;
1412 		debugFile << " " << myInputPower << "->" << myOutputPower << endl;
1413 		string myKeyString = myCircuitName + to_string(myNetOffset) + myInputPower + myOutputPower;
1414 		if ( myLevelShifters.count(myKeyString) == 0 ) {
1415 			bool myIsInternal = false;
1416 			if ( deviceParent_v[myCheckDevice] == netParent_v[myCheckNet]
1417 					&& netParent_v[myCheckNet] == netParent_v[inverterNet_v[myCheckNet]] ) {  // same subcircuit
1418 				CVirtualNet myMinInverterInput;
1419 				CVirtualNet myMaxInverterInput;
1420 				myMinInverterInput(minNet_v, inverterNet_v[myCheckNet]);
1421 				myMaxInverterInput(maxNet_v, inverterNet_v[myCheckNet]);
1422 				string myInverterPower = NetName(myMinInverterInput.finalNetId, thePrintCircuitFlag) + "/" + NetName(myMaxInverterInput.finalNetId, thePrintCircuitFlag);
1423 				myIsInternal = myInputPower == myInverterPower;  // level shifter contained in subcircuit with same power
1424 			}
1425 			vector<text_t> mySignals_v;
1426 			mySignals_v.reserve(myMaster_p->localSignalIdMap.size());
1427 			for (auto signal_net_pair_pit = myMaster_p->localSignalIdMap.begin(); signal_net_pair_pit != myMaster_p->localSignalIdMap.end(); signal_net_pair_pit++) {
1428 				mySignals_v[signal_net_pair_pit->second] = signal_net_pair_pit->first;
1429 			}
1430 			string myLocalNetName = "*(" + myCircuitName + ")/" + string(mySignals_v[myNetOffset]);
1431 			myDumpFile << ( myIsInternal ? "#" : "" );  // level shifters that are internal to subcircuits do not need to be checked
1432 			myDumpFile << HierarchyName(deviceParent_v[myNmos], true) << "/" << string(mySignals_v[myNetOffset]);
1433 			myDumpFile << " " << (myCheckDevice == myNmos ? "N" : "P");
1434 			myDumpFile << " " << myInputPower << "->" << myOutputPower << endl;
1435 			myLevelShifters.insert(myKeyString);
1436 			if ( ! myIsInternal ) {
1437 				myLevelShifterCount++;
1438 			}
1439 		}
1440 	}
1441 	reportFile << "total level shifters written: " << myLevelShifterCount << endl;
1442 	myDumpFile.close();
1443 }
1444 
CheckFuses()1445 returnCode_t CCvcDb::CheckFuses() {
1446 	if ( IsEmpty(cvcParameters.cvcFuseFilename) ) return (OK);
1447 	ifstream myFuseFile(cvcParameters.cvcFuseFilename);
1448 	if ( myFuseFile.fail() ) {
1449 		reportFile << "ERROR: Could not open fuse file: " << cvcParameters.cvcFuseFilename << endl;
1450 		return(FAIL);
1451 	}
1452 	string myFuseName, myFuseStatus;
1453 	bool myFuseError = false;
1454 	deviceId_t myDeviceId;
1455 	string myInputLine;
1456 	while ( getline(myFuseFile, myInputLine) ) {
1457 		if ( myInputLine.length() == 0 ) continue;
1458 		if ( myInputLine.substr(0, 1) == "#" ) continue;
1459 		myInputLine = trim_(myInputLine);
1460 		stringstream myFuseStringStream(myInputLine);
1461 		myFuseStringStream >> myFuseName >> myFuseStatus;
1462 		if ( myFuseStringStream.fail() ) {
1463 			reportFile << "ERROR: invalid format '" << myInputLine << "' expected fuse_name fuse_on/fuse_off" << endl;
1464 			myFuseError = true;
1465 			continue;
1466 		}
1467 		myDeviceId = FindDevice(0, myFuseName);
1468 		if ( myFuseStatus != "fuse_on" && myFuseStatus != "fuse_off" ) {
1469 			reportFile << "ERROR: unknown fuse setting " << myFuseStatus << endl;
1470 			myFuseError = true;
1471 		}
1472 		if ( myDeviceId == UNKNOWN_DEVICE ) {
1473 			reportFile << "ERROR: unknown device " << myFuseName << endl;
1474 			myFuseError = true;
1475 		} else {
1476 			CInstance * myInstance_p = instancePtr_v[deviceParent_v[myDeviceId]];
1477 			CCircuit * myCircuit_p = myInstance_p->master_p;
1478 			CModel * myModel_p = myCircuit_p->devicePtr_v[myDeviceId - myInstance_p->firstDeviceId]->model_p;
1479 			if ( myModel_p->type != FUSE_ON && myModel_p->type != FUSE_OFF ) {
1480 				reportFile << "ERROR: not a fuse " << myFuseName << endl;
1481 				myFuseError = true;
1482 			}
1483 		}
1484 	}
1485 	myFuseFile.close();
1486 	return ((myFuseError) ? FAIL : OK);
1487 }
1488 
CreateDebugCvcrcFile(ofstream & theOutputFile,instanceId_t theInstanceId,string theCell,int theCurrentStage)1489 void CCvcDb::CreateDebugCvcrcFile(ofstream & theOutputFile, instanceId_t theInstanceId, string theCell, int theCurrentStage) {
1490 	if ( instancePtr_v[theInstanceId]->IsParallelInstance() ) {
1491 		reportFile << "Cannot create debug file for parallel instance" << endl;
1492 		PrintParallelInstance(theInstanceId, false);
1493 		return;
1494 	}
1495 	theOutputFile << "# Debug cvcrc for " << HierarchyName(theInstanceId) << endl;
1496 	string mySubcircuitName = instancePtr_v[theInstanceId]->master_p->name;
1497 	theOutputFile << "CVC_TOP = '" << mySubcircuitName << "'" << endl;
1498 	PrintSubcircuitCdl(mySubcircuitName);
1499 	theOutputFile << "CVC_NETLIST = '" << mySubcircuitName << ".cdl" << "'" << endl;
1500 	theOutputFile << "CVC_MODE = '" << theCell << "." << cvcParameters.cvcMode << "'" << endl;
1501 	theOutputFile << "CVC_MODEL_FILE = '" << cvcParameters.cvcModelFilename << "'" << endl;
1502 	string myPowerFile = "power." + theCell + "." + cvcParameters.cvcMode;
1503 	PrintInstancePowerFile(theInstanceId, myPowerFile, theCurrentStage);
1504 	theOutputFile << "CVC_POWER_FILE = '" << myPowerFile << "'" << endl;
1505 	theOutputFile << "CVC_FUSE_FILE = ''" << endl;
1506 	theOutputFile << "CVC_REPORT_FILE = '" << "debug_" << theCell << "_" << cvcParameters.cvcMode << ".log" << "'" << endl;
1507 	theOutputFile << "CVC_REPORT_TITLE = 'Debug " << theCell << " mode " << cvcParameters.cvcMode << "'" << endl;
1508 	theOutputFile << "CVC_CIRCUIT_ERROR_LIMIT = '" << cvcParameters.cvcCircuitErrorLimit << "'" << endl;
1509 	theOutputFile << "CVC_SEARCH_LIMIT = '" << cvcParameters.cvcSearchLimit << "'" << endl;
1510 	theOutputFile << "CVC_LEAK_LIMIT = '" << cvcParameters.cvcLeakLimit << "'" << endl;
1511 	theOutputFile << "CVC_SOI = '" << (( cvcParameters.cvcSOI ) ? "true" : "false") << "'" << endl;
1512 	theOutputFile << "CVC_SCRC = '" << (( cvcParameters.cvcSCRC ) ? "true" : "false") << "'" << endl;
1513 	theOutputFile << "CVC_VTH_GATES = '" << (( cvcParameters.cvcVthGates ) ? "true" : "false") << "'" << endl;
1514 	theOutputFile << "CVC_MIN_VTH_GATES = '" << (( cvcParameters.cvcMinVthGates ) ? "true" : "false") << "'" << endl;
1515 	theOutputFile << "CVC_IGNORE_VTH_FLOATING = '" << (( cvcParameters.cvcIgnoreVthFloating ) ? "true" : "false") << "'" << endl;
1516 	theOutputFile << "CVC_IGNORE_NO_LEAK_FLOATING = '" << (( cvcParameters.cvcIgnoreNoLeakFloating ) ? "true" : "false") << "'" << endl;
1517 	theOutputFile << "CVC_LEAK_OVERVOLTAGE = '" << (( cvcParameters.cvcLeakOvervoltage ) ? "true" : "false") << "'" << endl;
1518 	theOutputFile << "CVC_LOGIC_DIODES = '" << (( cvcParameters.cvcLogicDiodes ) ? "true" : "false") << "'" << endl;
1519 	theOutputFile << "CVC_ANALOG_GATES = '" << (( cvcParameters.cvcAnalogGates ) ? "true" : "false") << "'" << endl;
1520 	theOutputFile << "CVC_MOS_DIODE_ERROR_THRESHOLD = '" << Voltage_to_float(cvcParameters.cvcMosDiodeErrorThreshold) << "'" << endl;
1521 	theOutputFile << "CVC_SHORT_ERROR_THRESHOLD = '" << Voltage_to_float(cvcParameters.cvcShortErrorThreshold) << "'" << endl;
1522 	theOutputFile << "CVC_BIAS_ERROR_THRESHOLD = '" << Voltage_to_float(cvcParameters.cvcBiasErrorThreshold) << "'" << endl;
1523 	theOutputFile << "CVC_FORWARD_ERROR_THRESHOLD = '" << Voltage_to_float(cvcParameters.cvcForwardErrorThreshold) << "'" << endl;
1524 	theOutputFile << "CVC_FLOATING_ERROR_THRESHOLD = '" << Voltage_to_float(cvcParameters.cvcFloatingErrorThreshold) << "'" << endl;
1525 	theOutputFile << "CVC_GATE_ERROR_THRESHOLD = '" << Voltage_to_float(cvcParameters.cvcGateErrorThreshold) << "'" << endl;
1526 	theOutputFile << "CVC_LEAK?_ERROR_THRESHOLD = '" << Voltage_to_float(cvcParameters.cvcLeakErrorThreshold) << "'" << endl;
1527 	theOutputFile << "CVC_EXPECTED_ERROR_THRESHOLD = '" << Voltage_to_float(cvcParameters.cvcExpectedErrorThreshold) << "'" << endl;
1528 	theOutputFile << "CVC_OVERVOLTAGE_ERROR_THRESHOLD = '" << Voltage_to_float(cvcParameters.cvcOvervoltageErrorThreshold) << "'" << endl;
1529 	theOutputFile << "CVC_PARALLEL_CIRCUIT_PORT_LIMIT = '" << cvcParameters.cvcParallelCircuitPortLimit << "'" << endl;
1530 	theOutputFile << "CVC_CELL_ERROR_LIMIT_FILE = '" << cvcParameters.cvcCellErrorLimitFile << "'" << endl;
1531 	theOutputFile << "CVC_CELL_CHECKSUM_FILE = '" << cvcParameters.cvcCellChecksumFile << "'" << endl;
1532 	theOutputFile << "CVC_LARGE_CIRCUIT_SIZE = '" << cvcParameters.cvcLargeCircuitSize << "'" << endl;
1533 }
1534 
PrintInstancePowerFile(instanceId_t theInstanceId,string thePowerFileName,int theCurrentStage)1535 void CCvcDb::PrintInstancePowerFile(instanceId_t theInstanceId, string thePowerFileName, int theCurrentStage) {
1536 	ofstream myPowerFile(thePowerFileName);
1537 	if ( ! ( myPowerFile && myPowerFile.good() ) ) {
1538 		cout << "ERROR: Could not open power file " << thePowerFileName << " for output." << endl;
1539 		return;
1540 	}
1541 	myPowerFile << "#NO AUTO MACROS" << endl;
1542 	// print macro definitions
1543 	// really bad overkill
1544 	vector<string> myMacro_v;
1545 	myMacro_v.reserve(CPower::powerCount);
1546 	myMacro_v.resize(CPower::powerCount, "");
1547 	for ( auto pair_pit = cvcParameters.cvcPowerMacroPtrMap.begin(); pair_pit != cvcParameters.cvcPowerMacroPtrMap.end(); pair_pit++ ) {
1548 		myMacro_v[pair_pit->second->powerId] = pair_pit->first;
1549 	}
1550 	for ( netId_t macro_it = 0; macro_it < CPower::powerCount; macro_it++ ) {
1551 		if ( ! IsEmpty(myMacro_v[macro_it]) ) {
1552 			myPowerFile << "#define " << myMacro_v[macro_it] << " " << cvcParameters.cvcPowerMacroPtrMap[myMacro_v[macro_it]]->definition << endl;
1553 		}
1554 	}
1555 	CInstance * myInstance_p = instancePtr_v[theInstanceId];
1556 	CCircuit * myCircuit_p = myInstance_p->master_p;
1557 	const text_t myResistorText = CPower::powerDefinitionText.SetTextAddress(RESISTOR_TEXT);
1558 	// print port power and input definitions
1559 	vector<text_t> mySignals_v;
1560 	mySignals_v.reserve(myCircuit_p->localSignalIdMap.size());
1561 	for (auto signal_net_pair_pit = myCircuit_p->localSignalIdMap.begin(); signal_net_pair_pit != myCircuit_p->localSignalIdMap.end(); signal_net_pair_pit++) {
1562 		if ( signal_net_pair_pit->first != myResistorText ) {
1563 			mySignals_v[signal_net_pair_pit->second] = signal_net_pair_pit->first;
1564 		}
1565 	}
1566 	for ( netId_t net_it = 0; net_it < myInstance_p->master_p->portCount; net_it++ ) {
1567 		netId_t myGlobalNetId = GetEquivalentNet(myInstance_p->localToGlobalNetId_v[net_it]);
1568 		CPower * myPower_p = netVoltagePtr_v[myGlobalNetId].full;
1569 		if ( myPower_p && ! IsEmpty(myPower_p->powerSignal()) ) {
1570 			string myDefinition = string(myPower_p->definition).substr(0, string(myPower_p->definition).find(" calculation=>"));
1571 			myPowerFile << mySignals_v[net_it] << myDefinition << endl;
1572 		} else {
1573 			CDeviceCount myDeviceCounts(myGlobalNetId, this, theInstanceId);
1574 //			myDeviceCounts.Print(this);
1575 			string mySuffix = "";
1576 			if ( myDeviceCounts.activeNmosCount + myDeviceCounts.activePmosCount + myDeviceCounts.resistorCount == 0 ) {
1577 				mySuffix = " input";
1578 			} else {  // print ports that are not input for reference
1579 				myPowerFile << "#";
1580 			}
1581 			myPowerFile << mySignals_v[net_it] << mySuffix;
1582 			netId_t myMinNetId, myMaxNetId;
1583 			CPower *myMinPower_p = NULL;
1584 			CPower *myMaxPower_p = NULL;
1585 			if ( theCurrentStage == STAGE_COMPLETE ) {
1586 				myMinNetId = minNet_v[myGlobalNetId].backupNetId;
1587 				if ( myMinNetId != UNKNOWN_NET ) {
1588 					while ( myMinNetId != minNet_v[myMinNetId].backupNetId ) {
1589 						myMinNetId = minNet_v[myMinNetId].backupNetId;
1590 					}
1591 					myMinPower_p = leakVoltagePtr_v[myMinNetId].full;
1592 				}
1593 				myMaxNetId = maxNet_v[myGlobalNetId].backupNetId;
1594 				if ( myMaxNetId != UNKNOWN_NET ) {
1595 					while ( myMaxNetId != maxNet_v[myMaxNetId].backupNetId ) {
1596 						myMaxNetId = maxNet_v[myMaxNetId].backupNetId;
1597 					}
1598 					myMaxPower_p = leakVoltagePtr_v[myMaxNetId].full;
1599 				}
1600 			} else {
1601 				myMinNetId = minNet_v[myGlobalNetId].finalNetId;
1602 				if ( myMinNetId != UNKNOWN_NET ) {
1603 					myMinPower_p = netVoltagePtr_v[myMinNetId].full;
1604 				}
1605 				myMaxNetId = maxNet_v[myGlobalNetId].finalNetId;
1606 				if ( myMaxNetId != UNKNOWN_NET ) {
1607 					myMaxPower_p = netVoltagePtr_v[myMaxNetId].full;
1608 				}
1609 			}
1610 			netId_t mySimNetId = simNet_v[myGlobalNetId].finalNetId;
1611 			if ( myMinPower_p && myMinPower_p->minVoltage != UNKNOWN_VOLTAGE ) {
1612 				myPowerFile << " min@" << PrintParameter(myMinPower_p->minVoltage, VOLTAGE_SCALE);
1613 			}
1614 			if ( mySimNetId != UNKNOWN_NET && netVoltagePtr_v[mySimNetId].full ) {
1615 				CPower * mySimPower_p = netVoltagePtr_v[mySimNetId].full;
1616 				if ( mySimPower_p->simVoltage != UNKNOWN_VOLTAGE ) {
1617 					myPowerFile << " sim@" << PrintParameter(mySimPower_p->simVoltage, VOLTAGE_SCALE);
1618 				}
1619 				if ( mySimPower_p->type[HIZ_BIT] ) {
1620 					myPowerFile << " open";
1621 				}
1622 			}
1623 			if ( myMaxPower_p && myMaxPower_p->maxVoltage != UNKNOWN_VOLTAGE ) {
1624 				myPowerFile << " max@" << PrintParameter(myMaxPower_p->maxVoltage, VOLTAGE_SCALE);
1625 			}
1626 			myPowerFile << endl;
1627 		}
1628 	}
1629 	// print internal definitions
1630 	unordered_set<text_t> myInternalDefinitions;  // only print internal definitions once
1631 	netId_t myFirstNetId = myInstance_p->firstNetId;
1632 	for ( netId_t net_it = myFirstNetId; net_it < netCount && IsSubcircuitOf(netParent_v[net_it], theInstanceId); net_it++ ) {
1633 		CPower * myPower_p = netVoltagePtr_v[net_it].full;
1634 		if ( myPower_p ) {
1635 			text_t mySignal = myPower_p->powerSignal();
1636 			if ( ! IsEmpty(mySignal) && mySignal != myResistorText && myPower_p->simCalculationType != ESTIMATED_CALCULATION
1637 					&& myInternalDefinitions.count(mySignal) == 0 ) {  // do not print resistor calculations, latch/scrc estimates, or duplicates
1638 				myPowerFile << mySignal << " " << myPower_p->definition << endl;
1639 				myInternalDefinitions.insert(mySignal);
1640 			}
1641 		}
1642 	}
1643 	cout << "Wrote debug power file " << thePowerFileName << endl;
1644 	myPowerFile.close();
1645 }
1646