1 #include <ot/liberty/celllib.hpp>
2 
3 namespace ot {
4 
5 // Procedure: _uncomment
_uncomment(std::vector<char> & buffer)6 void Celllib::_uncomment(std::vector<char>& buffer) {
7 
8   auto fsize = buffer.size() > 0 ? buffer.size() - 1 : 0;
9 
10   // Mart out the comment
11   for(size_t i=0; i<fsize; ++i) {
12 
13     // Block comment
14     if(buffer[i] == '/' && buffer[i+1] == '*') {
15       buffer[i] = buffer[i+1] = ' ';
16       for(i=i+2; i<fsize; buffer[i++]=' ') {
17         if(buffer[i] == '*' && buffer[i+1] == '/') {
18           buffer[i] = buffer[i+1] = ' ';
19           i = i+1;
20           break;
21         }
22       }
23     }
24 
25     // Line comment
26     if(buffer[i] == '/' && buffer[i+1] == '/') {
27       buffer[i] = buffer[i+1] = ' ';
28       for(i=i+2; i<fsize; ++i) {
29         if(buffer[i] == '\n' || buffer[i] == '\r') {
30           break;
31         }
32         else buffer[i] = ' ';
33       }
34     }
35 
36     // Pond comment
37     if(buffer[i] == '#') {
38       buffer[i] = ' ';
39       for(i=i+1; i<fsize; ++i) {
40         if(buffer[i] == '\n' || buffer[i] == '\r') {
41           break;
42         }
43         else buffer[i] = ' ';
44       }
45     }
46   }
47 }
48 
49 // Procedure: _tokenize
_tokenize(const std::vector<char> & buf,std::vector<std::string_view> & tokens)50 void Celllib::_tokenize(const std::vector<char>& buf, std::vector<std::string_view>& tokens) {
51 
52   static std::string_view dels = "(),:;/#[]{}*\"\\";
53 
54   // get the position
55   const char* beg = buf.data();
56   const char* end = buf.data() + buf.size();
57 
58   // Parse the token.
59   const char *token {nullptr};
60   size_t len {0};
61 
62   tokens.clear();
63 
64   for(const char* itr = beg; itr != end && *itr != 0; ++itr) {
65 
66     // extract the entire quoted string as a token
67     bool is_del = (dels.find(*itr) != std::string_view::npos);
68 
69     if(std::isspace(*itr) || is_del) {
70       if(len > 0) {                            // Add the current token.
71         tokens.push_back({token, len});
72         token = nullptr;
73         len = 0;
74       }
75       // group delimiter is liberty token
76       if(*itr == '(' || *itr == ')' || *itr == '{' || *itr == '}') {
77         tokens.push_back({itr, 1});
78       }
79       // extract the entire quoted string (this is buggy now...)
80       //else if(*itr == '"') {
81       //  for(++itr; itr != end && *itr != '"'; ++itr, ++len) ;
82       //  if(len > 0) {
83       //    tokens.push_back({itr-len, len});
84       //    len = 0;
85       //  }
86       //}
87     }
88     else {
89       if(len == 0) {
90         token = itr;
91       }
92       ++len;
93     }
94   }
95 
96   if(len > 0) {
97     tokens.push_back({token, len});
98   }
99 }
100 
101 // ------------------------------------------------------------------------------------------------
102 
103 // Function: to_string
to_string(DelayModel m)104 std::string to_string(DelayModel m) {
105   switch(m) {
106     case DelayModel::GENERIC_CMOS:
107       return "generic_cmos";
108     break;
109 
110     case DelayModel::TABLE_LOOKUP:
111       return "table_lookup";
112     break;
113 
114     case DelayModel::CMOS2:
115       return "cmos2";
116     break;
117 
118     case DelayModel::PIECEWISE_CMOS:
119       return "piecewise_cmos";
120     break;
121 
122     case DelayModel::DCM:
123       return "dcm";
124     break;
125 
126     case DelayModel::POLYNOMIAL:
127       return "polynomial";
128     break;
129 
130     default:
131       return "undefined";
132     break;
133   }
134 }
135 
136 // Function: lut_template
lut_template(const std::string & name) const137 const LutTemplate* Celllib::lut_template(const std::string& name) const {
138   if(auto itr = lut_templates.find(name); itr == lut_templates.end()) {
139     return nullptr;
140   }
141   else {
142     return &(itr->second);
143   }
144 }
145 
146 // Function: lut_template
lut_template(const std::string & name)147 LutTemplate* Celllib::lut_template(const std::string& name) {
148   if(auto itr = lut_templates.find(name); itr == lut_templates.end()) {
149     return nullptr;
150   }
151   else {
152     return &(itr->second);
153   }
154 }
155 
156 // Function: cell
cell(const std::string & name) const157 const Cell* Celllib::cell(const std::string& name) const {
158   if(auto itr = cells.find(name); itr == cells.end()) {
159     return nullptr;
160   }
161   else {
162     return &(itr->second);
163   }
164 }
165 
166 // Function: cell
cell(const std::string & name)167 Cell* Celllib::cell(const std::string& name) {
168   if(auto itr = cells.find(name); itr == cells.end()) {
169     return nullptr;
170   }
171   else {
172     return &(itr->second);
173   }
174 }
175 
176 // Function: _extract_lut_template
_extract_lut_template(token_iterator & itr,const token_iterator end)177 LutTemplate Celllib::_extract_lut_template(token_iterator& itr, const token_iterator end) {
178 
179   LutTemplate lt;
180 
181   if(itr=on_next_parentheses(
182     itr,
183     end,
184     [&] (auto& name) mutable { lt.name = name; }); itr == end) {
185     OT_LOGF("can't find lut template name");
186   }
187 
188   // Extract the lut template group
189   if(itr = std::find(itr, end, "{"); itr == end) {
190     OT_LOGF("can't find lut template group brace '{'");
191   }
192 
193   //std::cout << lt.name << std::endl;
194 
195   int stack = 1;
196 
197   while(stack && ++itr != end) {
198 
199     // variable 1
200     if(*itr == "variable_1") {                       // Read the variable.
201 
202       if(++itr == end) {
203         OT_LOGF("variable_1 error in lut template ", lt.name);
204       }
205 
206       if(auto vitr = lut_vars.find(*itr); vitr != lut_vars.end()) {
207         lt.variable1 = vitr->second;
208       }
209       else {
210         OT_LOGW("unexpected lut template variable ", *itr);
211       }
212     }
213     // variable 2
214     else if(*itr == "variable_2") {
215 
216       if(++itr == end) {
217         OT_LOGF("variable_2 error in lut template ", lt.name);
218       }
219 
220       if(auto vitr = lut_vars.find(*itr); vitr != lut_vars.end()) {
221         lt.variable2 = vitr->second;
222       }
223       else {
224         OT_LOGW("unexpected lut template variable ", *itr);
225       }
226     }
227     // index_1
228     else if(*itr == "index_1") {
229       itr = on_next_parentheses(itr, end, [&] (auto& str) {
230         lt.indices1.push_back(std::strtof(str.data(), nullptr));
231       });
232     }
233     // index_2
234     else if(*itr == "index_2") {
235       itr = on_next_parentheses(itr, end, [&] (auto& str) {
236         lt.indices2.push_back(std::strtof(str.data(), nullptr));
237       });
238     }
239     else if(*itr == "}") {
240       stack--;
241     }
242     else if(*itr == "{") {
243       stack++;
244     }
245     else {
246     }
247   }
248 
249   if(stack != 0 || *itr != "}") {
250     OT_LOGF("can't find lut template group brace '}'");
251   }
252 
253   return lt;
254 }
255 
256 // Function: _extract_lut
_extract_lut(token_iterator & itr,const token_iterator end)257 Lut Celllib::_extract_lut(token_iterator& itr, const token_iterator end) {
258 
259   Lut lut;
260 
261   if(itr=on_next_parentheses(
262     itr,
263     end,
264     [&] (auto& name) mutable { lut.name = name; }); itr == end) {
265     OT_LOGF("can't find lut template name");
266   }
267 
268   // Set up the template
269   lut.lut_template = lut_template(lut.name);
270 
271   // Extract the lut group
272   if(itr = std::find(itr, end, "{"); itr == end) {
273     OT_LOGF("group brace '{' error in lut ", lut.name);
274   }
275 
276   int stack = 1;
277 
278   size_t size1 = 1;
279   size_t size2 = 1;
280 
281   while(stack && ++itr != end) {
282 
283     if(*itr == "index_1") {
284       itr = on_next_parentheses(itr, end, [&] (auto& v) mutable {
285         lut.indices1.push_back(std::strtof(v.data(), nullptr));
286       });
287 
288       if(lut.indices1.size() == 0) {
289         OT_LOGF("syntax error in ", lut.name, " index_1");
290       }
291 
292       size1 = lut.indices1.size();
293     }
294     else if(*itr == "index_2") {
295       itr = on_next_parentheses(itr, end, [&] (auto& v) mutable {
296         lut.indices2.push_back(std::strtof(v.data(), nullptr));
297       });
298 
299       if(lut.indices2.size() == 0) {
300         OT_LOGF("syntax error in ", lut.name, " index_2");
301       }
302 
303       size2 = lut.indices2.size();
304     }
305     else if(*itr == "values") {
306 
307       if(lut.indices1.empty()) {
308         if(size1 != 1) {
309           OT_LOGF("empty indices1 in non-scalar lut ", lut.name);
310         }
311         lut.indices1.resize(size1);
312       }
313 
314       if(lut.indices2.empty()){
315         if(size2 != 1) {
316           OT_LOGF("empty indices2 in non-scalar lut ", lut.name);
317         }
318         lut.indices2.resize(size2);
319       }
320 
321       lut.table.resize(size1*size2);
322 
323       int id {0};
324       itr = on_next_parentheses(itr, end, [&] (auto& v) mutable {
325         lut.table[id++] = std::strtof(v.data(), nullptr);
326       });
327     }
328     else if(*itr == "}") {
329       stack--;
330     }
331     else if(*itr == "{") {
332       stack++;
333     }
334     else {
335     }
336   }
337 
338   if(stack != 0 || *itr != "}") {
339     OT_LOGF("group brace '}' error in lut ", lut.name);
340   }
341 
342   return lut;
343 }
344 
345 // Function: _extract_timing
_extract_timing(token_iterator & itr,const token_iterator end)346 Timing Celllib::_extract_timing(token_iterator& itr, const token_iterator end) {
347 
348   Timing timing;
349 
350   // Extract the lut template group
351   if(itr = std::find(itr, end, "{"); itr == end) {
352     OT_LOGF("can't find group brace '{' in timing");
353   }
354 
355   int stack = 1;
356 
357   while(stack && ++itr != end) {
358 
359     if (*itr == "cell_fall") {
360       timing.cell_fall = _extract_lut(itr, end);
361     }
362     else if (*itr == "cell_rise") {                  // Rise delay.
363       timing.cell_rise = _extract_lut(itr, end);
364     }
365     else if (*itr == "fall_transition") {            // Fall slew.
366       timing.fall_transition = _extract_lut(itr, end);
367     }
368     else if (*itr == "rise_transition") {            // Rise slew.
369       timing.rise_transition = _extract_lut(itr, end);
370     }
371     else if (*itr == "rise_constraint") {            // FF rise constraint.
372       timing.rise_constraint = _extract_lut(itr, end);
373     }
374     else if(*itr == "fall_constraint") {             // FF fall constraint.
375       timing.fall_constraint = _extract_lut(itr, end);
376     }
377     else if(*itr == "timing_sense") {               // Read the timing sense.
378 
379       OT_LOGF_IF(++itr == end, "syntex error in timing_sense");
380 
381       if(*itr == "negative_unate") {
382         timing.sense = TimingSense::NEGATIVE_UNATE;       // Negative unate.
383       }
384       else if(*itr == "positive_unate") {            // Positive unate.
385         timing.sense = TimingSense::POSITIVE_UNATE;
386       }
387       else if(*itr == "non_unate") {                 // Non unate.
388         timing.sense = TimingSense::NON_UNATE;
389       }
390       else {
391         OT_LOGF("unexpected timing sense ", *itr);
392       }
393     }
394     else if(*itr == "timing_type") {
395 
396       if(++itr == end) {
397         OT_LOGF("syntax error in timing_type");
398       }
399 
400       if(auto titr = timing_types.find(*itr); titr != timing_types.end()) {
401         timing.type = titr->second;
402       }
403       else {
404         OT_LOGW("unexpected timing type ", *itr);
405       }
406     }
407     else if (*itr == "related_pin") {
408 
409       if(++itr == end) {
410         OT_LOGF("syntax error in related_pin");
411       }
412 
413       timing.related_pin = *itr;
414     }
415     else if(*itr == "}") {
416       stack--;
417     }
418     else if(*itr == "{") {
419       stack++;
420     }
421     else {
422     }
423   }
424 
425   if(stack != 0 || *itr != "}") {
426     OT_LOGF("can't find group brace '}' in timing");
427   }
428 
429   return timing;
430 }
431 
432 // Functoin: _extract_cellpin
_extract_cellpin(token_iterator & itr,const token_iterator end)433 Cellpin Celllib::_extract_cellpin(token_iterator& itr, const token_iterator end) {
434 
435   Cellpin cellpin;
436 
437   if(itr=on_next_parentheses(
438     itr,
439     end,
440     [&] (auto& name) mutable { cellpin.name = name; }); itr == end) {
441     OT_LOGF("can't find cellpin name");
442   }
443 
444   // Extract the lut template group
445   if(itr = std::find(itr, end, "{"); itr == end) {
446     OT_LOGF("can't find group brace '{' in cellpin ", cellpin.name);
447   }
448 
449   //std::cout << "  -->" << cellpin.name << std::endl;
450 
451   int stack = 1;
452 
453   while(stack && ++itr != end) {
454 
455     if(*itr == "direction") {
456 
457       if(++itr == end) {
458         OT_LOGF("can't get the direction in cellpin ", cellpin.name);
459       }
460 
461       if(auto ditr = cellpin_directions.find(*itr); ditr != cellpin_directions.end()) {
462         cellpin.direction = ditr->second;
463       }
464       else {
465         OT_LOGW("unexpected cellpin direction ", *itr);
466       }
467     }
468     else if(*itr == "capacitance") {
469       OT_LOGF_IF(++itr == end, "can't get the capacitance in cellpin ", cellpin.name);
470       cellpin.capacitance = std::strtof(itr->data(), nullptr);
471     }
472     else if(*itr == "max_capacitance") {
473       OT_LOGF_IF(++itr == end, "can't get the max_capacitance in cellpin ", cellpin.name);
474       cellpin.max_capacitance = std::strtof(itr->data(), nullptr);
475     }
476     else if(*itr == "min_capacitance") {
477       OT_LOGF_IF(++itr == end, "can't get the min_capacitance in cellpin ", cellpin.name);
478       cellpin.min_capacitance = std::strtof(itr->data(), nullptr);
479     }
480     else if(*itr == "max_transition") {
481       OT_LOGF_IF(++itr == end, "can't get the max_transition in cellpin ", cellpin.name);
482       cellpin.max_transition = std::strtof(itr->data(), nullptr);
483     }
484     else if(*itr == "min_transition") {
485       OT_LOGF_IF(++itr == end, "can't get the min_transition in cellpin ", cellpin.name);
486       cellpin.min_transition = std::strtof(itr->data(), nullptr);
487     }
488     else if(*itr == "fall_capacitance") {
489       OT_LOGF_IF(++itr == end, "can't get fall_capacitance in cellpin ", cellpin.name);
490       cellpin.fall_capacitance = std::strtof(itr->data(), nullptr);
491     }
492     else if(*itr == "rise_capacitance") {
493       OT_LOGF_IF(++itr == end, "can't get rise_capacitance in cellpin ", cellpin.name);
494       cellpin.rise_capacitance = std::strtof(itr->data(), nullptr);
495     }
496     else if(*itr == "fanout_load") {
497       OT_LOGF_IF(++itr == end, "can't get fanout_load in cellpin ", cellpin.name);
498       cellpin.fanout_load = std::strtof(itr->data(), nullptr);
499     }
500     else if(*itr == "max_fanout") {
501       OT_LOGF_IF(++itr == end, "can't get max_fanout in cellpin ", cellpin.name);
502       cellpin.max_fanout = std::strtof(itr->data(), nullptr);
503     }
504     else if(*itr == "min_fanout") {
505       OT_LOGF_IF(++itr == end, "can't get min_fanout in cellpin ", cellpin.name);
506       cellpin.min_fanout = std::strtof(itr->data(), nullptr);
507     }
508     else if(*itr == "clock") {
509       OT_LOGF_IF(++itr == end, "can't get the clock status in cellpin ", cellpin.name);
510       cellpin.is_clock = (*itr == "true") ? true : false;
511     }
512     else if(*itr == "original_pin") {
513       OT_LOGF_IF(++itr == end, "can't get the original pin in cellpin ", cellpin.name);
514       cellpin.original_pin = *itr;
515     }
516     else if(*itr == "timing") {
517       cellpin.timings.push_back(_extract_timing(itr, end));
518     }
519     else if(*itr == "}") {
520       stack--;
521     }
522     else if(*itr == "{") {
523       stack++;
524     }
525     else {
526     }
527   }
528 
529   if(stack != 0 || *itr != "}") {
530     OT_LOGF("can't find group brace '}' in cellpin ", cellpin.name);
531   }
532 
533   return cellpin;
534 }
535 
536 // Function: _extract_cell
_extract_cell(token_iterator & itr,const token_iterator end)537 Cell Celllib::_extract_cell(token_iterator& itr, const token_iterator end) {
538 
539   Cell cell;
540 
541   if(itr=on_next_parentheses(
542     itr,
543     end,
544     [&] (auto& name) mutable { cell.name = name; }); itr==end) {
545     OT_LOGF("can't find cell name");
546   }
547 
548   // Extract the lut template group
549   if(itr = std::find(itr, end, "{"); itr == end) {
550     OT_LOGF("can't find group brace '{' in cell ", cell.name);
551   }
552 
553   int stack = 1;
554 
555   while(stack && ++itr != end) {
556 
557     if(*itr == "cell_leakage_power") {               // Read the leakage power.
558       OT_LOGF_IF(++itr == end, "can't get leakage power in cell ", cell.name);
559       cell.leakage_power = std::strtof(itr->data(), nullptr);
560     }
561     else if(*itr == "cell_footprint") {              // Read the footprint.
562       OT_LOGF_IF(++itr == end, "can't get footprint in cell ", cell.name);
563       cell.cell_footprint = *itr;
564     }
565     else if(*itr == "area") {                        // Read the area.
566       OT_LOGF_IF(++itr == end, "can't get area in cell ", cell.name);
567       cell.area = std::strtof(itr->data(), nullptr);
568     }
569     else if(*itr == "pin") {                         // Read the cell pin group.
570       auto pin = _extract_cellpin(itr, end);
571       cell.cellpins[pin.name] = std::move(pin);
572     }
573     else if(*itr == "}") {
574       stack--;
575     }
576     else if(*itr == "{") {
577       stack++;
578     }
579     else {
580       //OT_LOGW("unexpected token ", *itr);
581     }
582   }
583 
584   if(stack != 0 || *itr != "}") {
585     OT_LOGF("can't find group brace '}' in cell ", cell.name);
586   }
587 
588   return cell;
589 }
590 
591 // Procedure: read
read(const std::filesystem::path & path)592 void Celllib::read(const std::filesystem::path& path) {
593 
594   std::ifstream ifs(path, std::ios::ate);
595 
596   // return on failure
597   OT_LOGF_IF(!ifs, "failed to open celllib ", path);
598 
599   size_t fsize = ifs.tellg();
600   ifs.seekg(0, std::ios::beg);
601   std::vector<char> buffer(fsize + 1);
602   ifs.read(buffer.data(), fsize);
603   buffer[fsize] = 0;
604 
605   // get tokens
606   std::vector<std::string_view> tokens;
607   tokens.reserve(buffer.size() / sizeof(std::string));
608 
609   _uncomment(buffer);
610   _tokenize (buffer, tokens);
611 
612   // Set up the iterator
613   auto itr = tokens.begin();
614   auto end = tokens.end();
615 
616   // Read the library name.
617   if(itr = std::find(itr, end, "library"); itr == end) {
618     OT_LOGF("can't find keyword ", std::quoted("library"));
619   }
620 
621   if(itr = on_next_parentheses(
622     itr,
623     end,
624     [&] (auto& str) mutable { name = str; }); itr == end) {
625     OT_LOGF("can't find library name");
626   }
627 
628   // Extract the library group
629   if(itr = std::find(itr, tokens.end(), "{"); itr == tokens.end()) {
630     OT_LOGF("can't find library group symbol '{'");
631   }
632 
633   int stack = 1;
634 
635   while(stack && ++itr != end) {
636 
637     if(*itr == "lu_table_template") {
638       auto lut = _extract_lut_template(itr, end);
639       lut_templates[lut.name] = lut;
640     }
641     else if(*itr == "delay_model") {
642       OT_LOGF_IF(++itr == end, "syntax error in delay_model");
643       if(auto ditr = delay_models.find(*itr); ditr != delay_models.end()) {
644         delay_model = ditr->second;
645       }
646       else {
647         OT_LOGW("unexpected delay model ", *itr);
648       }
649     }
650     else if(*itr == "default_cell_leakage_power") {
651       OT_LOGF_IF(++itr == end, "syntax error in default_cell_leakage_power");
652       default_cell_leakage_power = std::strtof(itr->data(), nullptr);
653     }
654     else if(*itr == "default_inout_pin_cap") {
655       OT_LOGF_IF(++itr == end, "syntax error in default_inout_pin_cap");
656       default_inout_pin_cap = std::strtof(itr->data(), nullptr);
657     }
658     else if(*itr == "default_input_pin_cap") {
659       OT_LOGF_IF(++itr == end, "syntax error in default_input_pin_cap");
660       default_input_pin_cap = std::strtof(itr->data(), nullptr);
661     }
662     else if(*itr == "default_output_pin_cap") {
663       OT_LOGF_IF(++itr == end, "syntax error in default_output_pin_cap");
664       default_output_pin_cap = std::strtof(itr->data(), nullptr);
665     }
666     else if(*itr == "default_fanout_load") {
667       OT_LOGF_IF(++itr == end, "syntax error in default_fanout_load");
668       default_fanout_load = std::strtof(itr->data(), nullptr);
669     }
670     else if(*itr == "default_max_fanout") {
671       OT_LOGF_IF(++itr == end, "syntax error in default_max_fanout");
672       default_max_fanout = std::strtof(itr->data(), nullptr);
673     }
674     else if(*itr == "default_max_transition") {
675       OT_LOGF_IF(++itr == end, "syntax error in default_max_transition");
676       default_max_transition = std::strtof(itr->data(), nullptr);
677     }
678     // TODO: Unit field.
679     else if(*itr == "time_unit") {
680       OT_LOGF_IF(++itr == end, "time_unit syntax error");
681       time_unit = make_time_unit(*itr);
682     }
683     else if(*itr == "voltage_unit") {
684       OT_LOGF_IF(++itr == end, "voltage_unit syntax error");
685       voltage_unit = make_voltage_unit(*itr);
686     }
687     else if(*itr == "current_unit") {
688       OT_LOGF_IF(++itr == end, "current_unit syntax error");
689       current_unit = make_current_unit(*itr);
690     }
691     else if(*itr == "pulling_resistance_unit") {
692       OT_LOGF_IF(++itr == end, "pulling_resistance_unit syntax error");
693       resistance_unit = make_resistance_unit(*itr);
694     }
695     else if(*itr == "leakage_power_unit") {
696       OT_LOGF_IF(++itr == end, "leakage_power_unit syntax error");
697       power_unit = make_power_unit(*itr);
698     }
699     else if(*itr == "capacitive_load_unit") {
700       std::string unit;
701       if(itr = on_next_parentheses(
702         itr,
703         end,
704         [&] (auto& str) mutable { unit += str; }); itr == end) {
705         OT_LOGF("capacitive_load_unit syntax error");
706       }
707       capacitance_unit = make_capacitance_unit(unit);
708     }
709     else if(*itr == "cell") {
710       auto cell = _extract_cell(itr, end);
711       cells[cell.name] = std::move(cell);
712     }
713     else if(*itr == "}") {
714       stack--;
715     }
716     else if(*itr == "{") {
717       stack++;
718     }
719     else {
720     }
721   }
722 
723   if(stack != 0 || *itr != "}") {
724     OT_LOGF("can't find library group brace '}'");
725   }
726 
727   _apply_default_values();
728 }
729 
730 // Procedure: _apply_default_values
_apply_default_values()731 void Celllib::_apply_default_values() {
732 
733   for(auto& ckvp : cells) {
734 
735     auto& cell = ckvp.second;
736 
737     // apply the default leakage power
738     if(!cell.leakage_power) {
739       cell.leakage_power = default_cell_leakage_power;
740     }
741 
742     for(auto& pkvp : cell.cellpins) {
743 
744       auto& cpin = pkvp.second;
745 
746       // direction-specific default values
747       if(!cpin.direction) {
748         OT_LOGW("cellpin ", cell.name, '/', cpin.name, " has no direction defined");
749         continue;
750       }
751 
752       switch(*cpin.direction) {
753 
754         case CellpinDirection::INPUT:
755           if(!cpin.capacitance) {
756             cpin.capacitance = default_input_pin_cap;
757           }
758 
759           if(!cpin.fanout_load) {
760             cpin.fanout_load = default_fanout_load;
761           }
762         break;
763 
764         case CellpinDirection::OUTPUT:
765           if(!cpin.capacitance) {
766             cpin.capacitance = default_output_pin_cap;
767           }
768 
769           if(!cpin.max_fanout) {
770             cpin.max_fanout = default_max_fanout;
771           }
772 
773           if(!cpin.max_transition) {
774             cpin.max_transition = default_max_transition;
775           }
776         break;
777 
778         case CellpinDirection::INOUT:
779           if(!cpin.capacitance) {
780             cpin.capacitance = default_inout_pin_cap;
781           }
782         break;
783 
784         case CellpinDirection::INTERNAL:
785         break;
786       }
787 
788     }
789   }
790 }
791 
792 // Procedure: scale_time
793 // Convert the numerics to the new unit
scale_time(float s)794 void Celllib::scale_time(float s) {
795 
796   if(default_max_transition) {
797     default_max_transition = *default_max_transition * s;
798   }
799 
800   for(auto& c : cells) {
801     c.second.scale_time(s);
802   }
803 }
804 
805 // Procedure: scale_capacitance
scale_capacitance(float s)806 void Celllib::scale_capacitance(float s) {
807 
808   if(default_inout_pin_cap) {
809     default_inout_pin_cap = *default_inout_pin_cap * s;
810   }
811 
812   if(default_input_pin_cap) {
813     default_input_pin_cap = *default_input_pin_cap * s;
814   }
815 
816   if(default_output_pin_cap) {
817     default_output_pin_cap = *default_output_pin_cap * s;
818   }
819 
820   for(auto& c : cells) {
821     c.second.scale_capacitance(s);
822   }
823 }
824 
825 // Procedure: scale_voltage
scale_voltage(float s)826 void Celllib::scale_voltage(float s) {
827   // TODO
828 }
829 
830 // Procedure: scale_current
scale_current(float s)831 void Celllib::scale_current(float s) {
832 
833   // TODO
834 }
835 
836 // Procedure: scale_resistance
scale_resistance(float s)837 void Celllib::scale_resistance(float s) {
838   // TODO
839 }
840 
841 // Procedure: scale_power
scale_power(float s)842 void Celllib::scale_power(float s) {
843   // TODO
844 }
845 
846 // Operator: <<
operator <<(std::ostream & os,const Celllib & c)847 std::ostream& operator << (std::ostream& os, const Celllib& c) {
848 
849   // Write the comment.
850   os << "/* Generated by OpenTimer " << " */\n";
851 
852   // Write library name.
853   os << "library (\"" << c.name << "\") {\n\n";
854 
855   // Delay modeA
856   if(c.delay_model) {
857     os << "delay_model : " << to_string(*(c.delay_model)) << ";\n";
858   }
859 
860   // Library units
861   if(auto u = c.time_unit; u) {
862     os << "time_unit : \"" << u->value() << "s\"\n";
863   }
864 
865   if(auto u = c.voltage_unit; u) {
866     os << "voltage_unit : \"" << u->value() << "V\"\n";
867   }
868 
869   if(auto u = c.current_unit; u) {
870     os << "current_unit : \"" << u->value() << "A\"\n";
871   }
872 
873   if(auto u = c.resistance_unit; u) {
874     os << "pulling_resistance_unit : \"" << u->value() << "ohm\"\n";
875   }
876 
877   if(auto u = c.power_unit; u) {
878     os << "leakage_power_unit : \"" << u->value() << "W\"\n";
879   }
880 
881   if(auto u = c.capacitance_unit; u) {
882     os << "capacitive_load_unit (" << u->value() << ",F)\"\n";
883   }
884 
885   // default values
886   if(c.default_cell_leakage_power) {
887     os << *c.default_cell_leakage_power << '\n';
888   }
889 
890   if(c.default_inout_pin_cap) {
891     os << *c.default_inout_pin_cap << '\n';
892   }
893 
894   if(c.default_input_pin_cap) {
895     os << *c.default_input_pin_cap << '\n';
896   }
897 
898   if(c.default_output_pin_cap) {
899     os << *c.default_fanout_load << '\n';
900   }
901 
902   if(c.default_max_fanout) {
903     os << *c.default_max_fanout << '\n';
904   }
905 
906   if(c.default_max_transition) {
907     os << *c.default_max_transition << '\n';
908   }
909 
910   // Write the lut templates
911   for(const auto& kvp : c.lut_templates) {
912     os << kvp.second << '\n';
913   }
914 
915   // Write all cells.
916   for(const auto& kvp : c.cells) {
917     os << kvp.second << '\n';
918   }
919 
920   // Write library ending group symbol.
921   os << "}\n";
922 
923   return os;
924 }
925 
926 
927 
928 };  // namespace ot. ------------------------------------------------------------------------------
929 
930 
931 
932 
933 
934