1 #include <ot/liberty/lut.hpp>
2 
3 namespace ot {
4 
5 // Function: is_time_lut_var
is_time_lut_var(LutVar v)6 bool is_time_lut_var(LutVar v) {
7   switch(v) {
8     case LutVar::INPUT_NET_TRANSITION:
9     case LutVar::CONSTRAINED_PIN_TRANSITION:
10     case LutVar::RELATED_PIN_TRANSITION:
11     case LutVar::INPUT_TRANSITION_TIME:
12       return true;
13     break;
14 
15     default:
16       return false;
17     break;
18   }
19 }
20 
21 // Function: is_capacitance_lut_var
is_capacitance_lut_var(LutVar v)22 bool is_capacitance_lut_var(LutVar v) {
23   switch(v) {
24     case LutVar::TOTAL_OUTPUT_NET_CAPACITANCE:
25       return true;
26     break;
27 
28     default:
29       return false;
30     break;
31   }
32 }
33 
34 // Function: to_string
to_string(LutVar v)35 std::string to_string(LutVar v) {
36 
37   switch(v) {
38     case LutVar::TOTAL_OUTPUT_NET_CAPACITANCE:
39       return "total_output_net_capacitance";
40     break;
41 
42     case LutVar::INPUT_NET_TRANSITION:
43       return "input_net_transition";
44     break;
45 
46     case LutVar::CONSTRAINED_PIN_TRANSITION:
47       return "constrained_pin_transition";
48     break;
49 
50     case LutVar::RELATED_PIN_TRANSITION:
51       return "related_pin_transition";
52     break;
53 
54     case LutVar::INPUT_TRANSITION_TIME:
55       return "input_transition_time";
56     break;
57 
58     default:
59       return "undefined";
60     break;
61   }
62 }
63 
64 // ------------------------------------------------------------------------------------------------
65 
66 // Operator: <<
operator <<(std::ostream & os,const LutTemplate & lut)67 std::ostream& operator << (std::ostream& os, const LutTemplate& lut) {
68 
69   // Write the lut template name.
70   os << "lu_table_template (" << lut.name << ") {\n";
71 
72   // Write variables.
73   if(lut.variable1) {
74     os << "  variable_1: " << to_string(*(lut.variable1)) << ";\n";
75   }
76 
77   if(lut.variable2) {
78     os << "  variable_2: " << to_string(*(lut.variable2)) << ";\n";
79   }
80 
81   // Write indices.
82   if(!lut.indices1.empty()) {
83     os << "  index_1 (\"";
84     for(size_t i=0; i<lut.indices1.size(); i++) {
85       if(i) {
86         os << ", ";
87       }
88       os << lut.indices1[i];
89     }
90     os << "\");\n";
91   }
92 
93   if(!lut.indices2.empty()) {
94     os << "  index_2 (\"";
95     for(size_t i=0; i<lut.indices2.size(); i++) {
96       if(i) {
97         os << ", ";
98       }
99       os << lut.indices2[i];
100     }
101     os << "\");\n";
102   }
103 
104   // Write the lut template ending group symbol.
105   os <<"}\n";
106 
107   return os;
108 }
109 
110 // ------------------------------------------------------------------------------------------------
111 
112 // Function: scale_time
scale_time(float s)113 void Lut::scale_time(float s) {
114 
115   if(lut_template) {
116     if(auto v1 = lut_template->variable1; v1 && is_time_lut_var(*v1)) {
117       for(auto& v : indices1) {
118         v *= s;
119       }
120     }
121     if(auto v2 = lut_template->variable2; v2 && is_time_lut_var(*v2)) {
122       for(auto& v : indices2) {
123         v *= s;
124       }
125     }
126   }
127 
128   // scale the table
129   for(auto& v : table) {
130     v *= s;
131   }
132 }
133 
134 // Function: scale_capacitance
scale_capacitance(float s)135 void Lut::scale_capacitance(float s) {
136 
137   if(lut_template) {
138     if(auto v1 = lut_template->variable1; v1 && is_capacitance_lut_var(*v1)) {
139       for(auto& v : indices1) {
140         v *= s;
141       }
142     }
143     if(auto v2 = lut_template->variable2; v2 && is_capacitance_lut_var(*v2)) {
144       for(auto& v : indices2) {
145         v *= s;
146       }
147     }
148   }
149 }
150 
151 // Function: is_scalar
is_scalar() const152 bool Lut::is_scalar() const {
153   return indices1.size() == 1 && indices2.size() == 1;
154 }
155 
156 // Function: empty
empty() const157 inline bool Lut::empty() const {
158   return indices1.size() == 0 && indices2.size() == 0;
159 }
160 
161 // Function: lut
162 // Performs the linear inter/extra polation between a segment (x1, x2) which satisfies the
163 // function f(x1) = y1 and f(x2) = y2. There are five cases: 1) x < x1, 2) x = x1,
164 // 3) x1 < x < x2, 4) x = x2, and 5) x > x2. For cases 1) and 5), extra-polation is needed.
165 // Cases 2) and 4) are boundary cases. Case 3) requires the inter-polation.
operator ()(float val1,float val2) const166 float Lut::operator()(float val1, float val2) const {
167 
168   if(indices1.size() < 1 || indices2.size() < 1) {
169     OT_LOGF("invalid lut indices size");
170   }
171 
172   // Interpolation
173   constexpr auto interpolate = [] (float x, float x1, float x2, float y1, float y2) {
174 
175     assert(x1 < x2);
176 
177     if(x >= std::numeric_limits<float>::max() || x <= std::numeric_limits<float>::lowest()) {
178       return x;
179     }
180 
181     float slope = (y2 - y1) / (x2 - x1);
182 
183     if(x < x1) return y1 - (x1 - x) * slope;                  // Extrapolation.
184     else if(x > x2)  return y2 + (x - x2) * slope;            // Extrapolation.
185     else if(x == x1) return y1;                               // Boundary case.
186     else if(x == x2) return y2;                               // Boundary case.
187     else return y1 + (x - x1) * slope;                        // Interpolation.
188   };
189 
190   // Case 1: scalar
191   if(is_scalar()) return table[0];
192 
193   int idx1[2], idx2[2];
194 
195   idx1[1] = std::lower_bound(indices1.begin(), indices1.end(), val1) - indices1.begin();
196   idx2[1] = std::lower_bound(indices2.begin(), indices2.end(), val2) - indices2.begin();
197 
198   // Case 2: linear inter/extra polation.
199   idx1[1] = std::max(1, std::min(idx1[1], (int)(indices1.size() - 1)));
200   idx2[1] = std::max(1, std::min(idx2[1], (int)(indices2.size() - 1)));
201   idx1[0] = idx1[1] - 1;
202   idx2[0] = idx2[1] - 1;
203 
204   //printf("Perform the linear interpolation on val1=%.5f (%d %d) and val2=%.5f (%d %d)\n",
205   //        val1, idx1[0], idx1[1], val2, idx2[0], idx2[1]);
206 
207   // 1xN array (N>=2)
208   if(indices1.size() == 1) {
209     return interpolate(
210       val2,
211       indices2[idx2[0]],
212       indices2[idx2[1]],
213       table[idx2[0]],
214       table[idx2[1]]
215     );
216   }
217   // Nx1 array (N>=2)
218   else if(indices2.size() == 1) {
219     return interpolate(
220       val1,
221       indices1[idx1[0]],
222       indices1[idx1[1]],
223       table[idx1[0]*indices2.size()],
224       table[idx1[1]*indices2.size()]
225     );
226   }
227   // NxN array (N>=2)
228   else {
229     float numeric[2];
230 
231     numeric[0] = interpolate(
232       val1,
233       indices1[idx1[0]],
234       indices1[idx1[1]],
235       table[idx1[0]*indices2.size() + idx2[0]],
236       table[idx1[1]*indices2.size() + idx2[0]]
237     );
238 
239     numeric[1] = interpolate(
240       val1,
241       indices1[idx1[0]],
242       indices1[idx1[1]],
243       table[idx1[0]*indices2.size() + idx2[1]],
244       table[idx1[1]*indices2.size() + idx2[1]]
245     );
246 
247     return interpolate(val2, indices2[idx2[0]], indices2[idx2[1]], numeric[0], numeric[1]);
248   }
249 }
250 
251 // operator
operator <<(std::ostream & os,const Lut & lut)252 std::ostream& operator << (std::ostream& os, const Lut& lut) {
253 
254   // Write the indices1.
255   if(!lut.indices1.empty()) {
256     os << "        index_1 (\"";
257     for(size_t i=0; i<lut.indices1.size(); ++i) {
258       if(i) {
259         os << ", ";
260       }
261       os << lut.indices1[i];
262     }
263     os << "\");\n";
264   }
265 
266   // Write the indices2.
267   if(!lut.indices2.empty()) {
268     os << "        index_2 (\"";
269     for(size_t i=0; i<lut.indices2.size(); ++i) {
270       if(i) {
271         os << ", ";
272       }
273       os << lut.indices2[i];
274     }
275     os << "\");\n";
276   }
277 
278   // Write the values.
279   if(!lut.table.empty()) {
280     os << "        values (\n";
281     for(size_t i=0; i<lut.indices1.size(); ++i) {
282       os << "          \"";
283       for(size_t j=0; j<lut.indices2.size(); ++j) {
284         if(j) {
285           os << ", ";
286         }
287         os << lut.table[i*lut.indices2.size()+j];
288       }
289       os << "\",\n";
290     }
291     os << "        );\n";
292   }
293 
294   return os;
295 }
296 
297 
298 
299 
300 };  // end of namespace ot ------------------------------------------------------------------------
301