1 /*
2 * CModel.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 "CModel.hh"
25
26 #include "CCondition.hh"
27 #include "CParameterMap.hh"
28 #include "CDevice.hh"
29 #include "CCircuit.hh"
30 #include "CPower.hh"
31 #include <regex>
32
CModelCheck(string theCheck,string theParameter,string theInclusiveMin,string theExclusiveMin,string theInclusiveMax,string theExclusiveMax)33 CModelCheck::CModelCheck(string theCheck, string theParameter, string theInclusiveMin, string theExclusiveMin, string theInclusiveMax, string theExclusiveMax ) {
34 check = theCheck;
35 parameter = theParameter;
36 isVoltage = (theParameter[0] == 'V');
37 minInclusiveText = theInclusiveMin;
38 minExclusiveText = theExclusiveMin;
39 maxInclusiveText = theInclusiveMax;
40 maxExclusiveText = theExclusiveMax;
41 SetValue(minInclusiveText, minInclusiveVoltage, minInclusiveValue);
42 SetValue(maxInclusiveText, maxInclusiveVoltage, maxInclusiveValue);
43 SetValue(minExclusiveText, minExclusiveVoltage, minExclusiveValue);
44 SetValue(maxExclusiveText, maxExclusiveVoltage, maxExclusiveValue);
45 }
46
SetValue(string theParameter,voltage_t & theVoltage,float & theValue)47 void CModelCheck::SetValue(string theParameter, voltage_t &theVoltage, float &theValue) {
48 if ( ! IsEmpty(theParameter) ) {
49 if ( isVoltage && IsValidVoltage_(theParameter) ) {
50 theVoltage = round(from_string<float>(theParameter) * VOLTAGE_SCALE + 0.1);
51 } else {
52 theValue = from_string<float>(theParameter);
53 }
54 }
55 }
56
CModel(string theParameterString)57 CModel::CModel(string theParameterString) {
58 // parameter string example
59 // NMOS nch Vth=0.500 Vgs=0.3 Vds=0.5 Vbs=0.4 condition=(L<0.4u w>=1.2u)
60 // RESISTOR fuse Vds=0.4 R=1000 condition=(r<10) model=switch_on
61 // BOX res1 model=resistor diode=(1-3,2-3)
62 string myParameterName;
63 string myParameterValue;
64 size_t myEqualIndex;
65 size_t myStringBegin = theParameterString.find_first_not_of(" \t");
66 size_t myStringEnd = theParameterString.find_first_of(" \t", myStringBegin);
67 definition = theParameterString.substr(myStringBegin, myStringEnd - myStringBegin);
68 type = gModelTypeStringMap.at(theParameterString.substr(myStringBegin, myStringEnd - myStringBegin));
69 baseType = gBaseModelTypePrefixMap.at(type);
70 if ( IsMos_(type) ) {
71 resistanceDefinition = DEFAULT_MOS_RESISTANCE;
72 } else if ( type == RESISTOR ) {
73 resistanceDefinition = DEFAULT_RESISTANCE;
74 }
75 myStringBegin = theParameterString.find_first_not_of(" \t", myStringEnd);
76 myStringEnd = theParameterString.find_first_of(" \t", myStringBegin);
77 name = theParameterString.substr(myStringBegin, myStringEnd - myStringBegin);
78 definition = definition + " " + name;
79
80 myStringBegin = theParameterString.find_first_not_of(" \t", myStringEnd);
81 while ( myStringBegin < theParameterString.length() ) {
82 myStringEnd = theParameterString.find_first_of(" \t", myStringBegin);
83 definition = definition + " " + theParameterString.substr(myStringBegin, myStringEnd - myStringBegin);
84
85 myEqualIndex = theParameterString.find("=", myStringBegin);
86 myParameterName = theParameterString.substr(myStringBegin, myEqualIndex - myStringBegin);
87 myParameterValue = theParameterString.substr(myEqualIndex + 1, myStringEnd - (myEqualIndex + 1));
88 if (myParameterName == "Vth") {
89 vthDefinition = myParameterValue; // String_to_Voltage(myParameterValue);
90 } else if (myParameterName == "Vgs") {
91 maxVgsDefinition = myParameterValue; // String_to_Voltage(myParameterValue);
92 } else if (myParameterName == "Vds") {
93 maxVdsDefinition = myParameterValue; // String_to_Voltage(myParameterValue);
94 } else if (myParameterName == "Vbs") {
95 maxVbsDefinition = myParameterValue; // String_to_Voltage(myParameterValue);
96 } else if (myParameterName == "Vbg") {
97 maxVbgDefinition = myParameterValue; // String_to_Voltage(myParameterValue);
98 } else if (myParameterName == "R") {
99 resistanceDefinition = myParameterValue;
100 } else if (myParameterName == "model") {
101 if ( baseType != "M" && baseType != "R" && baseType != "C" && baseType != "X" ) throw EModelError("basetype " + baseType + "cannot be overriden as " + myParameterValue);
102 if ( baseType == "M" && ( myParameterValue != "fuse_on" && myParameterValue != "fuse_off" ) ) throw EModelError("mosfet cannot be overriden as " + myParameterValue);
103 if ( baseType != "X" && myParameterValue != "switch_on" && myParameterValue != "switch_off" && myParameterValue != "fuse_on" && myParameterValue != "fuse_off" ) throw EModelError("invalid override " + myParameterValue);
104 type = gModelTypeStringMap.at(myParameterValue);
105 } else if (myParameterName == "condition") {
106 CreateConditions(myParameterValue);
107 } else if (myParameterName == "diode") {
108 SetDiodes(myParameterValue);
109 } else {
110 throw EModelError("unknown parameter '" + theParameterString.substr(myStringBegin, myStringEnd - myStringBegin) + "' in " + definition);
111 }
112 myStringBegin = theParameterString.find_first_not_of(" \t", myStringEnd);
113 }
114 if ( diodeList.empty() ) {
115 if ( IsNmos_(type) ) {
116 diodeList.push_back(make_pair(4,1));
117 diodeList.push_back(make_pair(4,3));
118 } else if ( IsPmos_(type) ) {
119 diodeList.push_back(make_pair(1,4));
120 diodeList.push_back(make_pair(3,4));
121 } else if ( type == DIODE ) {
122 diodeList.push_back(make_pair(1,2));
123 }
124 }
125 }
126
ParameterMatch(CParameterMap & theParameterMap,text_t theCellName)127 bool CModel::ParameterMatch(CParameterMap& theParameterMap, text_t theCellName) {
128 CNormalValue myCheckValue;
129
130 for (CConditionPtrList::iterator condition_ppit = conditionPtrList.begin(); condition_ppit != conditionPtrList.end(); condition_ppit++) {
131 try {
132 myCheckValue = theParameterMap.at((*condition_ppit)->parameter);
133 if ( ! (*condition_ppit)->CheckCondition(myCheckValue) ) return (false);
134 }
135 catch (const out_of_range& oor_exception) {
136 throw EFatalError("missing parameter " + (*condition_ppit)->parameter + " in " + name);
137 }
138 }
139 if ( cellFilterRegex_p ) {
140 if ( ! regex_match(theCellName, *cellFilterRegex_p) ) return false;
141 }
142 return (true);
143 }
144
CreateConditions(string theConditionString)145 void CModel::CreateConditions (string theConditionString) {
146 // condition string example
147 // condition=(L<0.4u w>=1.2u)
148 // condition=(r<10)
149 string myConditionName;
150 string myConditionRelation;
151 string myConditionValue;
152 size_t myRelationIndex;
153 size_t myValueIndex;
154 size_t myStringBegin = theConditionString.find_first_not_of("( \t");
155 size_t myStringEnd = theConditionString.find_first_of(", )", myStringBegin);
156 while ( myStringEnd < theConditionString.length() ) {
157 myRelationIndex = theConditionString.find_first_of("<=>", myStringBegin);
158 myValueIndex = theConditionString.find_first_not_of("<=>", myRelationIndex);
159 myConditionName = trim_(theConditionString.substr(myStringBegin, myRelationIndex - myStringBegin));
160 myConditionRelation = trim_(theConditionString.substr(myRelationIndex, myValueIndex - myRelationIndex));
161 myConditionValue = trim_(theConditionString.substr(myValueIndex, myStringEnd - myValueIndex));
162 toupper_(myConditionName);
163 if ( myConditionName == "CELL" && myConditionRelation == "=" ) {
164 cellFilter = myConditionValue;
165 cellFilterRegex_p = new regex(FuzzyFilter(myConditionValue));
166 } else {
167 conditionPtrList.push_back(new CCondition(myConditionName, myConditionRelation, myConditionValue));
168 }
169 myStringBegin = theConditionString.find_first_not_of("), \t", myStringEnd);
170 myStringEnd = theConditionString.find_first_of(", )", myStringBegin);
171 }
172 }
173
SetDiodes(string theDiodeString)174 void CModel::SetDiodes (string theDiodeString) {
175 // diode string example
176 // diode=(1-3,2-3)
177 // diode=(3-2)
178 if ( ! diodeList.empty() ) {
179 diodeList.clear();
180 }
181 int myAnode;
182 int myCathode;
183 size_t myDelimterIndex;
184 size_t myStringBegin = theDiodeString.find_first_not_of("(, \t");
185 size_t myStringEnd = theDiodeString.find_first_of("), \t", myStringBegin);
186 while ( myStringEnd < theDiodeString.length() ) {
187 myDelimterIndex = theDiodeString.find_first_of("-", myStringBegin);
188 myAnode = from_string<int>(trim_(theDiodeString.substr(myStringBegin, myDelimterIndex - myStringBegin)));
189 myCathode = from_string<int>(trim_(theDiodeString.substr(myDelimterIndex+1, myStringEnd - myDelimterIndex - 1)));
190 diodeList.push_back(make_pair(myAnode, myCathode));
191 myStringBegin = theDiodeString.find_first_not_of("), \t", myStringEnd);
192 myStringEnd = theDiodeString.find_first_of("), \t", myStringBegin);
193 }
194 }
195
Clear()196 void CModel::Clear() {
197 while ( ! conditionPtrList.empty() ) {
198 delete conditionPtrList.front();
199 conditionPtrList.pop_front();
200 }
201 }
202
ModelCount()203 size_t CModel::ModelCount() {
204 size_t myModelCount = 0;
205 for (CDevice * myDevice_p = firstDevice_p; myDevice_p; myDevice_p = myDevice_p->nextDevice_p) {
206 myModelCount += myDevice_p->parent_p->instanceCount;
207 }
208 return myModelCount;
209 }
210
Print(ostream & theLogFile,bool thePrintDeviceListFlag,string theIndentation)211 void CModel::Print(ostream & theLogFile, bool thePrintDeviceListFlag, string theIndentation) {
212 string myIndentation = theIndentation + " ";
213 theLogFile << theIndentation << "Model> "<< setw(10) << left << name;
214 theLogFile << right << setw(10) << ModelCount();
215 theLogFile << " " << baseType << "->" << setw(10) << left << gModelTypeMap[type];
216 theLogFile << " Parameters>";
217 switch (type) {
218 case NMOS: case PMOS: case LDDN: case LDDP: {
219 theLogFile << " Vth=" << PrintToleranceParameter(vthDefinition, Vth, VOLTAGE_SCALE);
220 if ( ! IsEmpty(maxVdsDefinition) ) theLogFile << " Vds=" << PrintToleranceParameter(maxVdsDefinition, maxVds, VOLTAGE_SCALE);
221 if ( ! IsEmpty(maxVgsDefinition) ) theLogFile << " Vgs=" << PrintToleranceParameter(maxVgsDefinition, maxVgs, VOLTAGE_SCALE);
222 if ( ! IsEmpty(maxVbgDefinition) ) theLogFile << " Vbg=" << PrintToleranceParameter(maxVbgDefinition, maxVbg, VOLTAGE_SCALE);
223 if ( ! IsEmpty(maxVbsDefinition) ) theLogFile << " Vbs=" << PrintToleranceParameter(maxVbsDefinition, maxVbs, VOLTAGE_SCALE);
224 theLogFile << " R=" << resistanceDefinition;
225 break; }
226 case RESISTOR: {
227 if ( ! IsEmpty(maxVdsDefinition) ) theLogFile << " Vds=" << PrintToleranceParameter(maxVdsDefinition, maxVds, VOLTAGE_SCALE);
228 if ( ! IsEmpty(resistanceDefinition) ) theLogFile << " R=" << resistanceDefinition;
229 break; }
230 case FUSE_ON:
231 case FUSE_OFF:
232 case CAPACITOR:
233 case DIODE: {
234 if ( ! IsEmpty(maxVdsDefinition) ) theLogFile << " Vds=" << PrintToleranceParameter(maxVdsDefinition, maxVds, VOLTAGE_SCALE);
235 break; }
236 case BIPOLAR:
237 case SWITCH_ON:
238 case SWITCH_OFF: {
239 break; }
240 default: {
241 theLogFile << " Unknown type:";
242 }
243 }
244 if ( ! conditionPtrList.empty() ) {
245 theLogFile << " Conditions>";
246 for (CConditionPtrList::iterator condition_ppit = conditionPtrList.begin(); condition_ppit != conditionPtrList.end(); condition_ppit++) {
247 (*condition_ppit)->Print(theLogFile, "same-line");
248 }
249 }
250 if ( cellFilter != "" ) {
251 theLogFile << " Cell filter>" << cellFilter;
252 }
253 if ( ! diodeList.empty() ) {
254 theLogFile << " Diodes>";
255 for ( auto diode_pit = diodeList.begin(); diode_pit != diodeList.end(); diode_pit++ ) {
256 theLogFile << " " << diode_pit->first << "-" << diode_pit->second;
257 }
258 }
259 theLogFile << endl;
260 if ( firstDevice_p && thePrintDeviceListFlag ) {
261 theLogFile << myIndentation << "DeviceList> start" << endl;
262 for ( CDevice * myDevice_p = firstDevice_p; myDevice_p != NULL; myDevice_p = myDevice_p->nextDevice_p ) {
263 theLogFile << myIndentation << " " << myDevice_p->parent_p->name << "/" << myDevice_p->name << endl;
264 }
265 theLogFile << myIndentation << "DeviceList> end" << endl;
266 }
267 }
268
ConditionString()269 string CModel::ConditionString() {
270 stringstream myConditionString;
271 if ( ! conditionPtrList.empty() ) {
272 myConditionString << " Conditions>";
273 for (CConditionPtrList::iterator condition_ppit = conditionPtrList.begin(); condition_ppit != conditionPtrList.end(); condition_ppit++) {
274 (*condition_ppit)->Print(myConditionString, "same-line");
275 }
276 }
277 if ( cellFilter != "" ) {
278 myConditionString << " Cell filter>" << cellFilter;
279 }
280 return(myConditionString.str());
281 }
282
Clear()283 void CModelListMap::Clear() {
284 while ( ! empty() ) {
285 CModelList& myModelList = begin()->second;
286 while ( ! myModelList.empty() ) {
287 myModelList.front().Clear();
288 myModelList.pop_front();
289 }
290 erase(begin());
291 }
292 }
293
AddModel(string theParameterString)294 void CModelListMap::AddModel(string theParameterString) {
295 try {
296 CModel myNewModel(theParameterString);
297 string myModelKey = myNewModel.baseType + " " + myNewModel.name;
298 try {
299 this->at(myModelKey).push_back(myNewModel);
300 if ( (*this)[myModelKey].vthDefinition != myNewModel.vthDefinition ) {
301 cout << "Vth mismatch for " << myNewModel.name << " ignored. ";
302 cout << (*this)[myModelKey].vthDefinition << "!=" << myNewModel.vthDefinition << endl;
303 }
304 }
305 catch (const out_of_range& oor_exception) {
306 (*this)[myModelKey].push_back(myNewModel);
307 (*this)[myModelKey].vthDefinition = myNewModel.vthDefinition;
308 }
309 }
310 catch (EModelError & myError) {
311 cout << myError.what() << endl;
312 cout << "Invalid model format: " << theParameterString << endl;
313 hasError = true;
314 }
315 catch (...) {
316 cout << "Invalid model format: " << theParameterString << endl;
317 hasError = true;
318 }
319 }
320
FindModel(text_t theCellName,text_t theParameterText,CTextResistanceMap & theParameterResistanceMap,ostream & theLogFile)321 CModel * CModelListMap::FindModel(text_t theCellName, text_t theParameterText, CTextResistanceMap& theParameterResistanceMap, ostream& theLogFile) {
322 // FindModel: Set the model type based on theParameterText. Also adds entry to theParameterResistanceMap.
323 string myParameterString = trim_(string(theParameterText));
324 string myModelKey = myParameterString.substr(0, myParameterString.find(" ", 2));
325 try {
326 CParameterMap myParameterMap;
327 if ( myParameterString.length() > myModelKey.length() ) {
328 // if there are parameters besides the model name
329 myParameterMap.CreateParameterMap(myParameterString.substr(myModelKey.length() + 1));
330 }
331 CModelList::iterator myLastModel = this->at(myModelKey).end();
332 for (CModelList::iterator model_pit = this->at(myModelKey).begin(); model_pit != myLastModel; model_pit++) {
333 if ( model_pit->ParameterMatch(myParameterMap, theCellName) ) {
334 switch (model_pit->type) {
335 // TODO: do not recalculate if already exists
336 case NMOS: case PMOS: case LDDN: case LDDP: {
337 theParameterResistanceMap[theParameterText] = myParameterMap.CalculateResistance(model_pit->resistanceDefinition);
338 if ( theParameterResistanceMap[theParameterText] == MAX_RESISTANCE ) {
339 theLogFile << "WARNING: resistance for " << theParameterText << " exceeds maximum" << endl;
340 }
341 break; }
342 case RESISTOR: {
343 theParameterResistanceMap[theParameterText] = myParameterMap.CalculateResistance(model_pit->resistanceDefinition);
344 if ( theParameterResistanceMap[theParameterText] == MAX_RESISTANCE ) {
345 theLogFile << "WARNING: resistance for " << theParameterText << " exceeds maximum" << endl;
346 }
347 break; }
348 default: theParameterResistanceMap[theParameterText] = 1;
349 }
350
351 return &(*model_pit);
352 }
353 }
354 return (NULL);
355 }
356 catch (const out_of_range& oor_exception) {
357 return (NULL);
358 }
359 }
360
FindModelList(string theModelName)361 CModelList * CModelListMap::FindModelList(string theModelName) {
362 // FindModelList: Return a pointer to the first model list for theModelName
363 //
364 // Warning: is 2 different types of models have the same name, only returns the first.
365 for (auto mapPair_pit = begin(); mapPair_pit != end(); mapPair_pit++) {
366 if ( mapPair_pit->first.substr(2) == theModelName ) {
367 return &mapPair_pit->second;
368
369 }
370 }
371 return NULL;
372 }
373
Print(ostream & theLogFile,string theIndentation)374 void CModelListMap::Print(ostream & theLogFile, string theIndentation) {
375 string myIndentation = theIndentation + " ";
376 theLogFile << endl << theIndentation << "ModelList> filename " << filename << endl;
377 for (CModelListMap::iterator modelList_pit = begin(); modelList_pit != end(); modelList_pit++) {
378 for (CModelList::iterator model_pit = modelList_pit->second.begin(); model_pit != modelList_pit->second.end(); model_pit++) {
379 model_pit->Print(theLogFile, PRINT_DEVICE_LIST_OFF, myIndentation);
380 }
381 }
382 theLogFile << theIndentation << "ModelList> end" << endl << endl;
383 }
384
DebugPrint(string theIndentation)385 void CModelListMap::DebugPrint(string theIndentation) {
386 string myIndentation = theIndentation + " ";
387 cout << theIndentation << "ModelList> start" << endl;
388 for (CModelListMap::iterator modelList_pit = begin(); modelList_pit != end(); modelList_pit++) {
389 for (CModelList::iterator model_pit = modelList_pit->second.begin(); model_pit != modelList_pit->second.end(); model_pit++) {
390 model_pit->Print(cout, PRINT_DEVICE_LIST_ON, myIndentation);
391 }
392 }
393 cout << theIndentation << "ModelList> end" << endl << endl;
394 }
395
396 #define PERMIT_UNDEFINED true
SetVoltageTolerances(teestream & theReportFile,CPowerPtrMap & thePowerMacroPtrMap)397 returnCode_t CModelListMap::SetVoltageTolerances(teestream & theReportFile, CPowerPtrMap & thePowerMacroPtrMap) {
398 theReportFile << "Setting model tolerances..." << endl;
399 bool myToleranceErrorFlag = false;
400 for (CModelListMap::iterator modelList_pit = begin(); modelList_pit != end(); modelList_pit++) {
401 for (CModelList::iterator model_pit = modelList_pit->second.begin(); model_pit != modelList_pit->second.end(); model_pit++) {
402 try {
403 if ( ! IsEmpty(model_pit->vthDefinition) ) {
404 model_pit->Vth = thePowerMacroPtrMap.CalculateVoltage(model_pit->vthDefinition, SIM_POWER, (*this), PERMIT_UNDEFINED);
405 if ( model_pit->Vth == UNKNOWN_VOLTAGE ) model_pit->validModel = false;
406 }
407 if ( ! IsEmpty(model_pit->maxVbgDefinition) ) {
408 model_pit->maxVbg = thePowerMacroPtrMap.CalculateVoltage(model_pit->maxVbgDefinition, SIM_POWER, (*this), PERMIT_UNDEFINED);
409 if ( model_pit->maxVbg == UNKNOWN_VOLTAGE ) model_pit->validModel = false;
410 }
411 if ( ! IsEmpty(model_pit->maxVbsDefinition) ) {
412 model_pit->maxVbs = thePowerMacroPtrMap.CalculateVoltage(model_pit->maxVbsDefinition, SIM_POWER, (*this), PERMIT_UNDEFINED);
413 if ( model_pit->maxVbs == UNKNOWN_VOLTAGE ) model_pit->validModel = false;
414 }
415 if ( ! IsEmpty(model_pit->maxVdsDefinition) ) {
416 model_pit->maxVds = thePowerMacroPtrMap.CalculateVoltage(model_pit->maxVdsDefinition, SIM_POWER, (*this), PERMIT_UNDEFINED);
417 if ( model_pit->maxVds == UNKNOWN_VOLTAGE ) model_pit->validModel = false;
418 }
419 if ( ! IsEmpty(model_pit->maxVgsDefinition) ) {
420 model_pit->maxVgs = thePowerMacroPtrMap.CalculateVoltage(model_pit->maxVgsDefinition, SIM_POWER, (*this), PERMIT_UNDEFINED);
421 if ( model_pit->maxVgs == UNKNOWN_VOLTAGE ) model_pit->validModel = false;
422 }
423 }
424 catch (EPowerError & myException) {
425 theReportFile << "ERROR: Model tolerance " << myException.what() << endl;
426 myToleranceErrorFlag = true;
427 }
428 }
429 }
430 return (myToleranceErrorFlag) ? FAIL : OK;
431 }
432
433
434