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