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