| /***************************************************************************** | |
| * McPAT/CACTI | |
| * SOFTWARE LICENSE AGREEMENT | |
| * Copyright 2012 Hewlett-Packard Development Company, L.P. | |
| * Copyright (c) 2010-2013 Advanced Micro Devices, Inc. | |
| * All Rights Reserved | |
| * | |
| * Redistribution and use in source and binary forms, with or without | |
| * modification, are permitted provided that the following conditions are | |
| * met: redistributions of source code must retain the above copyright | |
| * notice, this list of conditions and the following disclaimer; | |
| * redistributions in binary form must reproduce the above copyright | |
| * notice, this list of conditions and the following disclaimer in the | |
| * documentation and/or other materials provided with the distribution; | |
| * neither the name of the copyright holders nor the names of its | |
| * contributors may be used to endorse or promote products derived from | |
| * this software without specific prior written permission. | |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
| * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| * | |
| ***************************************************************************/ | |
| #include "wire.h" | |
| #include "cmath" | |
| // use this constructor to calculate wire stats | |
| Wire::Wire( | |
| enum Wire_type wire_model, | |
| double wl, | |
| int n, | |
| double w_s, | |
| double s_s, | |
| enum Wire_placement wp, | |
| double resistivity, | |
| TechnologyParameter::DeviceType *dt | |
| ): wt(wire_model), wire_length(wl*1e-6), nsense(n), w_scale(w_s), | |
| s_scale(s_s), | |
| resistivity(resistivity), deviceType(dt) { | |
| wire_placement = wp; | |
| min_w_pmos = deviceType->n_to_p_eff_curr_drv_ratio * g_tp.min_w_nmos_; | |
| in_rise_time = 0; | |
| out_rise_time = 0; | |
| if (initialized != 1) { | |
| cout << "Wire not initialized. Initializing it with default values\n"; | |
| Wire winit; | |
| } | |
| calculate_wire_stats(); | |
| // change everything back to seconds, microns, and Joules | |
| repeater_spacing *= 1e6; | |
| wire_length *= 1e6; | |
| wire_width *= 1e6; | |
| wire_spacing *= 1e6; | |
| assert(wire_length > 0); | |
| assert(power.readOp.dynamic > 0); | |
| assert(power.readOp.leakage > 0); | |
| assert(power.readOp.gate_leakage > 0); | |
| } | |
| // the following values are for peripheral global technology | |
| // specified in the input config file | |
| Component Wire::global; | |
| Component Wire::global_5; | |
| Component Wire::global_10; | |
| Component Wire::global_20; | |
| Component Wire::global_30; | |
| Component Wire::low_swing; | |
| int Wire::initialized; | |
| double Wire::wire_width_init; | |
| double Wire::wire_spacing_init; | |
| Wire::Wire(double w_s, double s_s, enum Wire_placement wp, double resis, | |
| TechnologyParameter::DeviceType *dt) { | |
| w_scale = w_s; | |
| s_scale = s_s; | |
| deviceType = dt; | |
| wire_placement = wp; | |
| resistivity = resis; | |
| min_w_pmos = deviceType->n_to_p_eff_curr_drv_ratio * g_tp.min_w_nmos_; | |
| in_rise_time = 0; | |
| out_rise_time = 0; | |
| switch (wire_placement) { | |
| case outside_mat: | |
| wire_width = g_tp.wire_outside_mat.pitch; | |
| break; | |
| case inside_mat : | |
| wire_width = g_tp.wire_inside_mat.pitch; | |
| break; | |
| default: | |
| wire_width = g_tp.wire_local.pitch; | |
| break; | |
| } | |
| wire_spacing = wire_width; | |
| wire_width *= (w_scale * 1e-6 / 2) /* (m) */; | |
| wire_spacing *= (s_scale * 1e-6 / 2) /* (m) */; | |
| initialized = 1; | |
| init_wire(); | |
| wire_width_init = wire_width; | |
| wire_spacing_init = wire_spacing; | |
| assert(power.readOp.dynamic > 0); | |
| assert(power.readOp.leakage > 0); | |
| assert(power.readOp.gate_leakage > 0); | |
| } | |
| Wire::~Wire() { | |
| } | |
| void | |
| Wire::calculate_wire_stats() { | |
| if (wire_placement == outside_mat) { | |
| wire_width = g_tp.wire_outside_mat.pitch; | |
| } else if (wire_placement == inside_mat) { | |
| wire_width = g_tp.wire_inside_mat.pitch; | |
| } else { | |
| wire_width = g_tp.wire_local.pitch; | |
| } | |
| wire_spacing = wire_width; | |
| wire_width *= (w_scale * 1e-6 / 2) /* (m) */; | |
| wire_spacing *= (s_scale * 1e-6 / 2) /* (m) */; | |
| if (wt != Low_swing) { | |
| // delay_optimal_wire(); | |
| if (wt == Global) { | |
| delay = global.delay * wire_length; | |
| power.readOp.dynamic = global.power.readOp.dynamic * wire_length; | |
| power.readOp.leakage = global.power.readOp.leakage * wire_length; | |
| power.readOp.gate_leakage = global.power.readOp.gate_leakage * wire_length; | |
| repeater_spacing = global.area.w; | |
| repeater_size = global.area.h; | |
| area.set_area((wire_length / repeater_spacing) * | |
| compute_gate_area(INV, 1, min_w_pmos * repeater_size, | |
| g_tp.min_w_nmos_ * repeater_size, | |
| g_tp.cell_h_def)); | |
| } else if (wt == Global_5) { | |
| delay = global_5.delay * wire_length; | |
| power.readOp.dynamic = global_5.power.readOp.dynamic * wire_length; | |
| power.readOp.leakage = global_5.power.readOp.leakage * wire_length; | |
| power.readOp.gate_leakage = global_5.power.readOp.gate_leakage * wire_length; | |
| repeater_spacing = global_5.area.w; | |
| repeater_size = global_5.area.h; | |
| area.set_area((wire_length / repeater_spacing) * | |
| compute_gate_area(INV, 1, min_w_pmos * repeater_size, | |
| g_tp.min_w_nmos_ * repeater_size, | |
| g_tp.cell_h_def)); | |
| } else if (wt == Global_10) { | |
| delay = global_10.delay * wire_length; | |
| power.readOp.dynamic = global_10.power.readOp.dynamic * wire_length; | |
| power.readOp.leakage = global_10.power.readOp.leakage * wire_length; | |
| power.readOp.gate_leakage = global_10.power.readOp.gate_leakage * wire_length; | |
| repeater_spacing = global_10.area.w; | |
| repeater_size = global_10.area.h; | |
| area.set_area((wire_length / repeater_spacing) * | |
| compute_gate_area(INV, 1, min_w_pmos * repeater_size, | |
| g_tp.min_w_nmos_ * repeater_size, | |
| g_tp.cell_h_def)); | |
| } else if (wt == Global_20) { | |
| delay = global_20.delay * wire_length; | |
| power.readOp.dynamic = global_20.power.readOp.dynamic * wire_length; | |
| power.readOp.leakage = global_20.power.readOp.leakage * wire_length; | |
| power.readOp.gate_leakage = global_20.power.readOp.gate_leakage * wire_length; | |
| repeater_spacing = global_20.area.w; | |
| repeater_size = global_20.area.h; | |
| area.set_area((wire_length / repeater_spacing) * | |
| compute_gate_area(INV, 1, min_w_pmos * repeater_size, | |
| g_tp.min_w_nmos_ * repeater_size, | |
| g_tp.cell_h_def)); | |
| } else if (wt == Global_30) { | |
| delay = global_30.delay * wire_length; | |
| power.readOp.dynamic = global_30.power.readOp.dynamic * wire_length; | |
| power.readOp.leakage = global_30.power.readOp.leakage * wire_length; | |
| power.readOp.gate_leakage = global_30.power.readOp.gate_leakage * wire_length; | |
| repeater_spacing = global_30.area.w; | |
| repeater_size = global_30.area.h; | |
| area.set_area((wire_length / repeater_spacing) * | |
| compute_gate_area(INV, 1, min_w_pmos * repeater_size, | |
| g_tp.min_w_nmos_ * repeater_size, | |
| g_tp.cell_h_def)); | |
| } | |
| out_rise_time = delay * repeater_spacing / deviceType->Vth; | |
| } else if (wt == Low_swing) { | |
| low_swing_model (); | |
| repeater_spacing = wire_length; | |
| repeater_size = 1; | |
| } else { | |
| assert(0); | |
| } | |
| } | |
| /* | |
| * The fall time of an input signal to the first stage of a circuit is | |
| * assumed to be same as the fall time of the output signal of two | |
| * inverters connected in series (refer: CACTI 1 Technical report, | |
| * section 6.1.3) | |
| */ | |
| double | |
| Wire::signal_fall_time () { | |
| /* rise time of inverter 1's output */ | |
| double rt; | |
| /* fall time of inverter 2's output */ | |
| double ft; | |
| double timeconst; | |
| timeconst = (drain_C_(g_tp.min_w_nmos_, NCH, 1, 1, g_tp.cell_h_def) + | |
| drain_C_(min_w_pmos, PCH, 1, 1, g_tp.cell_h_def) + | |
| gate_C(min_w_pmos + g_tp.min_w_nmos_, 0)) * | |
| tr_R_on(min_w_pmos, PCH, 1); | |
| rt = horowitz (0, timeconst, deviceType->Vth / deviceType->Vdd, | |
| deviceType->Vth / deviceType->Vdd, FALL) / | |
| (deviceType->Vdd - deviceType->Vth); | |
| timeconst = (drain_C_(g_tp.min_w_nmos_, NCH, 1, 1, g_tp.cell_h_def) + | |
| drain_C_(min_w_pmos, PCH, 1, 1, g_tp.cell_h_def) + | |
| gate_C(min_w_pmos + g_tp.min_w_nmos_, 0)) * | |
| tr_R_on(g_tp.min_w_nmos_, NCH, 1); | |
| ft = horowitz (rt, timeconst, deviceType->Vth / deviceType->Vdd, | |
| deviceType->Vth / deviceType->Vdd, RISE) / deviceType->Vth; | |
| return ft; | |
| } | |
| double Wire::signal_rise_time () { | |
| /* rise time of inverter 1's output */ | |
| double ft; | |
| /* fall time of inverter 2's output */ | |
| double rt; | |
| double timeconst; | |
| timeconst = (drain_C_(g_tp.min_w_nmos_, NCH, 1, 1, g_tp.cell_h_def) + | |
| drain_C_(min_w_pmos, PCH, 1, 1, g_tp.cell_h_def) + | |
| gate_C(min_w_pmos + g_tp.min_w_nmos_, 0)) * | |
| tr_R_on(g_tp.min_w_nmos_, NCH, 1); | |
| rt = horowitz (0, timeconst, deviceType->Vth / deviceType->Vdd, | |
| deviceType->Vth / deviceType->Vdd, RISE) / deviceType->Vth; | |
| timeconst = (drain_C_(g_tp.min_w_nmos_, NCH, 1, 1, g_tp.cell_h_def) + | |
| drain_C_(min_w_pmos, PCH, 1, 1, g_tp.cell_h_def) + | |
| gate_C(min_w_pmos + g_tp.min_w_nmos_, 0)) * | |
| tr_R_on(min_w_pmos, PCH, 1); | |
| ft = horowitz (rt, timeconst, deviceType->Vth / deviceType->Vdd, | |
| deviceType->Vth / deviceType->Vdd, FALL) / | |
| (deviceType->Vdd - deviceType->Vth); | |
| return ft; //sec | |
| } | |
| /* Wire resistance and capacitance calculations | |
| * wire width | |
| * | |
| * /__/ | |
| * | | | |
| * | | height = ASPECT_RATIO*wire width (ASPECT_RATIO = 2.2, ref: ITRS) | |
| * |__|/ | |
| * | |
| * spacing between wires in same level = wire width | |
| * spacing between wires in adjacent levels = wire width---this is incorrect, | |
| * according to R.Ho's paper and thesis. ILD != wire width | |
| * | |
| */ | |
| double Wire::wire_cap (double len /* in m */, bool call_from_outside) { | |
| //TODO: this should be consistent with the wire_res in technology file | |
| double sidewall, adj, tot_cap; | |
| double wire_height; | |
| double epsilon0 = 8.8542e-12; | |
| double aspect_ratio; | |
| double horiz_dielectric_constant; | |
| double vert_dielectric_constant; | |
| double miller_value; | |
| double ild_thickness; | |
| switch (wire_placement) { | |
| case outside_mat: { | |
| aspect_ratio = g_tp.wire_outside_mat.aspect_ratio; | |
| horiz_dielectric_constant = g_tp.wire_outside_mat.horiz_dielectric_constant; | |
| vert_dielectric_constant = g_tp.wire_outside_mat.vert_dielectric_constant; | |
| miller_value = g_tp.wire_outside_mat.miller_value; | |
| ild_thickness = g_tp.wire_outside_mat.ild_thickness; | |
| break; | |
| } | |
| case inside_mat : { | |
| aspect_ratio = g_tp.wire_inside_mat.aspect_ratio; | |
| horiz_dielectric_constant = g_tp.wire_inside_mat.horiz_dielectric_constant; | |
| vert_dielectric_constant = g_tp.wire_inside_mat.vert_dielectric_constant; | |
| miller_value = g_tp.wire_inside_mat.miller_value; | |
| ild_thickness = g_tp.wire_inside_mat.ild_thickness; | |
| break; | |
| } | |
| default: { | |
| aspect_ratio = g_tp.wire_local.aspect_ratio; | |
| horiz_dielectric_constant = g_tp.wire_local.horiz_dielectric_constant; | |
| vert_dielectric_constant = g_tp.wire_local.vert_dielectric_constant; | |
| miller_value = g_tp.wire_local.miller_value; | |
| ild_thickness = g_tp.wire_local.ild_thickness; | |
| break; | |
| } | |
| } | |
| if (call_from_outside) { | |
| wire_width *= 1e-6; | |
| wire_spacing *= 1e-6; | |
| } | |
| wire_height = wire_width / w_scale * aspect_ratio; | |
| /* | |
| * assuming height does not change. wire_width = width_original*w_scale | |
| * So wire_height does not change as wire width increases | |
| */ | |
| // capacitance between wires in the same level | |
| // sidewall = 2*miller_value * horiz_dielectric_constant * (wire_height/wire_spacing) | |
| // * epsilon0; | |
| sidewall = miller_value * horiz_dielectric_constant * | |
| (wire_height / wire_spacing) | |
| * epsilon0; | |
| // capacitance between wires in adjacent levels | |
| //adj = miller_value * vert_dielectric_constant *w_scale * epsilon0; | |
| //adj = 2*vert_dielectric_constant *wire_width/(ild_thickness*1e-6) * epsilon0; | |
| adj = miller_value * vert_dielectric_constant * wire_width / | |
| (ild_thickness * 1e-6) * epsilon0; | |
| //Change ild_thickness from micron to M | |
| //tot_cap = (sidewall + adj + (deviceType->C_fringe * 1e6)); //F/m | |
| tot_cap = (sidewall + adj + (g_tp.fringe_cap * 1e6)); //F/m | |
| if (call_from_outside) { | |
| wire_width *= 1e6; | |
| wire_spacing *= 1e6; | |
| } | |
| return (tot_cap*len); // (F) | |
| } | |
| double | |
| Wire::wire_res (double len /*(in m)*/) { | |
| double aspect_ratio; | |
| double alpha_scatter = 1.05; | |
| double dishing_thickness = 0; | |
| double barrier_thickness = 0; | |
| //TODO: this should be consistent with the wire_res in technology file | |
| //The whole computation should be consistent with the wire_res in technology.cc too! | |
| switch (wire_placement) { | |
| case outside_mat: { | |
| aspect_ratio = g_tp.wire_outside_mat.aspect_ratio; | |
| break; | |
| } | |
| case inside_mat : { | |
| aspect_ratio = g_tp.wire_inside_mat.aspect_ratio; | |
| break; | |
| } | |
| default: { | |
| aspect_ratio = g_tp.wire_local.aspect_ratio; | |
| break; | |
| } | |
| } | |
| return (alpha_scatter * resistivity * 1e-6 * len / | |
| ((aspect_ratio*wire_width / w_scale - dishing_thickness - | |
| barrier_thickness)* | |
| (wire_width - 2*barrier_thickness))); | |
| } | |
| /* | |
| * Calculates the delay, power and area of the transmitter circuit. | |
| * | |
| * The transmitter delay is the sum of nand gate delay, inverter delay | |
| * low swing nmos delay, and the wire delay | |
| * (ref: Technical report 6) | |
| */ | |
| void | |
| Wire::low_swing_model() { | |
| double len = wire_length; | |
| double beta = pmos_to_nmos_sz_ratio(); | |
| double inputrise = (in_rise_time == 0) ? signal_rise_time() : in_rise_time; | |
| /* Final nmos low swing driver size calculation: | |
| * Try to size the driver such that the delay | |
| * is less than 8FO4. | |
| * If the driver size is greater than | |
| * the max allowable size, assume max size for the driver. | |
| * In either case, recalculate the delay using | |
| * the final driver size assuming slow input with | |
| * finite rise time instead of ideal step input | |
| * | |
| * (ref: Technical report 6) | |
| */ | |
| double cwire = wire_cap(len); /* load capacitance */ | |
| double rwire = wire_res(len); | |
| #define RES_ADJ (8.6) // Increase in resistance due to low driving vol. | |
| double driver_res = (-8 * g_tp.FO4 / (log(0.5) * cwire)) / RES_ADJ; | |
| double nsize = R_to_w(driver_res, NCH); | |
| nsize = MIN(nsize, g_tp.max_w_nmos_); | |
| nsize = MAX(nsize, g_tp.min_w_nmos_); | |
| if (rwire*cwire > 8*g_tp.FO4) { | |
| nsize = g_tp.max_w_nmos_; | |
| } | |
| // size the inverter appropriately to minimize the transmitter delay | |
| // Note - In order to minimize leakage, we are not adding a set of inverters to | |
| // bring down delay. Instead, we are sizing the single gate | |
| // based on the logical effort. | |
| double st_eff = sqrt((2 + beta / 1 + beta) * gate_C(nsize, 0) / | |
| (gate_C(2 * g_tp.min_w_nmos_, 0) | |
| + gate_C(2 * min_w_pmos, 0))); | |
| double req_cin = ((2 + beta / 1 + beta) * gate_C(nsize, 0)) / st_eff; | |
| double inv_size = req_cin / (gate_C(min_w_pmos, 0) + | |
| gate_C(g_tp.min_w_nmos_, 0)); | |
| inv_size = MAX(inv_size, 1); | |
| /* nand gate delay */ | |
| double res_eq = (2 * tr_R_on(g_tp.min_w_nmos_, NCH, 1)); | |
| double cap_eq = 2 * drain_C_(min_w_pmos, PCH, 1, 1, g_tp.cell_h_def) + | |
| drain_C_(2 * g_tp.min_w_nmos_, NCH, 1, 1, g_tp.cell_h_def) + | |
| gate_C(inv_size * g_tp.min_w_nmos_, 0) + | |
| gate_C(inv_size * min_w_pmos, 0); | |
| double timeconst = res_eq * cap_eq; | |
| delay = horowitz(inputrise, timeconst, deviceType->Vth / deviceType->Vdd, | |
| deviceType->Vth / deviceType->Vdd, RISE); | |
| double temp_power = cap_eq * deviceType->Vdd * deviceType->Vdd; | |
| inputrise = delay / (deviceType->Vdd - deviceType->Vth); /* for the next stage */ | |
| /* Inverter delay: | |
| * The load capacitance of this inv depends on | |
| * the gate capacitance of the final stage nmos | |
| * transistor which in turn depends on nsize | |
| */ | |
| res_eq = tr_R_on(inv_size * min_w_pmos, PCH, 1); | |
| cap_eq = drain_C_(inv_size * min_w_pmos, PCH, 1, 1, g_tp.cell_h_def) + | |
| drain_C_(inv_size * g_tp.min_w_nmos_, NCH, 1, 1, g_tp.cell_h_def) + | |
| gate_C(nsize, 0); | |
| timeconst = res_eq * cap_eq; | |
| delay += horowitz(inputrise, timeconst, deviceType->Vth / deviceType->Vdd, | |
| deviceType->Vth / deviceType->Vdd, FALL); | |
| temp_power += cap_eq * deviceType->Vdd * deviceType->Vdd; | |
| transmitter.delay = delay; | |
| /* since it is a diff. model*/ | |
| transmitter.power.readOp.dynamic = temp_power * 2; | |
| transmitter.power.readOp.leakage = deviceType->Vdd * | |
| (4 * cmos_Isub_leakage(g_tp.min_w_nmos_, min_w_pmos, 2, nand) + | |
| 4 * cmos_Isub_leakage(g_tp.min_w_nmos_, min_w_pmos, 1, inv)); | |
| transmitter.power.readOp.gate_leakage = deviceType->Vdd * | |
| (4 * cmos_Ig_leakage(g_tp.min_w_nmos_, min_w_pmos, 2, nand) + | |
| 4 * cmos_Ig_leakage(g_tp.min_w_nmos_, min_w_pmos, 1, inv)); | |
| inputrise = delay / deviceType->Vth; | |
| /* nmos delay + wire delay */ | |
| cap_eq = cwire + drain_C_(nsize, NCH, 1, 1, g_tp.cell_h_def) * 2 + | |
| nsense * sense_amp_input_cap(); //+receiver cap | |
| /* | |
| * NOTE: nmos is used as both pull up and pull down transistor | |
| * in the transmitter. This is because for low voltage swing, drive | |
| * resistance of nmos is less than pmos | |
| * (for a detailed graph ref: On-Chip Wires: Scaling and Efficiency) | |
| */ | |
| timeconst = (tr_R_on(nsize, NCH, 1) * RES_ADJ) * (cwire + | |
| drain_C_(nsize, NCH, 1, 1, g_tp.cell_h_def) * 2) + | |
| rwire * cwire / 2 + | |
| (tr_R_on(nsize, NCH, 1) * RES_ADJ + rwire) * | |
| nsense * sense_amp_input_cap(); | |
| /* | |
| * since we are pre-equalizing and overdriving the low | |
| * swing wires, the net time constant is less | |
| * than the actual value | |
| */ | |
| delay += horowitz(inputrise, timeconst, deviceType->Vth / | |
| deviceType->Vdd, .25, 0); | |
| #define VOL_SWING .1 | |
| temp_power += cap_eq * VOL_SWING * .400; /* .4v is the over drive voltage */ | |
| temp_power *= 2; /* differential wire */ | |
| l_wire.delay = delay - transmitter.delay; | |
| l_wire.power.readOp.dynamic = temp_power - transmitter.power.readOp.dynamic; | |
| l_wire.power.readOp.leakage = deviceType->Vdd * | |
| (4 * cmos_Isub_leakage(nsize, 0, 1, nmos)); | |
| l_wire.power.readOp.gate_leakage = deviceType->Vdd * | |
| (4 * cmos_Ig_leakage(nsize, 0, 1, nmos)); | |
| //double rt = horowitz(inputrise, timeconst, deviceType->Vth/deviceType->Vdd, | |
| // deviceType->Vth/deviceType->Vdd, RISE)/deviceType->Vth; | |
| delay += g_tp.sense_delay; | |
| sense_amp.delay = g_tp.sense_delay; | |
| out_rise_time = g_tp.sense_delay / (deviceType->Vth); | |
| sense_amp.power.readOp.dynamic = g_tp.sense_dy_power; | |
| sense_amp.power.readOp.leakage = 0; //FIXME | |
| sense_amp.power.readOp.gate_leakage = 0; | |
| power.readOp.dynamic = temp_power + sense_amp.power.readOp.dynamic; | |
| power.readOp.leakage = transmitter.power.readOp.leakage + | |
| l_wire.power.readOp.leakage + | |
| sense_amp.power.readOp.leakage; | |
| power.readOp.gate_leakage = transmitter.power.readOp.gate_leakage + | |
| l_wire.power.readOp.gate_leakage + | |
| sense_amp.power.readOp.gate_leakage; | |
| } | |
| double | |
| Wire::sense_amp_input_cap() { | |
| return drain_C_(g_tp.w_iso, PCH, 1, 1, g_tp.cell_h_def) + | |
| gate_C(g_tp.w_sense_en + g_tp.w_sense_n, 0) + | |
| drain_C_(g_tp.w_sense_n, NCH, 1, 1, g_tp.cell_h_def) + | |
| drain_C_(g_tp.w_sense_p, PCH, 1, 1, g_tp.cell_h_def); | |
| } | |
| void Wire::delay_optimal_wire () { | |
| double len = wire_length; | |
| //double min_wire_width = wire_width; //m | |
| double beta = pmos_to_nmos_sz_ratio(); | |
| double switching = 0; // switching energy | |
| double short_ckt = 0; // short-circuit energy | |
| double tc = 0; // time constant | |
| // input cap of min sized driver | |
| double input_cap = gate_C(g_tp.min_w_nmos_ + min_w_pmos, 0); | |
| // output parasitic capacitance of | |
| // the min. sized driver | |
| double out_cap = drain_C_(min_w_pmos, PCH, 1, 1, g_tp.cell_h_def) + | |
| drain_C_(g_tp.min_w_nmos_, NCH, 1, 1, g_tp.cell_h_def); | |
| // drive resistance | |
| double out_res = (tr_R_on(g_tp.min_w_nmos_, NCH, 1) + | |
| tr_R_on(min_w_pmos, PCH, 1)) / 2; | |
| double wr = wire_res(len); //ohm | |
| // wire cap /m | |
| double wc = wire_cap(len); | |
| // size the repeater such that the delay of the wire is minimum | |
| // len will cancel | |
| double repeater_scaling = sqrt(out_res * wc / (wr * input_cap)); | |
| // calc the optimum spacing between the repeaters (m) | |
| repeater_spacing = sqrt(2 * out_res * (out_cap + input_cap) / | |
| ((wr / len) * (wc / len))); | |
| repeater_size = repeater_scaling; | |
| switching = (repeater_scaling * (input_cap + out_cap) + | |
| repeater_spacing * (wc / len)) * deviceType->Vdd * | |
| deviceType->Vdd; | |
| tc = out_res * (input_cap + out_cap) + | |
| out_res * wc / len * repeater_spacing / repeater_scaling + | |
| wr / len * repeater_spacing * input_cap * repeater_scaling + | |
| 0.5 * (wr / len) * (wc / len) * repeater_spacing * repeater_spacing; | |
| delay = 0.693 * tc * len / repeater_spacing; | |
| #define Ishort_ckt 65e-6 /* across all tech Ref:Banerjee et al. {IEEE TED} */ | |
| short_ckt = deviceType->Vdd * g_tp.min_w_nmos_ * Ishort_ckt * 1.0986 * | |
| repeater_scaling * tc; | |
| area.set_area((len / repeater_spacing) * | |
| compute_gate_area(INV, 1, min_w_pmos * repeater_scaling, | |
| g_tp.min_w_nmos_ * repeater_scaling, | |
| g_tp.cell_h_def)); | |
| power.readOp.dynamic = ((len / repeater_spacing) * (switching + short_ckt)); | |
| power.readOp.leakage = ((len / repeater_spacing) * | |
| deviceType->Vdd * | |
| cmos_Isub_leakage(g_tp.min_w_nmos_ * | |
| repeater_scaling, beta * | |
| g_tp.min_w_nmos_ * | |
| repeater_scaling, 1, inv)); | |
| power.readOp.gate_leakage = ((len / repeater_spacing) * | |
| deviceType->Vdd * | |
| cmos_Ig_leakage(g_tp.min_w_nmos_ * | |
| repeater_scaling, beta * | |
| g_tp.min_w_nmos_ * | |
| repeater_scaling, 1, inv)); | |
| } | |
| // calculate power/delay values for wires with suboptimal repeater sizing/spacing | |
| void | |
| Wire::init_wire() { | |
| wire_length = 1; | |
| delay_optimal_wire(); | |
| double sp, si; | |
| powerDef pow; | |
| si = repeater_size; | |
| sp = repeater_spacing; | |
| sp *= 1e6; // in microns | |
| double i, j, del; | |
| repeated_wire.push_back(Component()); | |
| for (j = sp; j < 4*sp; j += 100) { | |
| for (i = si; i > 1; i--) { | |
| pow = wire_model(j * 1e-6, i, &del); | |
| if (j == sp && i == si) { | |
| global.delay = del; | |
| global.power = pow; | |
| global.area.h = si; | |
| global.area.w = sp * 1e-6; // m | |
| } | |
| // cout << "Repeater size - "<< i << | |
| // " Repeater spacing - " << j << | |
| // " Delay - " << del << | |
| // " PowerD - " << pow.readOp.dynamic << | |
| // " PowerL - " << pow.readOp.leakage <<endl; | |
| repeated_wire.back().delay = del; | |
| repeated_wire.back().power.readOp = pow.readOp; | |
| repeated_wire.back().area.w = j * 1e-6; //m | |
| repeated_wire.back().area.h = i; | |
| repeated_wire.push_back(Component()); | |
| } | |
| } | |
| repeated_wire.pop_back(); | |
| update_fullswing(); | |
| Wire *l_wire = new Wire(Low_swing, 0.001/* 1 mm*/, 1); | |
| low_swing.delay = l_wire->delay; | |
| low_swing.power = l_wire->power; | |
| delete l_wire; | |
| } | |
| void Wire::update_fullswing() { | |
| list<Component>::iterator citer; | |
| double del[4]; | |
| del[3] = this->global.delay + this->global.delay * .3; | |
| del[2] = global.delay + global.delay * .2; | |
| del[1] = global.delay + global.delay * .1; | |
| del[0] = global.delay + global.delay * .05; | |
| double threshold; | |
| double ncost; | |
| double cost; | |
| int i = 4; | |
| while (i > 0) { | |
| threshold = del[i-1]; | |
| cost = BIGNUM; | |
| for (citer = repeated_wire.begin(); citer != repeated_wire.end(); | |
| citer++) { | |
| if (citer->delay > threshold) { | |
| citer = repeated_wire.erase(citer); | |
| citer --; | |
| } else { | |
| ncost = citer->power.readOp.dynamic / | |
| global.power.readOp.dynamic + | |
| citer->power.readOp.leakage / global.power.readOp.leakage; | |
| if (ncost < cost) { | |
| cost = ncost; | |
| if (i == 4) { | |
| global_30.delay = citer->delay; | |
| global_30.power = citer->power; | |
| global_30.area = citer->area; | |
| } else if (i == 3) { | |
| global_20.delay = citer->delay; | |
| global_20.power = citer->power; | |
| global_20.area = citer->area; | |
| } else if (i == 2) { | |
| global_10.delay = citer->delay; | |
| global_10.power = citer->power; | |
| global_10.area = citer->area; | |
| } else if (i == 1) { | |
| global_5.delay = citer->delay; | |
| global_5.power = citer->power; | |
| global_5.area = citer->area; | |
| } | |
| } | |
| } | |
| } | |
| i--; | |
| } | |
| } | |
| powerDef Wire::wire_model (double space, double size, double *delay) { | |
| powerDef ptemp; | |
| double len = 1; | |
| //double min_wire_width = wire_width; //m | |
| double beta = pmos_to_nmos_sz_ratio(); | |
| // switching energy | |
| double switching = 0; | |
| // short-circuit energy | |
| double short_ckt = 0; | |
| // time constant | |
| double tc = 0; | |
| // input cap of min sized driver | |
| double input_cap = gate_C (g_tp.min_w_nmos_ + | |
| min_w_pmos, 0); | |
| // output parasitic capacitance of | |
| // the min. sized driver | |
| double out_cap = drain_C_(min_w_pmos, PCH, 1, 1, g_tp.cell_h_def) + | |
| drain_C_(g_tp.min_w_nmos_, NCH, 1, 1, g_tp.cell_h_def); | |
| // drive resistance | |
| double out_res = (tr_R_on(g_tp.min_w_nmos_, NCH, 1) + | |
| tr_R_on(min_w_pmos, PCH, 1)) / 2; | |
| double wr = wire_res(len); //ohm | |
| // wire cap /m | |
| double wc = wire_cap(len); | |
| repeater_spacing = space; | |
| repeater_size = size; | |
| switching = (repeater_size * (input_cap + out_cap) + | |
| repeater_spacing * (wc / len)) * deviceType->Vdd * | |
| deviceType->Vdd; | |
| tc = out_res * (input_cap + out_cap) + | |
| out_res * wc / len * repeater_spacing / repeater_size + | |
| wr / len * repeater_spacing * out_cap * repeater_size + | |
| 0.5 * (wr / len) * (wc / len) * repeater_spacing * repeater_spacing; | |
| *delay = 0.693 * tc * len / repeater_spacing; | |
| #define Ishort_ckt 65e-6 /* across all tech Ref:Banerjee et al. {IEEE TED} */ | |
| short_ckt = deviceType->Vdd * g_tp.min_w_nmos_ * Ishort_ckt * 1.0986 * | |
| repeater_size * tc; | |
| ptemp.readOp.dynamic = ((len / repeater_spacing) * (switching + short_ckt)); | |
| ptemp.readOp.leakage = ((len / repeater_spacing) * | |
| deviceType->Vdd * | |
| cmos_Isub_leakage(g_tp.min_w_nmos_ * | |
| repeater_size, beta * | |
| g_tp.min_w_nmos_ * | |
| repeater_size, 1, inv)); | |
| ptemp.readOp.gate_leakage = ((len / repeater_spacing) * | |
| deviceType->Vdd * | |
| cmos_Ig_leakage(g_tp.min_w_nmos_ * | |
| repeater_size, beta * | |
| g_tp.min_w_nmos_ * | |
| repeater_size, 1, inv)); | |
| return ptemp; | |
| } | |
| void | |
| Wire::print_wire() { | |
| cout << "\nWire Properties:\n\n"; | |
| cout << " Delay Optimal\n\tRepeater size - " << global.area.h << | |
| " \n\tRepeater spacing - " << global.area.w*1e3 << " (mm)" | |
| " \n\tDelay - " << global.delay*1e6 << " (ns/mm)" | |
| " \n\tPowerD - " << global.power.readOp.dynamic *1e6 << " (nJ/mm)" | |
| " \n\tPowerL - " << global.power.readOp.leakage << " (mW/mm)" | |
| " \n\tPowerLgate - " << global.power.readOp.gate_leakage << | |
| " (mW/mm)\n"; | |
| cout << "\tWire width - " << wire_width_init*1e6 << " microns\n"; | |
| cout << "\tWire spacing - " << wire_spacing_init*1e6 << " microns\n"; | |
| cout << endl; | |
| cout << " 5% Overhead\n\tRepeater size - " << global_5.area.h << | |
| " \n\tRepeater spacing - " << global_5.area.w*1e3 << " (mm)" | |
| " \n\tDelay - " << global_5.delay *1e6 << " (ns/mm)" | |
| " \n\tPowerD - " << global_5.power.readOp.dynamic *1e6 << " (nJ/mm)" | |
| " \n\tPowerL - " << global_5.power.readOp.leakage << " (mW/mm)" | |
| " \n\tPowerLgate - " << global_5.power.readOp.gate_leakage << | |
| " (mW/mm)\n"; | |
| cout << "\tWire width - " << wire_width_init*1e6 << " microns\n"; | |
| cout << "\tWire spacing - " << wire_spacing_init*1e6 << " microns\n"; | |
| cout << endl; | |
| cout << " 10% Overhead\n\tRepeater size - " << global_10.area.h << | |
| " \n\tRepeater spacing - " << global_10.area.w*1e3 << " (mm)" | |
| " \n\tDelay - " << global_10.delay *1e6 << " (ns/mm)" | |
| " \n\tPowerD - " << global_10.power.readOp.dynamic *1e6 << " (nJ/mm)" | |
| " \n\tPowerL - " << global_10.power.readOp.leakage << " (mW/mm)" | |
| " \n\tPowerLgate - " << global_10.power.readOp.gate_leakage << | |
| " (mW/mm)\n"; | |
| cout << "\tWire width - " << wire_width_init*1e6 << " microns\n"; | |
| cout << "\tWire spacing - " << wire_spacing_init*1e6 << " microns\n"; | |
| cout << endl; | |
| cout << " 20% Overhead\n\tRepeater size - " << global_20.area.h << | |
| " \n\tRepeater spacing - " << global_20.area.w*1e3 << " (mm)" | |
| " \n\tDelay - " << global_20.delay *1e6 << " (ns/mm)" | |
| " \n\tPowerD - " << global_20.power.readOp.dynamic *1e6 << " (nJ/mm)" | |
| " \n\tPowerL - " << global_20.power.readOp.leakage << " (mW/mm)" | |
| " \n\tPowerLgate - " << global_20.power.readOp.gate_leakage << | |
| " (mW/mm)\n"; | |
| cout << "\tWire width - " << wire_width_init*1e6 << " microns\n"; | |
| cout << "\tWire spacing - " << wire_spacing_init*1e6 << " microns\n"; | |
| cout << endl; | |
| cout << " 30% Overhead\n\tRepeater size - " << global_30.area.h << | |
| " \n\tRepeater spacing - " << global_30.area.w*1e3 << " (mm)" | |
| " \n\tDelay - " << global_30.delay *1e6 << " (ns/mm)" | |
| " \n\tPowerD - " << global_30.power.readOp.dynamic *1e6 << " (nJ/mm)" | |
| " \n\tPowerL - " << global_30.power.readOp.leakage << " (mW/mm)" | |
| " \n\tPowerLgate - " << global_30.power.readOp.gate_leakage << | |
| " (mW/mm)\n"; | |
| cout << "\tWire width - " << wire_width_init*1e6 << " microns\n"; | |
| cout << "\tWire spacing - " << wire_spacing_init*1e6 << " microns\n"; | |
| cout << endl; | |
| cout << " Low-swing wire (1 mm) - Note: Unlike repeated wires, \n\t" << | |
| "delay and power values of low-swing wires do not\n\t" << | |
| "have a linear relationship with length." << | |
| " \n\tdelay - " << low_swing.delay *1e9 << " (ns)" | |
| " \n\tpowerD - " << low_swing.power.readOp.dynamic *1e9 << " (nJ)" | |
| " \n\tPowerL - " << low_swing.power.readOp.leakage << " (mW)" | |
| " \n\tPowerLgate - " << low_swing.power.readOp.gate_leakage << | |
| " (mW)\n"; | |
| cout << "\tWire width - " << wire_width_init * 2 /* differential */ << | |
| " microns\n"; | |
| cout << "\tWire spacing - " << wire_spacing_init * 2 /* differential */ << | |
| " microns\n"; | |
| cout << endl; | |
| cout << endl; | |
| } | |