text: /*****************************************************************************
   *                                McPAT
   *                      SOFTWARE LICENSE AGREEMENT
   *            Copyright 2012 Hewlett-Packard Development Company, L.P.
   *                          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 "interconnect.h"
  #include <assert.h>
  #include <iostream>
  #include "cacti/wire.h"
  #include "globalvar.h"
  
  interconnect::interconnect(string name_, enum Device_ty device_ty_,
                             double base_w, double base_h, int data_w, double len,
                             const InputParameter *configure_interface,
                             int start_wiring_level_, bool pipelinable_,
                             double route_over_perc_, bool opt_local_,
                             enum Core_type core_ty_, enum Wire_type wire_model,
                             double width_s, double space_s,
                             TechnologyParameter::DeviceType *dt)
      : name(name_),
        device_ty(device_ty_),
        in_rise_time(0),
        out_rise_time(0),
        base_width(base_w),
        base_height(base_h),
        data_width(data_w),
        wt(wire_model),
        width_scaling(width_s),
        space_scaling(space_s),
        start_wiring_level(start_wiring_level_),
        length(len),
        // interconnect_latency(1e-12),
        // interconnect_throughput(1e-12),
        opt_local(opt_local_),
        core_ty(core_ty_),
        pipelinable(pipelinable_),
        route_over_perc(route_over_perc_),
        deviceType(dt) {
    wt = Global;
    l_ip = *configure_interface;
    local_result = init_interface(&l_ip);
  
    max_unpipelined_link_delay = 0;  // TODO
    min_w_nmos = g_tp.min_w_nmos_;
    min_w_pmos = deviceType->n_to_p_eff_curr_drv_ratio * min_w_nmos;
  
    latency = l_ip.latency;
    throughput = l_ip.throughput;
    latency_overflow = false;
    throughput_overflow = false;
  
    /*
     * TODO: Add wiring option from semi-global to global automatically
     * And directly jump to global if semi-global cannot satisfy timing
     * Fat wires only available for global wires, thus
     * if signal wiring layer starts from semi-global,
     * the next layer up will be global, i.e., semi-global does
     * not have fat wires.
     */
    if (pipelinable == false)
    // Non-pipelinable wires, such as bypass logic, care latency
    {
      compute();
      if (opt_for_clk && opt_local) {
        while (delay > latency && width_scaling < 3.0) {
          width_scaling *= 2;
          space_scaling *= 2;
          Wire winit(width_scaling, space_scaling);
          compute();
        }
        if (delay > latency) {
          latency_overflow = true;
        }
      }
    }
    else  // Pipelinable wires, such as bus, does not care latency but throughput
    {
      /*
       * TODO: Add pipe regs power, area, and timing;
       * Pipelinable wires optimize latency first.
       */
      compute();
      if (opt_for_clk && opt_local) {
        while (delay > throughput && width_scaling < 3.0) {
          width_scaling *= 2;
          space_scaling *= 2;
          Wire winit(width_scaling, space_scaling);
          compute();
        }
        if (delay > throughput)
        // insert pipeline stages
        {
          num_pipe_stages = (int)ceil(delay / throughput);
          assert(num_pipe_stages > 0);
          delay = delay / num_pipe_stages + num_pipe_stages * 0.05 * delay;
        }
      }
    }
  
    power_bit = power;
    power.readOp.dynamic *= data_width;
    power.readOp.leakage *= data_width;
    power.readOp.gate_leakage *= data_width;
    area.set_area(area.get_area() * data_width);
    no_device_under_wire_area.h *= data_width;
  
    if (latency_overflow == true)
      cout << "Warning: " << name
           << " wire structure cannot satisfy latency constraint." << endl;
  
    assert(power.readOp.dynamic > 0);
    assert(power.readOp.leakage > 0);
    assert(power.readOp.gate_leakage > 0);
  
    double long_channel_device_reduction =
        longer_channel_device_reduction(device_ty, core_ty);
    double pg_reduction = power_gating_leakage_reduction(false);  //
  
    double sckRation = g_tp.sckt_co_eff;
    power.readOp.dynamic *= sckRation;
    power.writeOp.dynamic *= sckRation;
    power.searchOp.dynamic *= sckRation;
  
    power.readOp.longer_channel_leakage =
        power.readOp.leakage * long_channel_device_reduction;
  
    power.readOp.power_gated_leakage = power.readOp.leakage * pg_reduction;
  
    power.readOp.power_gated_with_long_channel_leakage =
        power.readOp.power_gated_leakage * long_channel_device_reduction;
  
    if (pipelinable)  // Only global wires has the option to choose whether
                      // routing over or not
      area.set_area(area.get_area() * route_over_perc +
                    no_device_under_wire_area.get_area() * (1 - route_over_perc));
  
    // Wire wreset();
  }
  
  void interconnect::compute() {
    Wire *wtemp1 = 0;
    wtemp1 = new Wire(wt, length, 1, width_scaling, space_scaling);
    delay = wtemp1->delay;
    power.readOp.dynamic = wtemp1->power.readOp.dynamic;
    power.readOp.leakage = wtemp1->power.readOp.leakage;
    power.readOp.gate_leakage = wtemp1->power.readOp.gate_leakage;
  
    area.set_area(wtemp1->area.get_area());
    no_device_under_wire_area.h = (wtemp1->wire_width + wtemp1->wire_spacing);
    no_device_under_wire_area.w = length;
  
    if (wtemp1)
      delete wtemp1;
  }
  
  void interconnect::leakage_feedback(
      double temperature)  // TODO: add code for processing power gating
  {
    l_ip.temp = (unsigned int)round(temperature / 10.0) * 10;
    uca_org_t init_result = init_interface(&l_ip);  // init_result is dummy
  
    compute();
  
    power_bit = power;
    power.readOp.dynamic *= data_width;
    power.readOp.leakage *= data_width;
    power.readOp.gate_leakage *= data_width;
  
    assert(power.readOp.dynamic > 0);
    assert(power.readOp.leakage > 0);
    assert(power.readOp.gate_leakage > 0);
  
    double long_channel_device_reduction =
        longer_channel_device_reduction(device_ty, core_ty);
  
    double sckRation = g_tp.sckt_co_eff;
    power.readOp.dynamic *= sckRation;
    power.writeOp.dynamic *= sckRation;
    power.searchOp.dynamic *= sckRation;
  
    power.readOp.longer_channel_leakage =
        power.readOp.leakage * long_channel_device_reduction;
  }
  