1/* Copyright (c) 2012 Massachusetts Institute of Technology
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining a copy
4 * of this software and associated documentation files (the "Software"), to deal
5 * in the Software without restriction, including without limitation the rights
6 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 * copies of the Software, and to permit persons to whom the Software is
8 * furnished to do so, subject to the following conditions:
9 *
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 * THE SOFTWARE.
20 */
21
22#include "tech/TechModel.h"
23
24#include <cmath>
25
26#include "model/std_cells/StdCellLib.h"
27
28namespace DSENT
29{
30    TechModel::TechModel()
31        : m_std_cell_lib_(NULL), m_available_wire_layers_(NULL)
32    {}
33
34    TechModel::~TechModel()
35    {}
36
37    const String& TechModel::get(const String &key_) const
38    {
39        return params.at(key_);
40    }
41
42    void TechModel::setStdCellLib(const StdCellLib* std_cell_lib_)
43    {
44        m_std_cell_lib_ = std_cell_lib_;
45        return;
46    }
47
48    const StdCellLib* TechModel::getStdCellLib() const
49    {
50        return m_std_cell_lib_;
51    }
52
53    TechModel* TechModel::clone() const
54    {
55        return new TechModel(*this);
56    }
57
58    void TechModel::readFile(const String& filename_)
59    {
60        // Read the main technology file
61        LibUtil::readFile(filename_, params);
62
63        // Search for "INCLUDE" to include more technology files
64        for (const auto &it : params)
65        {
66            const String& key = it.first;
67            if(key.compare(0, 8, "INCLUDE_") == 0)
68            {
69                const String& include_filename = it.second;
70                LibUtil::readFile(include_filename, params);
71            }
72        }
73
74        // Set the available wire layers
75        const vector<String>& available_wire_layer_vector = get("Wire->AvailableLayers").split("[,]");
76        m_available_wire_layers_ = new std::set<String>;
77        for(unsigned int i = 0; i < available_wire_layer_vector.size(); ++i)
78        {
79            m_available_wire_layers_->insert(available_wire_layer_vector[i]);
80        }
81    }
82
83    //-------------------------------------------------------------------------
84    // Transistor Related Functions
85    //-------------------------------------------------------------------------
86    //Returns the leakage current of NMOS transistors, given the transistor stakcing, transistor widths, and input combination
87    double TechModel::calculateNmosLeakageCurrent(unsigned int num_stacks_, double uni_stacked_mos_width_, unsigned int input_vector_) const
88    {
89        vector<double> stacked_mos_widths_(num_stacks_, uni_stacked_mos_width_);
90        return calculateNmosLeakageCurrent(num_stacks_, stacked_mos_widths_, input_vector_);
91    }
92
93    //Returns the leakage current of NMOS transistors, given the transistor stakcing, transistor widths, and input combination
94    double TechModel::calculateNmosLeakageCurrent(unsigned int num_stacks_, const vector<double>& stacked_mos_widths_, unsigned int input_vector_) const
95    {
96        // Get technology parameters
97        double vdd = get("Vdd");
98        double temp = get("Temperature");
99        double char_temp = get("Nmos->CharacterizedTemperature");
100        double min_off_current = get("Nmos->MinOffCurrent");
101        double off_current = get("Nmos->OffCurrent");
102        double subthreshold_swing = get("Nmos->SubthresholdSwing");
103        double dibl = get("Nmos->DIBL");
104        double temp_swing = get("Nmos->SubthresholdTempSwing");
105
106        // Map dibl to a swing value for easier calculation
107        double dibl_swing = subthreshold_swing / dibl;
108
109        //Calculate the leakage current factor
110        double leakage_current_factor = calculateLeakageCurrentFactor(num_stacks_, stacked_mos_widths_, input_vector_, vdd, subthreshold_swing, dibl_swing);
111
112        // Calcualte actual leakage current at characterized temperature
113        double leakage_current_char_tmp = stacked_mos_widths_[0] * off_current * std::pow(10.0, leakage_current_factor);
114        leakage_current_char_tmp = std::max(min_off_current, leakage_current_char_tmp);
115
116        // Calculate actual leakage current at temp
117        double leakage_current = leakage_current_char_tmp * std::pow(10.0, (temp - char_temp) / temp_swing);
118
119        return leakage_current;
120    }
121
122    double TechModel::calculatePmosLeakageCurrent(unsigned int num_stacks_, double uni_stacked_mos_width_, unsigned int input_vector_) const
123    {
124        vector<double> stacked_mos_widths_(num_stacks_, uni_stacked_mos_width_);
125        return calculatePmosLeakageCurrent(num_stacks_, stacked_mos_widths_, input_vector_);
126    }
127
128    //Returns the leakage current of PMOS transistors, given the transistor stakcing, transistor widths, and input combination
129    double TechModel::calculatePmosLeakageCurrent(unsigned int num_stacks_, const vector<double>& stacked_mos_widths_, unsigned int input_vector_) const
130    {
131        // Get technology parameters
132        double vdd = get("Vdd");
133        double temp = get("Temperature");
134        double char_temp = get("Pmos->CharacterizedTemperature");
135        double min_off_current = get("Pmos->MinOffCurrent");
136        double off_current = get("Pmos->OffCurrent");
137        double dibl = get("Pmos->DIBL");
138        double subthreshold_swing = get("Pmos->SubthresholdSwing");
139        double temp_swing = get("Nmos->SubthresholdTempSwing");
140
141        // Map dibl to a swing value for easier calculation
142        double dibl_swing = subthreshold_swing / dibl;
143
144        //Calculate the leakage current factor
145        double leakage_current_factor = calculateLeakageCurrentFactor(num_stacks_, stacked_mos_widths_, input_vector_, vdd, subthreshold_swing, dibl_swing);
146
147        // Calcualte actual leakage current at characterized temperature
148        double leakage_current_char_tmp = stacked_mos_widths_[0] * off_current * std::pow(10.0, leakage_current_factor);
149        leakage_current_char_tmp = std::max(min_off_current, leakage_current_char_tmp);
150
151        // Calculate actual leakage current at temp
152        double leakage_current = leakage_current_char_tmp * std::pow(10.0, (temp - char_temp) / temp_swing);
153
154        return leakage_current;
155    }
156
157    //Returns the leakage current, given the transistor stakcing, transistor widths, input combination,
158    //and technology information (vdd, subthreshold swing, subthreshold dibl swing)
159    double TechModel::calculateLeakageCurrentFactor(unsigned int num_stacks_, const vector<double>& stacked_mos_widths_, unsigned int input_vector_, double vdd_, double subthreshold_swing_, double dibl_swing_) const
160    {
161        // check everything is valid
162        ASSERT(num_stacks_ >= 1, "[Error] Number of stacks must be >= 1!");
163        ASSERT(stacked_mos_widths_.size() == num_stacks_, "[Error] Mismatch in number of stacks and the widths specified!");
164
165        //Use short name in this method
166        const double s1 = subthreshold_swing_;
167        const double s2 = dibl_swing_;
168
169        // Decode input combinations from input_vector_
170        std::vector<double> vs(num_stacks_, 0.0);
171        for(int i = 0; i < (int)num_stacks_; ++i)
172        {
173            double current_input = (double(input_vector_ & 0x1))*vdd_;
174            vs[i] = (current_input);
175            input_vector_ >>= 1;
176        }
177        // If the widths pointer is NULL, width is set to 1 by default
178        vector<double> ws = stacked_mos_widths_;
179
180        //Solve voltages at internal nodes of stacked transistors
181        // v[0] = 0
182        // v[num_stacks_] = vdd_
183        // v[i] = (1.0/(2*s1 + s2))*((s1 + s2)*v[i - 1] + s1*v[i + 1]
184        //                 + s2*(vs[i + 1] - vs[i]) + s1*s2*log10(ws[i + 1]/ws[i]))
185        //Use tri-matrix solver to solve the above linear system
186
187        double A = -(s1 + s2);
188        double B = 2*s1 + s2;
189        double C = -s1;
190        std::vector<double> a(num_stacks_ - 1, 0);
191        std::vector<double> b(num_stacks_ - 1, 0);
192        std::vector<double> c(num_stacks_ - 1, 0);
193        std::vector<double> d(num_stacks_ - 1, 0);
194        std::vector<double> v(num_stacks_ + 1, 0);
195        unsigned int eff_num_stacks = num_stacks_;
196        bool is_found_valid_v = false;
197        do
198        {
199            //Set boundary condition
200            v[0] = 0;
201            v[eff_num_stacks] = vdd_;
202
203            //If the effective number of stacks is 1, no matrix needs to be solved
204            if(eff_num_stacks == 1)
205            {
206                break;
207            }
208
209            //----------------------------------------------------------------------
210            //Setup the tri-matrix
211            //----------------------------------------------------------------------
212            for(int i = 0; i < (int)eff_num_stacks-2; ++i)
213            {
214                a[i + 1] = A;
215                c[i] = C;
216            }
217            for(int i = 0; i < (int)eff_num_stacks-1; ++i)
218            {
219                b[i] = B;
220                d[i] = s2*(vs[i + 1] - vs[i]) + s1*s2*std::log10(ws[i + 1]/ws[i]);
221                if(i == ((int)eff_num_stacks - 2))
222                {
223                    d[i] -= C*vdd_;
224                }
225            }
226            //----------------------------------------------------------------------
227
228            //----------------------------------------------------------------------
229            //Solve the tri-matrix
230            //----------------------------------------------------------------------
231            for(int i = 1; i < (int)eff_num_stacks-1; ++i)
232            {
233                double m = a[i]/b[i - 1];
234                b[i] -= m*c[i - 1];
235                d[i] -= m*d[i - 1];
236            }
237
238            v[eff_num_stacks - 1] = d[eff_num_stacks - 2]/b[eff_num_stacks - 2];
239            for(int i = eff_num_stacks - 3; i >= 0; --i)
240            {
241                v[i + 1] = (d[i] - c[i]*v[i + 2])/b[i];
242            }
243            //----------------------------------------------------------------------
244
245            //Check if the internal voltages are in increasing order
246            is_found_valid_v = true;
247            for(int i = 1; i <= (int)eff_num_stacks; ++i)
248            {
249                //If the ith internal voltage is not in increasing order
250                //(i-1)th transistor is in triode region
251                //Remove the transistors in triode region as it does not exist
252                if(v[i] < v[i - 1])
253                {
254                    is_found_valid_v = false;
255                    eff_num_stacks--;
256                    vs.erase(vs.begin() + i - 1);
257                    ws.erase(ws.begin() + i - 1);
258                    break;
259                }
260            }
261        } while(!is_found_valid_v);
262
263        //Calculate the leakage current of the bottom transistor (first not in triode region)
264        double vgs = vs[0] - v[0];
265        double vds = v[1] - v[0];
266        double leakage_current_factor = vgs/s1 + (vds - vdd_)/s2;
267        //TODO - Check if the leakage current calculate for other transistors is identical
268
269        return leakage_current_factor;
270    }
271    //-------------------------------------------------------------------------
272
273    //-------------------------------------------------------------------------
274    // Wire Related Functions
275    //-------------------------------------------------------------------------
276    bool TechModel::isWireLayerExist(const String& layer_name_) const
277    {
278        std::set<String>::const_iterator it;
279        it = m_available_wire_layers_->find(layer_name_);
280        return (it != m_available_wire_layers_->end());
281    }
282
283    const std::set<String>* TechModel::getAvailableWireLayers() const
284    {
285        return m_available_wire_layers_;
286    }
287
288    double TechModel::calculateWireCapacitance(const String& layer_name_, double width_, double spacing_, double length_) const
289    {
290        // Get technology parameter
291        double min_width = get("Wire->" + layer_name_ + "->MinWidth").toDouble();
292        double min_spacing = get("Wire->" + layer_name_ + "->MinSpacing").toDouble();
293        double metal_thickness = get("Wire->" + layer_name_ + "->MetalThickness").toDouble();
294        double dielec_thickness = get("Wire->" + layer_name_ + "->DielectricThickness").toDouble();
295        double dielec_const = get("Wire->" + layer_name_ + "->DielectricConstant").toDouble();
296
297        ASSERT(width_ >= min_width, "[Error] Wire width must be >= " + (String) min_width + "!");
298        ASSERT(spacing_ >= min_spacing, "[Error] Wire spacing must be >= " + (String) min_spacing + "!");
299        ASSERT(length_ >= 0, "[Error] Wire length must be >= 0!");
300
301        double A, B, C;
302        // Calculate ground capacitance
303        A = width_ / dielec_thickness;
304        B = 2.04*std::pow((spacing_ / (spacing_ + 0.54 * dielec_thickness)), 1.77);
305        C = std::pow((metal_thickness / (metal_thickness + 4.53 * dielec_thickness)), 0.07);
306        double unit_gnd_cap = dielec_const * 8.85e-12 * (A + B * C);
307
308        A = 1.14 * (metal_thickness / spacing_) * std::exp(-4.0 * spacing_ / (spacing_ + 8.01 * dielec_thickness));
309        B = 2.37 * std::pow((width_ / (width_ + 0.31 * spacing_)), 0.28);
310        C = std::pow((dielec_thickness / (dielec_thickness + 8.96 * spacing_)), 0.76) *
311                std::exp(-2.0 * spacing_ / (spacing_ + 6.0 * dielec_thickness));
312        double unit_coupling_cap = dielec_const * 8.85e-12 * (A + B * C);
313
314        double total_cap = 2 * (unit_gnd_cap + unit_coupling_cap) * length_;
315        return total_cap;
316    }
317
318    double TechModel::calculateWireResistance(const String& layer_name_, double width_, double length_) const
319    {
320        // Get technology parameter
321        double min_width = get("Wire->" + layer_name_ + "->MinWidth");
322        //double barrier_thickness = get("Wire->" + layer_name_ + "->BarrierThickness");
323        double resistivity = get("Wire->" + layer_name_ + "->Resistivity");
324        double metal_thickness = get("Wire->" + layer_name_ + "->MetalThickness");
325
326        ASSERT(width_ >= min_width, "[Error] Wire width must be >= " + (String) min_width + "!");
327        ASSERT(length_ >= 0, "[Error] Wire length must be >= 0!");
328
329        // Calculate Rho
330        // double rho = 2.202e-8 + (1.030e-15 / (width_ - 2.0 * barrier_thickness));
331
332        double unit_res = resistivity / (width_ * metal_thickness);
333        //double unit_res = rho / ((width_ - 2.0 * barrier_thickness) * (metal_thickness - barrier_thickness));
334
335        double total_res = unit_res * length_;
336        return total_res;
337    }
338    //-------------------------------------------------------------------------
339
340    TechModel::TechModel(const TechModel& tech_model_)
341        : m_std_cell_lib_(tech_model_.m_std_cell_lib_),
342          params(tech_model_.params)
343    {}
344} // namespace DSENT
345