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 "model/std_cells/CellMacros.h"
23
24#include <cmath>
25#include <vector>
26
27#include "model/std_cells/StdCell.h"
28#include "model/timing_graph/ElectricalNet.h"
29#include "model/timing_graph/ElectricalDriver.h"
30#include "model/timing_graph/ElectricalLoad.h"
31
32namespace DSENT
33{
34    //-------------------------------------------------------------------------
35    // NOR2 Macro (TODO: Generalize to N-input macro once leakage calc is done)
36    //-------------------------------------------------------------------------
37    void CellMacros::addNor2(StdCell* cell_, const String& name_,
38        bool sizable_, bool a1_to_zn_path_, bool a2_to_zn_path_,
39        const String& a1_net_, const String& a2_net_, const String& zn_net_)
40    {
41        //Create electrical timing model for the nand
42        // Construct loads and drivers
43        cell_->createLoad(name_ + "_CgA1");
44        cell_->createLoad(name_ + "_CgA2");
45        cell_->createLoad(name_ + "_CdZN");
46        cell_->createDriver(name_ + "_RonZN", sizable_);
47
48        //Get references to loads and drivers
49        ElectricalLoad* gate_a1_load = cell_->getLoad(name_ + "_CgA1");
50        ElectricalLoad* gate_a2_load = cell_->getLoad(name_ + "_CgA2");
51        ElectricalLoad* drain_load = cell_->getLoad(name_ + "_CdZN");
52        ElectricalDriver* zn_drive = cell_->getDriver(name_ + "_RonZN");
53        ElectricalNet* a1_net = cell_->getNet(a1_net_);
54        ElectricalNet* a2_net = cell_->getNet(a2_net_);
55        ElectricalNet* zn_net = cell_->getNet(zn_net_);
56
57        //Add loads and drivers to the specified nets
58        a1_net->addDownstreamNode(gate_a1_load);
59        a2_net->addDownstreamNode(gate_a2_load);
60        zn_net->addDownstreamNode(drain_load);
61        if (a1_to_zn_path_) gate_a1_load->addDownstreamNode(zn_drive);
62        if (a2_to_zn_path_) gate_a2_load->addDownstreamNode(zn_drive);
63        zn_drive->addDownstreamNode(zn_net);
64
65        return;
66    }
67
68    void CellMacros::updateNor2(StdCell* cell_, const String& name_, double normalized_size_)
69    {
70        ASSERT(normalized_size_ >= 0.0, "[Error] " + cell_->getInstanceName() +
71            " -> Cannot update a macro with a negative normalized size!");
72
73        //Grab pointer to tech model
74        const TechModel* tech = cell_->getTechModel();
75
76        // Get technology parameters
77        double vdd = tech->get("Vdd");
78        double gate_cap = tech->get("Gate->CapPerWidth");
79        double drain_cap = tech->get("Drain->CapPerWidth");
80        double nmos_eff_res = tech->get("Nmos->EffResWidth");
81        double pmos_eff_res = tech->get("Pmos->EffResWidth");
82        double pmos_eff_res_stack_ratio = tech->get("Pmos->EffResStackRatio");
83        double gate_pitch_contacted = tech->get("Gate->PitchContacted");
84        double metal1_wire_min_width = tech->get("Wire->Metal1->MinWidth");
85
86        //Calculate number of folds and gate pitches needed
87        unsigned int folds = (normalized_size_ < 1.0) ? 1 : (unsigned int)ceil(normalized_size_);
88        cell_->getGenProperties()->set(name_ + "_GatePitches", 2 * folds);
89
90        //Calculate widths, making sure they are above the minimum width
91        double nmos_width = std::max(calculateNmosWidth(cell_, 1, 2, 1) * normalized_size_ / folds, (double) tech->get("Gate->MinWidth"));
92        double pmos_width = std::max(calculatePmosWidth(cell_, 1, 2, 2) * normalized_size_ / folds, (double) tech->get("Gate->MinWidth"));
93
94        //Calculate leakage power for each given input state
95        double leakage_power_00 = vdd * folds * 2 * tech->calculateNmosLeakageCurrent(1, nmos_width, 0x0);
96        double leakage_power_01 = vdd * folds * tech->calculatePmosLeakageCurrent(2, pmos_width, ~0x1);
97        double leakage_power_10 = vdd * folds * tech->calculatePmosLeakageCurrent(2, pmos_width, ~0x2);
98        double leakage_power_11 = vdd * folds * tech->calculatePmosLeakageCurrent(2, pmos_width, ~0x3);
99        cell_->getGenProperties()->set(name_ + "_LeakagePower_00", leakage_power_00);
100        cell_->getGenProperties()->set(name_ + "_LeakagePower_01", leakage_power_01);
101        cell_->getGenProperties()->set(name_ + "_LeakagePower_10", leakage_power_10);
102        cell_->getGenProperties()->set(name_ + "_LeakagePower_11", leakage_power_11);
103
104        //Calculate R_on and capacitances
105        double pmos_stack2_balance = 1.0 + pmos_eff_res_stack_ratio;
106        double c_g = (nmos_width + pmos_width) * gate_cap * folds;
107        double c_d = (2 * pmos_width + 2 * nmos_width) * drain_cap * folds;
108        double r_on = (nmos_eff_res / nmos_width + pmos_stack2_balance * pmos_eff_res / pmos_width) / (folds * 2.0);
109
110        // Estimate the wire cap and add them all at the output
111        double cell_height = cell_->getTotalHeight();
112        double wire_width = metal1_wire_min_width;
113        double wire_spacing = gate_pitch_contacted - metal1_wire_min_width;
114        double wire_length = 2.0 * folds * cell_height;
115        double wire_cap = tech->calculateWireCapacitance("Metal1", wire_width, wire_spacing, wire_length);
116
117        // Construct equivalent load and drive strength
118        cell_->getLoad(name_ + "_CgA1")->setLoadCap(c_g);
119        cell_->getLoad(name_ + "_CgA2")->setLoadCap(c_g);
120        cell_->getLoad(name_ + "_CdZN")->setLoadCap(c_d + wire_cap);
121        cell_->getDriver(name_ + "_RonZN")->setOutputRes(r_on);
122
123        // Calculate flip energies
124        double zn_flip_energy = 0.5 * (c_d + wire_cap) * vdd * vdd;
125        double a1_flip_energy = 0.5 * c_g * vdd * vdd;
126        double a2_flip_energy = 0.5 * c_g * vdd * vdd;
127        cell_->getGenProperties()->set(name_ + "_ZN_Flip", zn_flip_energy);
128        cell_->getGenProperties()->set(name_ + "_A1_Flip", a1_flip_energy);
129        cell_->getGenProperties()->set(name_ + "_A2_Flip", a2_flip_energy);
130    }
131    //-------------------------------------------------------------------------
132
133    //-------------------------------------------------------------------------
134    // NAND2 Macro (TODO: Generalize to N-input macro once leakage calc is done)
135    //-------------------------------------------------------------------------
136    //Adds a NAND2 to the standard cell, normalized to some size
137    void CellMacros::addNand2(StdCell* cell_, const String& name_,
138        bool sizable_, bool a1_to_zn_path_, bool a2_to_zn_path_,
139        const String& a1_net_, const String& a2_net_, const String& zn_net_)
140    {
141        //Create electrical timing model for the nor
142        // Construct loads and drivers
143        cell_->createLoad(name_ + "_CgA1");
144        cell_->createLoad(name_ + "_CgA2");
145        cell_->createLoad(name_ + "_CdZN");
146        cell_->createDriver(name_ + "_RonZN", sizable_);
147
148        //Get references to loads and drivers
149        ElectricalLoad* gate_a1_load = cell_->getLoad(name_ + "_CgA1");
150        ElectricalLoad* gate_a2_load = cell_->getLoad(name_ + "_CgA2");
151        ElectricalLoad* drain_load = cell_->getLoad(name_ + "_CdZN");
152        ElectricalDriver* zn_drive = cell_->getDriver(name_ + "_RonZN");
153        ElectricalNet* a1_net = cell_->getNet(a1_net_);
154        ElectricalNet* a2_net = cell_->getNet(a2_net_);
155        ElectricalNet* zn_net = cell_->getNet(zn_net_);
156
157        a1_net->addDownstreamNode(gate_a1_load);
158        a2_net->addDownstreamNode(gate_a2_load);
159        zn_net->addDownstreamNode(drain_load);
160        if (a1_to_zn_path_) gate_a1_load->addDownstreamNode(zn_drive);
161        if (a2_to_zn_path_) gate_a2_load->addDownstreamNode(zn_drive);
162        zn_drive->addDownstreamNode(zn_net);
163
164        return;
165    }
166
167    //Updates a NAND2 to to the standard cell, normalized to some size
168    void CellMacros::updateNand2(StdCell* cell_, const String& name_, double normalized_size_)
169    {
170        ASSERT(normalized_size_ >= 0.0, "[Error] " + cell_->getInstanceName() +
171            " -> Cannot update a macro with a negative normalized size!");
172
173        //Grab pointer to tech model
174        const TechModel* tech = cell_->getTechModel();
175
176        // Get technology parameters
177        double vdd = tech->get("Vdd");
178        double gate_cap = tech->get("Gate->CapPerWidth");
179        double drain_cap = tech->get("Drain->CapPerWidth");
180        double nmos_eff_res = tech->get("Nmos->EffResWidth");
181        double pmos_eff_res = tech->get("Pmos->EffResWidth");
182        double nmos_eff_res_stack_ratio = tech->get("Nmos->EffResStackRatio");
183        double gate_pitch_contacted = tech->get("Gate->PitchContacted");
184        double metal1_wire_min_width = tech->get("Wire->Metal1->MinWidth");
185
186        //Calculate number of folds needed
187        unsigned int folds = (normalized_size_ < 1.0) ? 1 : (unsigned int)ceil(normalized_size_);
188        cell_->getGenProperties()->set(name_ + "_GatePitches", 2 * folds);
189
190        //Calculate widths, making sure they are above the minimum width
191        double nmos_width = std::max(calculateNmosWidth(cell_, 2, 1, 2) * normalized_size_ / folds, (double) tech->get("Gate->MinWidth"));
192        double pmos_width = std::max(calculatePmosWidth(cell_, 2, 1, 1) * normalized_size_ / folds, (double) tech->get("Gate->MinWidth"));
193
194        // Leakage power calculation
195        double leakage_power_00 = vdd * folds * tech->calculateNmosLeakageCurrent(2, nmos_width, 0x0);
196        double leakage_power_01 = vdd * folds * tech->calculateNmosLeakageCurrent(2, nmos_width, 0x1);
197        double leakage_power_10 = vdd * folds * tech->calculateNmosLeakageCurrent(2, nmos_width, 0x2);
198        double leakage_power_11 = vdd * folds * 2 * tech->calculatePmosLeakageCurrent(1, pmos_width, ~0x3);
199        cell_->getGenProperties()->set(name_ + "_LeakagePower_00", leakage_power_00);
200        cell_->getGenProperties()->set(name_ + "_LeakagePower_01", leakage_power_01);
201        cell_->getGenProperties()->set(name_ + "_LeakagePower_10", leakage_power_10);
202        cell_->getGenProperties()->set(name_ + "_LeakagePower_11", leakage_power_11);
203
204        // Get input parameters
205        double nmos_stack2_balance = 1.0 + nmos_eff_res_stack_ratio;
206
207        //Calculate caps
208        double c_g = (nmos_width + pmos_width) * gate_cap * folds;
209        double c_d = (2 * pmos_width + 2 * nmos_width) * drain_cap * folds;
210        double r_on = (nmos_stack2_balance * nmos_eff_res / nmos_width + pmos_eff_res / pmos_width) / (folds * 2.0);
211
212        // Estimate the wire cap and add them all at the output
213        double cell_height = cell_->getTotalHeight();
214        double wire_width = metal1_wire_min_width;
215        double wire_spacing = gate_pitch_contacted - metal1_wire_min_width;
216        double wire_length = 2.0 * folds * cell_height;
217        double wire_cap = tech->calculateWireCapacitance("Metal1", wire_width, wire_spacing, wire_length);
218
219        // Construct equivalent load and drive strength
220        cell_->getLoad(name_ + "_CgA1")->setLoadCap(c_g);
221        cell_->getLoad(name_ + "_CgA2")->setLoadCap(c_g);
222        cell_->getLoad(name_ + "_CdZN")->setLoadCap(c_d + wire_cap);
223        cell_->getDriver(name_ + "_RonZN")->setOutputRes(r_on);
224
225        // Calculate flip energies
226        double zn_flip_energy = 0.5 * (c_d + wire_cap) * vdd * vdd;
227        double a1_flip_energy = 0.5 * c_g * vdd * vdd;
228        double a2_flip_energy = 0.5 * c_g * vdd * vdd;
229        cell_->getGenProperties()->set(name_ + "_ZN_Flip", zn_flip_energy);
230        cell_->getGenProperties()->set(name_ + "_A1_Flip", a1_flip_energy);
231        cell_->getGenProperties()->set(name_ + "_A2_Flip", a2_flip_energy);
232    }
233    //-------------------------------------------------------------------------
234
235    //-------------------------------------------------------------------------
236    // INV Macro
237    //-------------------------------------------------------------------------
238    //Adds an inverter to the model, normalized to some size
239    void CellMacros::addInverter(StdCell* cell_, const String& name_,
240        bool sizable_, bool a_to_zn_path_,
241        const String& a_net_, const String& zn_net_)
242    {
243        //Create electrical timing model for the inverter
244        // Construct loads and drivers
245        cell_->createLoad(name_ + "_CgA");
246        cell_->createLoad(name_ + "_CdZN");
247        cell_->createDriver(name_ + "_RonZN", sizable_);
248
249        //Get references to loads and drivers
250        ElectricalLoad* gate_load = cell_->getLoad(name_ + "_CgA");
251        ElectricalLoad* drain_load = cell_->getLoad(name_ + "_CdZN");
252        ElectricalDriver* out_drive = cell_->getDriver(name_ + "_RonZN");
253        ElectricalNet* a_net = cell_->getNet(a_net_);
254        ElectricalNet* zn_net = cell_->getNet(zn_net_);
255
256        // Setup connectivity of loads and drivers
257        a_net->addDownstreamNode(gate_load);
258        if (a_to_zn_path_) gate_load->addDownstreamNode(out_drive);
259        zn_net->addDownstreamNode(drain_load);
260        out_drive->addDownstreamNode(zn_net);
261
262        return;
263    }
264
265    //Updates the numbers of an inverter for some normalized size
266    void CellMacros::updateInverter(StdCell* cell_, const String& name_, double normalized_size_)
267    {
268        ASSERT(normalized_size_ >= 0.0, "[Error] " + cell_->getInstanceName() +
269            " -> Cannot update a macro with a negative normalized size!");
270
271        //Grab pointer to tech model
272        const TechModel* tech = cell_->getTechModel();
273
274        //Get values from technology library
275        double vdd = tech->get("Vdd");
276        double gate_cap = tech->get("Gate->CapPerWidth");
277        double drain_cap = tech->get("Drain->CapPerWidth");
278        double nmos_eff_res = tech->get("Nmos->EffResWidth");
279        double pmos_eff_res = tech->get("Pmos->EffResWidth");
280        double gate_pitch_contacted = tech->get("Gate->PitchContacted");
281        double metal1_wire_min_width = tech->get("Wire->Metal1->MinWidth");
282
283        //Calculate number of folds needed
284        unsigned int folds = (normalized_size_ < 1.0) ? 1 : (unsigned int)ceil(normalized_size_);
285        cell_->getGenProperties()->set(name_ + "_GatePitches", folds);
286
287        //Calculate widths, making sure they are above the minimum width
288        double nmos_width = std::max(calculateNmosWidth(cell_, 1, 1, 1) * normalized_size_ / folds, (double) tech->get("Gate->MinWidth"));
289        double pmos_width = std::max(calculatePmosWidth(cell_, 1, 1, 1) * normalized_size_ / folds, (double) tech->get("Gate->MinWidth"));
290
291        //Calculate leakage power for each given input state
292        double leakage_power_0 = vdd * folds * tech->calculateNmosLeakageCurrent(1, nmos_width, 0x0);
293        double leakage_power_1 = vdd * folds * tech->calculatePmosLeakageCurrent(1, pmos_width, ~0x1);
294        cell_->getGenProperties()->set(name_ + "_LeakagePower_0", leakage_power_0);
295        cell_->getGenProperties()->set(name_ + "_LeakagePower_1", leakage_power_1);
296
297        //Calculate caps
298        double c_g = (nmos_width + pmos_width) * gate_cap * folds;
299        double c_d = (pmos_width + nmos_width) * drain_cap * folds;
300        double r_on = (nmos_eff_res / nmos_width + pmos_eff_res / pmos_width) / (folds * 2.0);
301
302        // Estimate the wire cap and add them all at the output
303        double cell_height = cell_->getTotalHeight();
304        double wire_width = metal1_wire_min_width;
305        double wire_spacing = gate_pitch_contacted - metal1_wire_min_width;
306        double wire_length = folds * cell_height;
307        double wire_cap = tech->calculateWireCapacitance("Metal1", wire_width, wire_spacing, wire_length);
308
309        // Construct equivalent load and drive strength
310        cell_->getLoad(name_ + "_CgA")->setLoadCap(c_g);
311        cell_->getLoad(name_ + "_CdZN")->setLoadCap(c_d + wire_cap);
312        cell_->getDriver(name_ + "_RonZN")->setOutputRes(r_on);
313
314        // Calculate flip energy (output flip)
315        // Calculate flip energies
316        double zn_flip_energy = 0.5 * (c_d + wire_cap) * vdd * vdd;
317        double a_flip_energy = 0.5 * c_g * vdd * vdd;
318        cell_->getGenProperties()->set(name_ + "_ZN_Flip", zn_flip_energy);
319        cell_->getGenProperties()->set(name_ + "_A_Flip", a_flip_energy);
320
321        return;
322    }
323    //-------------------------------------------------------------------------
324
325    //-------------------------------------------------------------------------
326    // INVZ Macro
327    //-------------------------------------------------------------------------
328    //Adds a tristated inverter to the model, normalized to some size
329    void CellMacros::addTristate(StdCell* cell_, const String& name_,
330        bool sizable_, bool a_to_zn_path_, bool oe_to_zn_path_, bool oen_to_zn_path_,
331        const String& a_net_, const String& oe_net_, const String& oen_net_, const String& zn_net_)
332    {
333        // Construct loads and drivers
334        cell_->createLoad(name_ + "_CgA");
335        cell_->createLoad(name_ + "_CgOE");
336        cell_->createLoad(name_ + "_CgOEN");
337        cell_->createLoad(name_ + "_CdZN");
338        cell_->createDriver(name_ + "_RonZN", sizable_);
339
340        // Get references to loads, nets and drivers
341        ElectricalLoad* gate_a_load = cell_->getLoad(name_ + "_CgA");
342        ElectricalLoad* gate_oe_load = cell_->getLoad(name_ + "_CgOE");
343        ElectricalLoad* gate_oen_load = cell_->getLoad(name_ + "_CgOEN");
344        ElectricalLoad* drain_load = cell_->getLoad(name_ + "_CdZN");
345        ElectricalDriver* out_drive = cell_->getDriver(name_ + "_RonZN");
346        ElectricalNet* a_net = cell_->getNet(a_net_);
347        ElectricalNet* oe_net = cell_->getNet(oe_net_);
348        ElectricalNet* oen_net = cell_->getNet(oen_net_);
349        ElectricalNet* zn_net = cell_->getNet(zn_net_);
350
351        // Setup connectivity of loads and drivers
352        a_net->addDownstreamNode(gate_a_load);
353        oe_net->addDownstreamNode(gate_oe_load);
354        oen_net->addDownstreamNode(gate_oen_load);
355        if (a_to_zn_path_) gate_a_load->addDownstreamNode(out_drive);
356        if (oe_to_zn_path_) gate_oe_load->addDownstreamNode(out_drive);
357        if (oen_to_zn_path_) gate_oen_load->addDownstreamNode(out_drive);
358        zn_net->addDownstreamNode(drain_load);
359        out_drive->addDownstreamNode(zn_net);
360
361        return;
362    }
363
364    //Updates the numbers of an inverter for some normalized size
365    void CellMacros::updateTristate(StdCell* cell_, const String& name_, double normalized_size_)
366    {
367        ASSERT(normalized_size_ >= 0.0, "[Error] " + cell_->getInstanceName() +
368            " -> Cannot update a macro with a negative normalized size!");
369
370        //Grab pointer to tech model
371        const TechModel* tech = cell_->getTechModel();
372
373        //Get values from technology library
374        double vdd = tech->get("Vdd");
375        double gate_cap = tech->get("Gate->CapPerWidth");
376        double drain_cap = tech->get("Drain->CapPerWidth");
377        double nmos_eff_res = tech->get("Nmos->EffResWidth");
378        double pmos_eff_res = tech->get("Pmos->EffResWidth");
379        double pmos_eff_res_stack_ratio = tech->get("Pmos->EffResStackRatio");
380        double nmos_eff_res_stack_ratio = tech->get("Nmos->EffResStackRatio");
381        double gate_pitch_contacted = tech->get("Gate->PitchContacted");
382        double metal1_wire_min_width = tech->get("Wire->Metal1->MinWidth");
383
384        //Calculate number of folds and gate pitches needed
385        unsigned int folds = (normalized_size_ < 1.0) ? 1 : (unsigned int)ceil(normalized_size_);
386        cell_->getGenProperties()->set(name_ + "_GatePitches", 2 * folds);
387
388        //Calculate widths, making sure they are above the minimum width
389        double nmos_width = std::max(calculateNmosWidth(cell_, 2, 2, 2) * normalized_size_ / folds, (double) tech->get("Gate->MinWidth"));
390        double pmos_width = std::max(calculatePmosWidth(cell_, 2, 2, 2) * normalized_size_ / folds, (double) tech->get("Gate->MinWidth"));
391
392        //Calculate leakage power for each given input state
393        //if output_enable = 0, then it is possible that the PMOS may leak (if output = 0),
394        //or the NMOS will leak (if output = 1)
395
396        //OE OEN A _ ZN
397        double leakage_power_010_0 = vdd * folds * tech->calculatePmosLeakageCurrent(2, pmos_width, ~0x2);
398        double leakage_power_010_1 = vdd * folds * tech->calculateNmosLeakageCurrent(2, nmos_width, 0x0);
399        double leakage_power_011_0 = vdd * folds * tech->calculatePmosLeakageCurrent(2, pmos_width, ~0x3);
400        double leakage_power_011_1 = vdd * folds * tech->calculateNmosLeakageCurrent(2, nmos_width, 0x1);
401        double leakage_power_100_1 = vdd * folds * tech->calculateNmosLeakageCurrent(2, nmos_width, 0x2);
402        double leakage_power_101_0 = vdd * folds * tech->calculatePmosLeakageCurrent(2, pmos_width, ~0x1);
403        cell_->getGenProperties()->set(name_ + "_LeakagePower_010_0", leakage_power_010_0);
404        cell_->getGenProperties()->set(name_ + "_LeakagePower_010_1", leakage_power_010_1);
405        cell_->getGenProperties()->set(name_ + "_LeakagePower_011_0", leakage_power_011_0);
406        cell_->getGenProperties()->set(name_ + "_LeakagePower_011_1", leakage_power_011_1);
407        cell_->getGenProperties()->set(name_ + "_LeakagePower_100_1", leakage_power_100_1);
408        cell_->getGenProperties()->set(name_ + "_LeakagePower_101_0", leakage_power_101_0);
409
410        //Caculate stack balance
411        double pmos_stack2_balance = 1.0 + pmos_eff_res_stack_ratio;
412        double nmos_stack2_balance = 1.0 + nmos_eff_res_stack_ratio;
413
414        //Calculate caps
415        double c_g_a = (nmos_width + pmos_width) * gate_cap * folds;
416        double c_g_oe = nmos_width * gate_cap * folds;
417        double c_g_oen = pmos_width * gate_cap * folds;
418        double c_d = (2 * pmos_width + 2 * nmos_width) * drain_cap * folds;
419        double r_on = (nmos_stack2_balance * nmos_eff_res / nmos_width + pmos_stack2_balance * pmos_eff_res / pmos_width) / (folds * 2.0);
420
421        // Estimate the wire cap and add them all at the output
422        double cell_height = cell_->getTotalHeight();
423        double wire_width = metal1_wire_min_width;
424        double wire_spacing = gate_pitch_contacted - metal1_wire_min_width;
425        double wire_length = 2.0 * folds * cell_height;
426        double wire_cap = tech->calculateWireCapacitance("Metal1", wire_width, wire_spacing, wire_length);
427
428        // Construct equivalent load and drive strength
429        cell_->getLoad(name_ + "_CgA")->setLoadCap(c_g_a);
430        cell_->getLoad(name_ + "_CgOE")->setLoadCap(c_g_oe);
431        cell_->getLoad(name_ + "_CgOEN")->setLoadCap(c_g_oen);
432        cell_->getLoad(name_ + "_CdZN")->setLoadCap(c_d + wire_cap);
433        cell_->getDriver(name_ + "_RonZN")->setOutputRes(r_on);
434
435        // Calculate flip energy (output flip)
436        double zn_flip_energy = 0.5 * (c_d + wire_cap) * vdd * vdd;
437        double a_flip_energy = 0.5 * c_g_a * vdd * vdd;
438        double oe_flip_energy = 0.5 * c_g_oe * vdd * vdd;
439        double oen_flip_energy = 0.5 * c_g_oen * vdd * vdd;
440        cell_->getGenProperties()->set(name_ + "_ZN_Flip", zn_flip_energy);
441        cell_->getGenProperties()->set(name_ + "_A_Flip", a_flip_energy);
442        cell_->getGenProperties()->set(name_ + "_OE_Flip", oe_flip_energy);
443        cell_->getGenProperties()->set(name_ + "_OEN_Flip", oen_flip_energy);
444        return;
445    }
446    //-------------------------------------------------------------------------
447
448
449    //-------------------------------------------------------------------------
450    // Helper Functions
451    //-------------------------------------------------------------------------
452    //Returns the width of NMOS transistors, given the NMOS and PMOS stacking
453    double CellMacros::calculateNmosWidth(const StdCell* cell_, unsigned int max_stacked_nmos_, unsigned int max_stacked_pmos_, unsigned int current_stacked_nmos_)
454    {
455        //Grab pointer to tech model
456        const TechModel* tech = cell_->getTechModel();
457
458        double nmos_eff_res_stack_ratio = tech->get("Nmos->EffResStackRatio");
459        double pmos_eff_res_stack_ratio = tech->get("Pmos->EffResStackRatio");
460
461        double nmos_stack_balance = 1.0 + nmos_eff_res_stack_ratio * (double) (max_stacked_nmos_ - 1);
462        double pmos_stack_balance = 1.0 + pmos_eff_res_stack_ratio * (double) (max_stacked_pmos_ - 1);
463        double current_nmos_stack_balance = 1.0 + nmos_eff_res_stack_ratio * (double) (current_stacked_nmos_ - 1);
464
465        double pn_ratio = cell_->getPToNRatio();
466        double active_height = cell_->getActiveHeight();
467
468        //Calculate the width of the current device
469        double nmos_width = active_height * current_nmos_stack_balance / (nmos_stack_balance + pn_ratio * pmos_stack_balance);
470
471        return nmos_width;
472    }
473
474    //Returns the width of PMOS transistors, given the NMOS and PMOS stacking
475    double CellMacros::calculatePmosWidth(const StdCell* cell_, unsigned int max_stacked_nmos_, unsigned int max_stacked_pmos_, unsigned int current_stacked_pmos_)
476    {
477        //Grab pointer to tech model
478        const TechModel* tech = cell_->getTechModel();
479
480        double nmos_eff_res_stack_ratio = tech->get("Nmos->EffResStackRatio");
481        double pmos_eff_res_stack_ratio = tech->get("Pmos->EffResStackRatio");
482
483        double nmos_stack_balance = 1.0 + nmos_eff_res_stack_ratio * (double) (max_stacked_nmos_ - 1);
484        double pmos_stack_balance = 1.0 + pmos_eff_res_stack_ratio * (double) (max_stacked_pmos_ - 1);
485        double current_pmos_stack_balance = 1.0 + pmos_eff_res_stack_ratio * (double) (current_stacked_pmos_ - 1);
486
487        double pn_ratio = cell_->getPToNRatio();
488        double active_height = cell_->getActiveHeight();
489
490        //Calculate the width of the current device
491        double pmos_width = active_height * current_pmos_stack_balance * pn_ratio / (nmos_stack_balance + pn_ratio * pmos_stack_balance);
492
493        return pmos_width;
494    }
495    //-------------------------------------------------------------------------
496
497} // namespace DSENT
498
499