384 lines
14 KiB
C++
384 lines
14 KiB
C++
/*
|
|
* Copyright (c) 2009 Princeton University
|
|
* Copyright (c) 2009 The Regents of the University of California
|
|
* 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.
|
|
*
|
|
* Authors: Hangsheng Wang (Orion 1.0, Princeton)
|
|
* Xinping Zhu (Orion 1.0, Princeton)
|
|
* Xuning Chen (Orion 1.0, Princeton)
|
|
* Bin Li (Orion 2.0, Princeton)
|
|
* Kambiz Samadi (Orion 2.0, UC San Diego)
|
|
*/
|
|
|
|
#include <cmath>
|
|
#include <cstdlib>
|
|
#include <iostream>
|
|
|
|
#include "base/misc.hh"
|
|
#include "mem/ruby/network/orion/TechParameter.hh"
|
|
#include "mem/ruby/network/orion/Wire.hh"
|
|
|
|
using namespace std;
|
|
|
|
Wire::Wire(
|
|
const string& wire_spacing_model_str_,
|
|
const string& buf_scheme_str_,
|
|
bool is_shielding_,
|
|
const TechParameter* tech_param_ptr_
|
|
)
|
|
{
|
|
set_width_spacing_model(wire_spacing_model_str_);
|
|
set_buf_scheme(buf_scheme_str_);
|
|
|
|
m_is_shielding = is_shielding_;
|
|
|
|
m_tech_param_ptr = tech_param_ptr_;
|
|
|
|
if (m_tech_param_ptr->get_tech_node() > 90)
|
|
{
|
|
cerr << "ERROR: Wire model only support tech node <= 90" << endl;
|
|
exit(1);
|
|
}
|
|
|
|
init();
|
|
}
|
|
|
|
Wire::~Wire()
|
|
{}
|
|
|
|
// OPTIMUM K and H CALCULATION
|
|
// Computes the optimum number and size of repeaters for the link
|
|
void Wire::calc_opt_buffering(
|
|
int* k_,
|
|
double* h_,
|
|
double len_
|
|
) const
|
|
{
|
|
double BufferDriveResistance = m_tech_param_ptr->get_BufferDriveResistance();
|
|
double BufferInputCapacitance = m_tech_param_ptr->get_BufferInputCapacitance();
|
|
switch(m_buf_scheme)
|
|
{
|
|
case MIN_DELAY:
|
|
{
|
|
if (m_is_shielding)
|
|
{
|
|
double r = m_res_unit_len*len_;
|
|
double c_g = 2*m_gnd_cap_unit_len*len_;
|
|
double c_c = 2*m_couple_cap_unit_len*len_;
|
|
*k_ = (int) sqrt(((0.4*r*c_g)+(0.57*r*c_c))/
|
|
(0.7*BufferDriveResistance*BufferInputCapacitance)); //k is the number of buffers to be inserted
|
|
*h_ = sqrt(((0.7*BufferDriveResistance*c_g)+
|
|
(1.4*1.5*BufferDriveResistance*c_c))/(0.7*r*BufferInputCapacitance)); //the size of the buffers to be inserted
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
double r = m_res_unit_len*len_;
|
|
double c_g = 2*m_gnd_cap_unit_len*len_;
|
|
double c_c = 2*m_couple_cap_unit_len*len_;
|
|
*k_ = (int) sqrt(((0.4*r*c_g)+(1.51*r*c_c))/
|
|
(0.7*BufferDriveResistance*BufferInputCapacitance));
|
|
*h_ = sqrt(((0.7*BufferDriveResistance*c_g)+
|
|
(1.4*2.2*BufferDriveResistance*c_c))/(0.7*r*BufferInputCapacitance));
|
|
break;
|
|
}
|
|
}
|
|
case STAGGERED:
|
|
{
|
|
double r = m_res_unit_len*len_;
|
|
double c_g = 2*m_gnd_cap_unit_len*len_;
|
|
double c_c = 2*m_couple_cap_unit_len*len_;
|
|
|
|
*k_ = (int) sqrt(((0.4*r*c_g)+(0.57*r*c_c))/
|
|
(0.7*BufferDriveResistance*BufferInputCapacitance));
|
|
*h_ = sqrt(((0.7*BufferDriveResistance*c_g)+
|
|
(1.4*1.5*BufferDriveResistance*c_c))/(0.7*r*BufferInputCapacitance));
|
|
break;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
double Wire::calc_dynamic_energy(double len_) const
|
|
{
|
|
|
|
double c_g = 2*m_gnd_cap_unit_len*len_;
|
|
double c_c = 2*m_couple_cap_unit_len*len_;
|
|
double cap_wire = c_g + c_c;
|
|
|
|
int k;
|
|
double h;
|
|
|
|
calc_opt_buffering(&k, &h, len_);
|
|
|
|
double BufferInputCapacitance = m_tech_param_ptr->get_BufferInputCapacitance();
|
|
double cap_buf = ((double)k)*BufferInputCapacitance*h;
|
|
|
|
double e_factor = m_tech_param_ptr->get_EnergyFactor();
|
|
return ((cap_wire+cap_buf)*e_factor);
|
|
}
|
|
|
|
double Wire::calc_static_power(double len_) const
|
|
{
|
|
int k;
|
|
double h;
|
|
calc_opt_buffering(&k, &h, len_);
|
|
|
|
double BufferNMOSOffCurrent = m_tech_param_ptr->get_BufferNMOSOffCurrent();
|
|
double BufferPMOSOffCurrent = m_tech_param_ptr->get_BufferPMOSOffCurrent();
|
|
double i_static_nmos = BufferNMOSOffCurrent*h*k;
|
|
double i_static_pmos = BufferPMOSOffCurrent*h*k;
|
|
|
|
double vdd = m_tech_param_ptr->get_vdd();
|
|
return (vdd*(i_static_pmos+i_static_nmos)/2);
|
|
}
|
|
|
|
void Wire::init()
|
|
{
|
|
m_res_unit_len = calc_res_unit_len();
|
|
m_gnd_cap_unit_len = calc_gnd_cap_unit_len();
|
|
m_couple_cap_unit_len = calc_couple_cap_unit_len();
|
|
return;
|
|
}
|
|
|
|
void Wire::set_width_spacing_model(
|
|
const string& wire_spacing_model_str_
|
|
)
|
|
{
|
|
if (wire_spacing_model_str_ == string("SWIDTH_SSPACE"))
|
|
{
|
|
m_width_spacing_model = SWIDTH_SSPACE;
|
|
}
|
|
else if (wire_spacing_model_str_ == string("SWIDTH_DSPACE"))
|
|
{
|
|
m_width_spacing_model = SWIDTH_DSPACE;
|
|
}
|
|
else if (wire_spacing_model_str_ == string("DWIDTH_SSPACE"))
|
|
{
|
|
m_width_spacing_model = DWIDTH_SSPACE;
|
|
}
|
|
else if (wire_spacing_model_str_ == string("DWIDTH_DSPACE"))
|
|
{
|
|
m_width_spacing_model = DWIDTH_DSPACE;
|
|
}
|
|
else
|
|
{
|
|
cerr << "ERROR: Invalid wire width/spacing model" << endl;
|
|
exit(1);
|
|
}
|
|
return;
|
|
}
|
|
|
|
void Wire::set_buf_scheme(
|
|
const string& buf_scheme_str_
|
|
)
|
|
{
|
|
if (buf_scheme_str_ == string("MIN_DELAY"))
|
|
{
|
|
m_buf_scheme = MIN_DELAY;
|
|
}
|
|
else if (buf_scheme_str_ == string("STAGGERED"))
|
|
{
|
|
m_buf_scheme = STAGGERED;
|
|
}
|
|
else
|
|
{
|
|
cerr << "ERROR: Invalid wire buf scheme" << endl;
|
|
exit(1);
|
|
}
|
|
return;
|
|
}
|
|
|
|
// The following function computes the wire resistance considering
|
|
// width-spacing combination and a width-dependent resistivity model
|
|
double Wire::calc_res_unit_len()
|
|
{
|
|
double r = -1.0;
|
|
double rho;
|
|
// r, rho is in ohm.m
|
|
|
|
double WireMinWidth = m_tech_param_ptr->get_WireMinWidth();
|
|
double WireBarrierThickness = m_tech_param_ptr->get_WireBarrierThickness();
|
|
double WireMetalThickness = m_tech_param_ptr->get_WireMetalThickness();
|
|
|
|
switch(m_width_spacing_model)
|
|
{
|
|
case SWIDTH_SSPACE:
|
|
case SWIDTH_DSPACE:
|
|
rho = 2.202e-8 + (1.030e-15 / (WireMinWidth - 2*WireBarrierThickness));
|
|
r = ((rho) / ((WireMinWidth - 2*WireBarrierThickness) *
|
|
(WireMetalThickness - WireBarrierThickness)));
|
|
break;
|
|
case DWIDTH_SSPACE:
|
|
case DWIDTH_DSPACE:
|
|
rho = 2.202e-8 + (1.030e-15 / (2*WireMinWidth - 2*WireBarrierThickness));
|
|
r = ((rho) / ((2*WireMinWidth - 2*WireBarrierThickness) *
|
|
(WireMetalThickness - WireBarrierThickness)));
|
|
break;
|
|
default:
|
|
warn("Orion: Width spacing model not found: %s\n", m_width_spacing_model);
|
|
r = 1.0;
|
|
}
|
|
return r;
|
|
}
|
|
|
|
// COMPUTE WIRE CAPACITANCE using PTM models
|
|
double Wire::calc_gnd_cap_unit_len()
|
|
{
|
|
// c_g is in F
|
|
double c_g = -1.0;
|
|
|
|
double WireMinWidth = m_tech_param_ptr->get_WireMinWidth();
|
|
double WireMinSpacing = m_tech_param_ptr->get_WireMinSpacing();
|
|
double WireMetalThickness = m_tech_param_ptr->get_WireMetalThickness();
|
|
double WireDielectricThickness = m_tech_param_ptr->get_WireDielectricThickness();
|
|
double WireDielectricConstant = m_tech_param_ptr->get_WireDielectricConstant();
|
|
|
|
switch(m_width_spacing_model)
|
|
{
|
|
case SWIDTH_SSPACE:
|
|
{
|
|
double A = (WireMinWidth/WireDielectricThickness);
|
|
double B = 2.04*pow((WireMinSpacing/(WireMinSpacing +
|
|
0.54*WireDielectricThickness)), 1.77);
|
|
double C = pow((WireMetalThickness/(WireMetalThickness +
|
|
4.53*WireDielectricThickness)), 0.07);
|
|
c_g = WireDielectricConstant*8.85e-12*(A+(B*C));
|
|
break;
|
|
}
|
|
case SWIDTH_DSPACE:
|
|
{
|
|
double minSpacingNew = 2*WireMinSpacing + WireMinWidth;
|
|
double A = (WireMinWidth/WireDielectricThickness);
|
|
double B = 2.04*pow((minSpacingNew/(minSpacingNew +
|
|
0.54*WireDielectricThickness)), 1.77);
|
|
double C = pow((WireMetalThickness/(WireMetalThickness +
|
|
4.53*WireDielectricThickness)), 0.07);
|
|
c_g = WireDielectricConstant*8.85e-12*(A+(B*C));
|
|
break;
|
|
}
|
|
case DWIDTH_SSPACE:
|
|
{
|
|
double minWidthNew = 2*WireMinWidth;
|
|
double A = (minWidthNew/WireDielectricThickness);
|
|
double B = 2.04*pow((WireMinSpacing/(WireMinSpacing +
|
|
0.54*WireDielectricThickness)), 1.77);
|
|
double C = pow((WireMetalThickness/(WireMetalThickness +
|
|
4.53*WireDielectricThickness)), 0.07);
|
|
c_g = WireDielectricConstant*8.85e-12*(A+(B*C));
|
|
break;
|
|
}
|
|
case DWIDTH_DSPACE:
|
|
{
|
|
double minWidthNew = 2*WireMinWidth;
|
|
double minSpacingNew = 2*WireMinSpacing;
|
|
double A = (minWidthNew/WireDielectricThickness);
|
|
double B = 2.04*pow((minSpacingNew/(minSpacingNew+
|
|
0.54*WireDielectricThickness)), 1.77);
|
|
double C = pow((WireMetalThickness/(WireMetalThickness +
|
|
4.53*WireDielectricThickness)), 0.07);
|
|
c_g = WireDielectricConstant*8.85e-12*(A+(B*C));
|
|
break;
|
|
}
|
|
default:
|
|
warn("Orion: Width spacing model not found: %s\n", m_width_spacing_model);
|
|
c_g = 1.0;
|
|
}
|
|
|
|
return c_g;
|
|
}
|
|
|
|
// Computes the coupling capacitance considering cross-talk
|
|
double Wire::calc_couple_cap_unit_len()
|
|
{
|
|
//c_c is in F
|
|
double c_c = -1.0;
|
|
|
|
double WireMinWidth = m_tech_param_ptr->get_WireMinWidth();
|
|
double WireMinSpacing = m_tech_param_ptr->get_WireMinSpacing();
|
|
double WireMetalThickness = m_tech_param_ptr->get_WireMetalThickness();
|
|
double WireDielectricThickness = m_tech_param_ptr->get_WireDielectricThickness();
|
|
double WireDielectricConstant = m_tech_param_ptr->get_WireDielectricConstant();
|
|
|
|
switch(m_width_spacing_model)
|
|
{
|
|
case SWIDTH_SSPACE:
|
|
{
|
|
double A = 1.14*(WireMetalThickness/WireMinSpacing) *
|
|
exp(-4*WireMinSpacing/(WireMinSpacing + 8.01*WireDielectricThickness));
|
|
double B = 2.37*pow((WireMinWidth/(WireMinWidth + 0.31*WireMinSpacing)), 0.28);
|
|
double C = pow((WireDielectricThickness/(WireDielectricThickness +
|
|
8.96*WireMinSpacing)), 0.76) *
|
|
exp(-2*WireMinSpacing/(WireMinSpacing + 6*WireDielectricThickness));
|
|
c_c = WireDielectricConstant*8.85e-12*(A + (B*C));
|
|
break;
|
|
}
|
|
case SWIDTH_DSPACE:
|
|
{
|
|
double minSpacingNew = 2*WireMinSpacing + WireMinWidth;
|
|
double A = 1.14*(WireMetalThickness/minSpacingNew) *
|
|
exp(-4*minSpacingNew/(minSpacingNew + 8.01*WireDielectricThickness));
|
|
double B = 2.37*pow((WireMinWidth/(WireMinWidth + 0.31*minSpacingNew)), 0.28);
|
|
double C = pow((WireDielectricThickness/(WireDielectricThickness +
|
|
8.96*minSpacingNew)), 0.76) *
|
|
exp(-2*minSpacingNew/(minSpacingNew + 6*WireDielectricThickness));
|
|
c_c = WireDielectricConstant*8.85e-12*(A + (B*C));
|
|
break;
|
|
}
|
|
case DWIDTH_SSPACE:
|
|
{
|
|
double minWidthNew = 2*WireMinWidth;
|
|
double A = 1.14*(WireMetalThickness/WireMinSpacing) *
|
|
exp(-4*WireMinSpacing/(WireMinSpacing + 8.01*WireDielectricThickness));
|
|
double B = 2.37*pow((2*minWidthNew/(2*minWidthNew + 0.31*WireMinSpacing)), 0.28);
|
|
double C = pow((WireDielectricThickness/(WireDielectricThickness +
|
|
8.96*WireMinSpacing)), 0.76) *
|
|
exp(-2*WireMinSpacing/(WireMinSpacing + 6*WireDielectricThickness));
|
|
c_c = WireDielectricConstant*8.85e-12*(A + (B*C));
|
|
break;
|
|
}
|
|
case DWIDTH_DSPACE:
|
|
{
|
|
double minWidthNew = 2*WireMinWidth;
|
|
double minSpacingNew = 2*WireMinSpacing;
|
|
double A = 1.14*(WireMetalThickness/minSpacingNew) *
|
|
exp(-4*minSpacingNew/(minSpacingNew + 8.01*WireDielectricThickness));
|
|
double B = 2.37*pow((minWidthNew/(minWidthNew + 0.31*minSpacingNew)), 0.28);
|
|
double C = pow((WireDielectricThickness/(WireDielectricThickness +
|
|
8.96*minSpacingNew)), 0.76) *
|
|
exp(-2*minSpacingNew/(minSpacingNew + 6*WireDielectricThickness));
|
|
c_c = WireDielectricConstant*8.85e-12*(A + (B*C));
|
|
break;
|
|
}
|
|
default:
|
|
warn("Orion: Width spacing model not found: %s\n", m_width_spacing_model);
|
|
c_c = 1.0;
|
|
}
|
|
|
|
return c_c;
|
|
}
|
|
|