1 /*
2  * CCircuit.cc
3  *
4  * Copyright 2014-2018 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 "CCircuit.hh"
25 
26 class CCvcDb;
27 #include "CDevice.hh"
28 #include "CFixedText.hh"
29 #include "CCvcDb.hh"
30 
31 text_t CCircuit::lastDeviceMap = NULL;
32 CTextDeviceIdMap CCircuit::localDeviceIdMap;
33 text_t CCircuit::lastSubcircuitMap = NULL;
34 CTextDeviceIdMap CCircuit::localSubcircuitIdMap;
35 
AddPortSignalIds(CTextList * thePortList_p)36 void CCircuit::AddPortSignalIds(CTextList * thePortList_p) {
37 	for (CTextList::iterator text_pit = thePortList_p->begin(); text_pit != thePortList_p->end(); ++text_pit) {
38 		localSignalIdMap[*text_pit] = portCount++;
39 	}
40 }
41 
SetSignalIds(CTextList * signalList_p,CNetIdVector & signalId_v)42 void CCircuit::SetSignalIds(CTextList * signalList_p, CNetIdVector& signalId_v ) {
43 	netId_t mySignalId;
44 
45 	signalId_v.reserve(signalList_p->size());
46 	for (CTextList::iterator text_pit = signalList_p->begin(); text_pit != signalList_p->end(); ++text_pit) {
47 		try {
48 			mySignalId = localSignalIdMap.at(*text_pit);
49 		}
50 		catch (const out_of_range& oor_exception) {
51 			mySignalId = localSignalIdMap.size();
52 			localSignalIdMap[*text_pit] = mySignalId;
53 			internalSignalList.push_back(*text_pit);
54 		}
55 		signalId_v.push_back(mySignalId);
56 	}
57 }
58 
GetLocalDeviceId(text_t theName)59 deviceId_t CCircuit::GetLocalDeviceId(text_t theName) {
60 	if ( CCircuit::lastDeviceMap != name ) {
61 		CCircuit::localDeviceIdMap.clear();
62 		for ( deviceId_t device_it = 0; device_it < devicePtr_v.size(); device_it++ ) {
63 			CCircuit::localDeviceIdMap[devicePtr_v[device_it]->name] = device_it;
64 		}
65 		CCircuit::lastDeviceMap = name;
66 	}
67 	return (CCircuit::localDeviceIdMap.at(theName));
68 }
69 
GetLocalSubcircuitId(text_t theName)70 deviceId_t CCircuit::GetLocalSubcircuitId(text_t theName) {
71 	if ( CCircuit::lastSubcircuitMap != name ) {
72 		CCircuit::localSubcircuitIdMap.clear();
73 		for ( deviceId_t device_it = 0; device_it < subcircuitPtr_v.size(); device_it++ ) {
74 			CCircuit::localSubcircuitIdMap[subcircuitPtr_v[device_it]->name] = device_it;
75 		}
76 		CCircuit::lastSubcircuitMap = name;
77 	}
78 	return (CCircuit::localSubcircuitIdMap.at(theName));
79 }
80 
LoadDevices(CDevicePtrList * theDevicePtrList_p)81 void CCircuit::LoadDevices(CDevicePtrList * theDevicePtrList_p) {
82 	CDevice *	myDevice_p;
83 	deviceId_t  myDeviceIndex = 0;
84 	deviceId_t  myInstanceIndex = 0;
85 	static int myDeviceCount = 0;
86 	static int myCircuitCount = 0;
87 	static int myInstanceCount = 0;
88 	static int myPrintCount = 0;
89 
90 	devicePtr_v.reserve(theDevicePtrList_p->DeviceCount());
91 	deviceErrorCount_v.resize(theDevicePtrList_p->DeviceCount());
92 	devicePrintCount_v.resize(theDevicePtrList_p->DeviceCount());
93 	subcircuitPtr_v.reserve(theDevicePtrList_p->SubcircuitCount());
94 	myCircuitCount++;
95 	if ( ++myPrintCount >= 100000 ) {
96 		cout << "Read " << myCircuitCount << " circuits, " << myInstanceCount << " instances, " << myDeviceCount << " devices\r" << std::flush;
97 		myPrintCount = 0;
98 	}
99 	CTextDeviceIdMap myDeviceIdMap;  // temporary map to check for duplicate device/instance names
100 	for (CDevicePtrList::iterator device_ppit = theDevicePtrList_p->begin(); device_ppit != theDevicePtrList_p->end(); device_ppit++) {
101 		myDevice_p = *device_ppit;
102 		SetSignalIds(myDevice_p->signalList_p, myDevice_p->signalId_v);
103 		myDevice_p->parent_p = this;
104 		if ( myDeviceIdMap.count(myDevice_p->name) ) {
105 			cout << "ERROR: Duplicate instance " << myDevice_p->name << " in " << name << endl;
106 			throw EDuplicateInstance();
107 		}
108 		if ( myDevice_p->IsSubcircuit() ) {
109 			myDevice_p->offset = myInstanceIndex++;
110 			myDeviceIdMap[myDevice_p->name] = subcircuitPtr_v.size();
111 			subcircuitPtr_v.push_back(myDevice_p);
112 			myInstanceCount++;
113 			myPrintCount++;
114 		} else {
115 			myDevice_p->offset = myDeviceIndex++;
116 			myDeviceIdMap[myDevice_p->name] = devicePtr_v.size();
117 			devicePtr_v.push_back(myDevice_p);
118 			myDeviceCount++;
119 			myPrintCount++;
120 		}
121 	}
122 	// list to vector conversion (top circuit must be redone to include top ports)
123 	internalSignal_v.reserve(internalSignalList.size());
124 	while( ! internalSignalList.empty() ) {
125 		internalSignal_v.push_back(internalSignalList.front());
126 		internalSignalList.pop_front();
127 	}
128 
129 }
130 
CountObjectsAndLinkSubcircuits(unordered_map<text_t,CCircuit * > & theCircuitNameMap)131 void CCircuit::CountObjectsAndLinkSubcircuits(unordered_map<text_t, CCircuit *> & theCircuitNameMap) {
132 	CCircuit * myChild_p;
133 
134 	deviceCount = devicePtr_v.size();
135 	netCount = LocalNetCount();
136 	subcircuitCount = subcircuitPtr_v.size();
137 	for (CDevicePtrVector::iterator subcircuit_ppit = subcircuitPtr_v.begin(); subcircuit_ppit != subcircuitPtr_v.end(); subcircuit_ppit++) {
138 		try {
139 			(*subcircuit_ppit)->master_p = theCircuitNameMap.at((*subcircuit_ppit)->masterName);
140 			myChild_p = (*subcircuit_ppit)->master_p;
141 			if ( myChild_p->linked ) {
142 				if ( myChild_p->subcircuitCount > 0 ) {
143 					myChild_p->CountInstantiations();
144 				}
145 			} else {
146 				myChild_p->CountObjectsAndLinkSubcircuits(theCircuitNameMap);
147 			}
148 			if ( (*subcircuit_ppit)->signalId_v.size() != myChild_p->portCount ) {
149 				stringstream myErrorMessage;
150 				myErrorMessage << "port mismatch in " << (*subcircuit_ppit)->name << " " << (*subcircuit_ppit)->signalId_v.size() << ":" << myChild_p->portCount << endl;
151 				throw EFatalError(myErrorMessage.str());
152 			}
153 			myChild_p->instanceCount++;
154 			deviceCount += myChild_p->deviceCount;
155 			netCount += myChild_p->netCount;
156 			subcircuitCount += myChild_p->subcircuitCount;
157 		}
158 		catch (const out_of_range& oor_exception) {
159 			stringstream myErrorMessage;
160 			myErrorMessage << "could not find subcircuit: " << (*subcircuit_ppit)->name << "(" << (*subcircuit_ppit)->masterName << ") in " << name << endl;
161 			throw EFatalError(myErrorMessage.str());
162 		}
163 	}
164 	linked = true;
165 }
166 
CountInstantiations()167 void CCircuit::CountInstantiations() {
168 	CCircuit * myChild_p;
169 
170 	for (CDevicePtrVector::iterator subcircuit_ppit = subcircuitPtr_v.begin(); subcircuit_ppit != subcircuitPtr_v.end(); subcircuit_ppit++) {
171 		myChild_p = (*subcircuit_ppit)->master_p;
172 		assert(myChild_p->linked);
173 		if ( myChild_p->subcircuitCount > 0 ) {
174 			myChild_p->CountInstantiations();
175 		}
176 		myChild_p->instanceCount++;
177 	}
178 }
179 
Print(const string theIndentation)180 void CCircuit::Print (const string theIndentation) {
181 	CTextVector mySignalName_v;
182 	netId_t mySignalId = 0;
183 
184 	cout << theIndentation << "Circuit Name: " << name << endl;
185 	cout << theIndentation << "Linked: " << linked;
186 	cout << "  Counts Devices: " << deviceCount;
187 	cout << "  Nets: " << netCount;
188 	cout << "  Subcircuits: " << subcircuitCount;
189 	cout << "  Instances: " << instanceCount << endl;
190 	string myIndentation = theIndentation + " ";
191 	cout << myIndentation << "Signal List(" << portCount << "/" << localSignalIdMap.size() << "): ";
192 	mySignalName_v.reserve(localSignalIdMap.size());
193 	for (CTextNetIdMap::iterator textNetIdPair_pit = localSignalIdMap.begin(); textNetIdPair_pit != localSignalIdMap.end(); ++textNetIdPair_pit) {
194 		mySignalName_v[textNetIdPair_pit->second] = textNetIdPair_pit->first;
195 	}
196 	while (mySignalId < localSignalIdMap.size()) {
197 		cout << " " << mySignalName_v[mySignalId] << ":" << mySignalId;
198 		mySignalId++;
199 	}
200 	cout << endl;
201 	devicePtr_v.Print(mySignalName_v, myIndentation, "DeviceList>");
202 	subcircuitPtr_v.Print(mySignalName_v, this, myIndentation, "SubcircuitList>");
203 	if ( instanceCount > 0 && instanceId_v.size() == instanceCount ) {
204 		cout << myIndentation << "InstanceList>";
205 		for (instanceId_t instance_it = 0; instance_it < instanceCount; instance_it++) {
206 			cout << " " << instanceId_v[instance_it];
207 		}
208 		cout << endl;
209 	}
210 	cout << endl;
211 }
212 
Clear()213 void CCircuitPtrList::Clear() {
214 	cdlText.Clear();
215 	circuitNameMap.clear();
216 	parameterText.Clear();
217 	for ( auto circuit_ppit = begin(); circuit_ppit != end(); circuit_ppit++ ) {
218 		delete (*circuit_ppit);
219 	}
220 	errorCount = 0;
221 }
222 
Print(const string theIndentation,const string theHeading)223 void CCircuitPtrList::Print (const string theIndentation, const string theHeading) {
224 	cout << theIndentation << theHeading << " start" << endl;
225 	string myIndentation = theIndentation + " ";
226 	cout << myIndentation << "Cdl text size: " << cdlText.Size() << endl;
227 	for (CCircuitPtrList::iterator circuit_ppit = begin(); circuit_ppit != end(); ++circuit_ppit) {
228 		(*circuit_ppit)->Print(myIndentation);
229 	}
230 	cout << theIndentation << theHeading << " end" << endl << endl;
231 }
232 
FindCircuit(const string theSearchCircuitName)233 CCircuit * CCircuitPtrList::FindCircuit(const string theSearchCircuitName) {
234 	// error handling in calling routine
235 	return(circuitNameMap.at(cdlText.GetTextAddress(theSearchCircuitName)));
236 }
237 
SetChecksum(const string theCircuitName,const string theChecksum)238 void CCircuitPtrList::SetChecksum(const string theCircuitName, const string theChecksum) {
239 	CCircuit * myCircuitPtr = FindCircuit(theCircuitName);
240 	myCircuitPtr->checksum = theChecksum;
241 }
242 
PrintAndResetCircuitErrors(CCvcDb * theCvcDb_p,deviceId_t theErrorLimit,ofstream & theLogFile,ogzstream & theErrorFile,string theSummaryHeading,int theErrorSubIndex,set<modelType_t> & theModelList)243 void CCircuitPtrList::PrintAndResetCircuitErrors(CCvcDb * theCvcDb_p, deviceId_t theErrorLimit, ofstream & theLogFile, ogzstream & theErrorFile,
244 		string theSummaryHeading, int theErrorSubIndex, set<modelType_t> & theModelList) {
245 	list<string> myErrorSummaryList;
246 	theErrorFile << theSummaryHeading << endl;
247 	for (auto circuit_ppit = begin(); circuit_ppit != end(); circuit_ppit++) {
248 		if ( (*circuit_ppit)->instanceCount == 0 ) continue;  // ignore unused circuits
249 		for (size_t device_it = 0; device_it < (*circuit_ppit)->devicePtr_v.size(); device_it++) {
250 			if ( theModelList.empty() || theModelList.count((*circuit_ppit)->devicePtr_v[device_it]->model_p->type) > 0 ) {
251 				if ( (*circuit_ppit)->devicePrintCount_v[device_it][theErrorSubIndex] > 0 ) {
252 					stringstream myErrorSummary;
253 					myErrorSummary.str("");
254 					myErrorSummary << "INFO: SUBCKT (" << (*circuit_ppit)->name << ")/" << (*circuit_ppit)->devicePtr_v[device_it]->name;
255 					myErrorSummary << "(" << (*circuit_ppit)->devicePtr_v[device_it]->model_p->name << ")";
256 					myErrorSummary << " error count " << (*circuit_ppit)->deviceErrorCount_v[device_it][theErrorSubIndex] << "/" << (*circuit_ppit)->instanceId_v.size();
257 					if ( theErrorLimit > 0 && (*circuit_ppit)->deviceErrorCount_v[device_it][theErrorSubIndex] > theErrorLimit ) {
258 						myErrorSummary << " exceeded error limit " << theErrorLimit;
259 					}
260 					myErrorSummary << " checksum(" << (*circuit_ppit)->checksum << ")";
261 					myErrorSummaryList.push_front(myErrorSummary.str());
262 				}
263 				(*circuit_ppit)->deviceErrorCount_v[device_it][theErrorSubIndex] = 0;
264 				(*circuit_ppit)->devicePrintCount_v[device_it][theErrorSubIndex] = 0;
265 			}
266 		}
267 	}
268 	myErrorSummaryList.sort();
269 	for ( auto error_pit = myErrorSummaryList.begin(); error_pit != myErrorSummaryList.end(); error_pit++ ) {
270 		theErrorFile << (*error_pit) << endl;
271 	}
272 	theErrorFile << endl<< "! Finished" << endl << endl;
273 	theCvcDb_p->cellErrorCountMap.clear();
274 }
275 
AllocateInstances(CCvcDb * theCvcDb_p,instanceId_t theFirstInstanceId)276 void CCircuit::AllocateInstances(CCvcDb * theCvcDb_p, instanceId_t theFirstInstanceId) {
277 	instanceId_v.reserve(instanceCount);
278 	instanceHashId_v.resize(instanceCount, UNKNOWN_DEVICE);
279 }
280