| /***************************************************************************** |
| * 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; |
| |
| } |
| |