blob: 7fa66b4ff6c7748dc3015f8493f798f1d16fa434 [file] [log] [blame]
/*****************************************************************************
* 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 <cassert>
#include <cmath>
#include <iostream>
#include "area.h"
#include "decoder.h"
#include "parameter.h"
using namespace std;
Decoder::Decoder(
int _num_dec_signals,
bool flag_way_select,
double _C_ld_dec_out,
double _R_wire_dec_out,
bool fully_assoc_,
bool is_dram_,
bool is_wl_tr_,
const Area & cell_)
: exist(false),
C_ld_dec_out(_C_ld_dec_out),
R_wire_dec_out(_R_wire_dec_out),
num_gates(0), num_gates_min(2),
delay(0),
//power(),
fully_assoc(fully_assoc_), is_dram(is_dram_),
is_wl_tr(is_wl_tr_), cell(cell_) {
for (int i = 0; i < MAX_NUMBER_GATES_STAGE; i++) {
w_dec_n[i] = 0;
w_dec_p[i] = 0;
}
/*
* _num_dec_signals is the number of decoded signal as output
* num_addr_bits_dec is the number of signal to be decoded
* as the decoders input.
*/
int num_addr_bits_dec = _log2(_num_dec_signals);
if (num_addr_bits_dec < 4) {
if (flag_way_select) {
exist = true;
num_in_signals = 2;
} else {
num_in_signals = 0;
}
} else {
exist = true;
if (flag_way_select) {
num_in_signals = 3;
} else {
num_in_signals = 2;
}
}
assert(cell.h > 0);
assert(cell.w > 0);
// the height of a row-decoder-driver cell is fixed to be 4 * cell.h;
//area.h = 4 * cell.h;
area.h = g_tp.h_dec * cell.h;
compute_widths();
compute_area();
}
void Decoder::compute_widths() {
double F;
double p_to_n_sz_ratio = pmos_to_nmos_sz_ratio(is_dram, is_wl_tr);
double gnand2 = (2 + p_to_n_sz_ratio) / (1 + p_to_n_sz_ratio);
double gnand3 = (3 + p_to_n_sz_ratio) / (1 + p_to_n_sz_ratio);
if (exist) {
if (num_in_signals == 2 || fully_assoc) {
w_dec_n[0] = 2 * g_tp.min_w_nmos_;
w_dec_p[0] = p_to_n_sz_ratio * g_tp.min_w_nmos_;
F = gnand2;
} else {
w_dec_n[0] = 3 * g_tp.min_w_nmos_;
w_dec_p[0] = p_to_n_sz_ratio * g_tp.min_w_nmos_;
F = gnand3;
}
F *= C_ld_dec_out / (gate_C(w_dec_n[0], 0, is_dram, false, is_wl_tr) +
gate_C(w_dec_p[0], 0, is_dram, false, is_wl_tr));
num_gates = logical_effort(
num_gates_min,
num_in_signals == 2 ? gnand2 : gnand3,
F,
w_dec_n,
w_dec_p,
C_ld_dec_out,
p_to_n_sz_ratio,
is_dram,
is_wl_tr,
g_tp.max_w_nmos_dec);
}
}
void Decoder::compute_area() {
double cumulative_area = 0;
double cumulative_curr = 0; // cumulative leakage current
double cumulative_curr_Ig = 0; // cumulative leakage current
if (exist) { // First check if this decoder exists
if (num_in_signals == 2) {
cumulative_area =
compute_gate_area(NAND, 2, w_dec_p[0], w_dec_n[0], area.h);
cumulative_curr =
cmos_Isub_leakage(w_dec_n[0], w_dec_p[0], 2, nand, is_dram);
cumulative_curr_Ig =
cmos_Ig_leakage(w_dec_n[0], w_dec_p[0], 2, nand, is_dram);
} else if (num_in_signals == 3) {
cumulative_area =
compute_gate_area(NAND, 3, w_dec_p[0], w_dec_n[0], area.h);
cumulative_curr =
cmos_Isub_leakage(w_dec_n[0], w_dec_p[0], 3, nand, is_dram);;
cumulative_curr_Ig =
cmos_Ig_leakage(w_dec_n[0], w_dec_p[0], 3, nand, is_dram);
}
for (int i = 1; i < num_gates; i++) {
cumulative_area +=
compute_gate_area(INV, 1, w_dec_p[i], w_dec_n[i], area.h);
cumulative_curr +=
cmos_Isub_leakage(w_dec_n[i], w_dec_p[i], 1, inv, is_dram);
cumulative_curr_Ig =
cmos_Ig_leakage(w_dec_n[i], w_dec_p[i], 1, inv, is_dram);
}
power.readOp.leakage = cumulative_curr * g_tp.peri_global.Vdd;
power.readOp.gate_leakage = cumulative_curr_Ig * g_tp.peri_global.Vdd;
area.w = (cumulative_area / area.h);
}
}
double Decoder::compute_delays(double inrisetime) {
if (exist) {
double ret_val = 0; // outrisetime
int i;
double rd, tf, this_delay, c_load, c_intrinsic, Vpp;
double Vdd = g_tp.peri_global.Vdd;
if ((is_wl_tr) && (is_dram)) {
Vpp = g_tp.vpp;
} else if (is_wl_tr) {
Vpp = g_tp.sram_cell.Vdd;
} else {
Vpp = g_tp.peri_global.Vdd;
}
// first check whether a decoder is required at all
rd = tr_R_on(w_dec_n[0], NCH, num_in_signals, is_dram, false, is_wl_tr);
c_load = gate_C(w_dec_n[1] + w_dec_p[1], 0.0, is_dram, false, is_wl_tr);
c_intrinsic = drain_C_(w_dec_p[0], PCH, 1, 1, area.h, is_dram, false, is_wl_tr) * num_in_signals +
drain_C_(w_dec_n[0], NCH, num_in_signals, 1, area.h, is_dram, false, is_wl_tr);
tf = rd * (c_intrinsic + c_load);
this_delay = horowitz(inrisetime, tf, 0.5, 0.5, RISE);
delay += this_delay;
inrisetime = this_delay / (1.0 - 0.5);
power.readOp.dynamic += (c_load + c_intrinsic) * Vdd * Vdd;
for (i = 1; i < num_gates - 1; ++i) {
rd = tr_R_on(w_dec_n[i], NCH, 1, is_dram, false, is_wl_tr);
c_load = gate_C(w_dec_p[i+1] + w_dec_n[i+1], 0.0, is_dram, false, is_wl_tr);
c_intrinsic = drain_C_(w_dec_p[i], PCH, 1, 1, area.h, is_dram, false, is_wl_tr) +
drain_C_(w_dec_n[i], NCH, 1, 1, area.h, is_dram, false, is_wl_tr);
tf = rd * (c_intrinsic + c_load);
this_delay = horowitz(inrisetime, tf, 0.5, 0.5, RISE);
delay += this_delay;
inrisetime = this_delay / (1.0 - 0.5);
power.readOp.dynamic += (c_load + c_intrinsic) * Vdd * Vdd;
}
// add delay of final inverter that drives the wordline
i = num_gates - 1;
c_load = C_ld_dec_out;
rd = tr_R_on(w_dec_n[i], NCH, 1, is_dram, false, is_wl_tr);
c_intrinsic = drain_C_(w_dec_p[i], PCH, 1, 1, area.h, is_dram, false, is_wl_tr) +
drain_C_(w_dec_n[i], NCH, 1, 1, area.h, is_dram, false, is_wl_tr);
tf = rd * (c_intrinsic + c_load) + R_wire_dec_out * c_load / 2;
this_delay = horowitz(inrisetime, tf, 0.5, 0.5, RISE);
delay += this_delay;
ret_val = this_delay / (1.0 - 0.5);
power.readOp.dynamic += c_load * Vpp * Vpp + c_intrinsic * Vdd * Vdd;
return ret_val;
} else {
return 0.0;
}
}
void Decoder::leakage_feedback(double temperature)
{
double cumulative_curr = 0; // cumulative leakage current
double cumulative_curr_Ig = 0; // cumulative leakage current
if (exist)
{ // First check if this decoder exists
if (num_in_signals == 2)
{
cumulative_curr = cmos_Isub_leakage(w_dec_n[0], w_dec_p[0], 2, nand,is_dram);
cumulative_curr_Ig = cmos_Ig_leakage(w_dec_n[0], w_dec_p[0], 2, nand,is_dram);
}
else if (num_in_signals == 3)
{
cumulative_curr = cmos_Isub_leakage(w_dec_n[0], w_dec_p[0], 3, nand, is_dram);;
cumulative_curr_Ig = cmos_Ig_leakage(w_dec_n[0], w_dec_p[0], 3, nand, is_dram);
}
for (int i = 1; i < num_gates; i++)
{
cumulative_curr += cmos_Isub_leakage(w_dec_n[i], w_dec_p[i], 1, inv, is_dram);
cumulative_curr_Ig = cmos_Ig_leakage(w_dec_n[i], w_dec_p[i], 1, inv, is_dram);
}
power.readOp.leakage = cumulative_curr * g_tp.peri_global.Vdd;
power.readOp.gate_leakage = cumulative_curr_Ig * g_tp.peri_global.Vdd;
}
}
PredecBlk::PredecBlk(
int num_dec_signals,
Decoder * dec_,
double C_wire_predec_blk_out,
double R_wire_predec_blk_out_,
int num_dec_per_predec,
bool is_dram,
bool is_blk1)
: dec(dec_),
exist(false),
number_input_addr_bits(0),
C_ld_predec_blk_out(0),
R_wire_predec_blk_out(0),
branch_effort_nand2_gate_output(1),
branch_effort_nand3_gate_output(1),
flag_two_unique_paths(false),
flag_L2_gate(0),
number_inputs_L1_gate(0),
number_gates_L1_nand2_path(0),
number_gates_L1_nand3_path(0),
number_gates_L2(0),
min_number_gates_L1(2),
min_number_gates_L2(2),
num_L1_active_nand2_path(0),
num_L1_active_nand3_path(0),
delay_nand2_path(0),
delay_nand3_path(0),
power_nand2_path(),
power_nand3_path(),
power_L2(),
is_dram_(is_dram) {
int branch_effort_predec_out;
double C_ld_dec_gate;
int num_addr_bits_dec = _log2(num_dec_signals);
int blk1_num_input_addr_bits = (num_addr_bits_dec + 1) / 2;
int blk2_num_input_addr_bits = num_addr_bits_dec - blk1_num_input_addr_bits;
w_L1_nand2_n[0] = 0;
w_L1_nand2_p[0] = 0;
w_L1_nand3_n[0] = 0;
w_L1_nand3_p[0] = 0;
if (is_blk1 == true) {
if (num_addr_bits_dec <= 0) {
return;
} else if (num_addr_bits_dec < 4) {
// Just one predecoder block is required with NAND2 gates. No decoder required.
// The first level of predecoding directly drives the decoder output load
exist = true;
number_input_addr_bits = num_addr_bits_dec;
R_wire_predec_blk_out = dec->R_wire_dec_out;
C_ld_predec_blk_out = dec->C_ld_dec_out;
} else {
exist = true;
number_input_addr_bits = blk1_num_input_addr_bits;
branch_effort_predec_out = (1 << blk2_num_input_addr_bits);
C_ld_dec_gate = num_dec_per_predec * gate_C(dec->w_dec_n[0] + dec->w_dec_p[0], 0, is_dram_, false, false);
R_wire_predec_blk_out = R_wire_predec_blk_out_;
C_ld_predec_blk_out = branch_effort_predec_out * C_ld_dec_gate + C_wire_predec_blk_out;
}
} else {
if (num_addr_bits_dec >= 4) {
exist = true;
number_input_addr_bits = blk2_num_input_addr_bits;
branch_effort_predec_out = (1 << blk1_num_input_addr_bits);
C_ld_dec_gate = num_dec_per_predec * gate_C(dec->w_dec_n[0] + dec->w_dec_p[0], 0, is_dram_, false, false);
R_wire_predec_blk_out = R_wire_predec_blk_out_;
C_ld_predec_blk_out = branch_effort_predec_out * C_ld_dec_gate + C_wire_predec_blk_out;
}
}
compute_widths();
compute_area();
}
void PredecBlk::compute_widths() {
double F, c_load_nand3_path, c_load_nand2_path;
double p_to_n_sz_ratio = pmos_to_nmos_sz_ratio(is_dram_);
double gnand2 = (2 + p_to_n_sz_ratio) / (1 + p_to_n_sz_ratio);
double gnand3 = (3 + p_to_n_sz_ratio) / (1 + p_to_n_sz_ratio);
if (exist == false) return;
switch (number_input_addr_bits) {
case 1:
flag_two_unique_paths = false;
number_inputs_L1_gate = 2;
flag_L2_gate = 0;
break;
case 2:
flag_two_unique_paths = false;
number_inputs_L1_gate = 2;
flag_L2_gate = 0;
break;
case 3:
flag_two_unique_paths = false;
number_inputs_L1_gate = 3;
flag_L2_gate = 0;
break;
case 4:
flag_two_unique_paths = false;
number_inputs_L1_gate = 2;
flag_L2_gate = 2;
branch_effort_nand2_gate_output = 4;
break;
case 5:
flag_two_unique_paths = true;
flag_L2_gate = 2;
branch_effort_nand2_gate_output = 8;
branch_effort_nand3_gate_output = 4;
break;
case 6:
flag_two_unique_paths = false;
number_inputs_L1_gate = 3;
flag_L2_gate = 2;
branch_effort_nand3_gate_output = 8;
break;
case 7:
flag_two_unique_paths = true;
flag_L2_gate = 3;
branch_effort_nand2_gate_output = 32;
branch_effort_nand3_gate_output = 16;
break;
case 8:
flag_two_unique_paths = true;
flag_L2_gate = 3;
branch_effort_nand2_gate_output = 64;
branch_effort_nand3_gate_output = 32;
break;
case 9:
flag_two_unique_paths = false;
number_inputs_L1_gate = 3;
flag_L2_gate = 3;
branch_effort_nand3_gate_output = 64;
break;
default:
assert(0);
break;
}
// find the number of gates and sizing in second level of predecoder (if there is a second level)
if (flag_L2_gate) {
if (flag_L2_gate == 2) { // 2nd level is a NAND2 gate
w_L2_n[0] = 2 * g_tp.min_w_nmos_;
F = gnand2;
} else { // 2nd level is a NAND3 gate
w_L2_n[0] = 3 * g_tp.min_w_nmos_;
F = gnand3;
}
w_L2_p[0] = p_to_n_sz_ratio * g_tp.min_w_nmos_;
F *= C_ld_predec_blk_out / (gate_C(w_L2_n[0], 0, is_dram_) + gate_C(w_L2_p[0], 0, is_dram_));
number_gates_L2 = logical_effort(
min_number_gates_L2,
flag_L2_gate == 2 ? gnand2 : gnand3,
F,
w_L2_n,
w_L2_p,
C_ld_predec_blk_out,
p_to_n_sz_ratio,
is_dram_, false,
g_tp.max_w_nmos_);
// Now find the number of gates and widths in first level of predecoder
if ((flag_two_unique_paths) || (number_inputs_L1_gate == 2)) {
// Whenever flag_two_unique_paths is true, it means first level of
// decoder employs
// both NAND2 and NAND3 gates. Or when number_inputs_L1_gate is 2,
// it means
// a NAND2 gate is used in the first level of the predecoder
c_load_nand2_path = branch_effort_nand2_gate_output *
(gate_C(w_L2_n[0], 0, is_dram_) +
gate_C(w_L2_p[0], 0, is_dram_));
w_L1_nand2_n[0] = 2 * g_tp.min_w_nmos_;
w_L1_nand2_p[0] = p_to_n_sz_ratio * g_tp.min_w_nmos_;
F = gnand2 * c_load_nand2_path /
(gate_C(w_L1_nand2_n[0], 0, is_dram_) +
gate_C(w_L1_nand2_p[0], 0, is_dram_));
number_gates_L1_nand2_path = logical_effort(
min_number_gates_L1,
gnand2,
F,
w_L1_nand2_n,
w_L1_nand2_p,
c_load_nand2_path,
p_to_n_sz_ratio,
is_dram_, false,
g_tp.max_w_nmos_);
}
//Now find widths of gates along path in which first gate is a NAND3
if ((flag_two_unique_paths) || (number_inputs_L1_gate == 3)) { // Whenever flag_two_unique_paths is TRUE, it means first level of decoder employs
// both NAND2 and NAND3 gates. Or when number_inputs_L1_gate is 3, it means
// a NAND3 gate is used in the first level of the predecoder
c_load_nand3_path = branch_effort_nand3_gate_output *
(gate_C(w_L2_n[0], 0, is_dram_) +
gate_C(w_L2_p[0], 0, is_dram_));
w_L1_nand3_n[0] = 3 * g_tp.min_w_nmos_;
w_L1_nand3_p[0] = p_to_n_sz_ratio * g_tp.min_w_nmos_;
F = gnand3 * c_load_nand3_path /
(gate_C(w_L1_nand3_n[0], 0, is_dram_) +
gate_C(w_L1_nand3_p[0], 0, is_dram_));
number_gates_L1_nand3_path = logical_effort(
min_number_gates_L1,
gnand3,
F,
w_L1_nand3_n,
w_L1_nand3_p,
c_load_nand3_path,
p_to_n_sz_ratio,
is_dram_, false,
g_tp.max_w_nmos_);
}
} else { // find number of gates and widths in first level of predecoder block when there is no second level
if (number_inputs_L1_gate == 2) {
w_L1_nand2_n[0] = 2 * g_tp.min_w_nmos_;
w_L1_nand2_p[0] = p_to_n_sz_ratio * g_tp.min_w_nmos_;
F = gnand2 * C_ld_predec_blk_out /
(gate_C(w_L1_nand2_n[0], 0, is_dram_) +
gate_C(w_L1_nand2_p[0], 0, is_dram_));
number_gates_L1_nand2_path = logical_effort(
min_number_gates_L1,
gnand2,
F,
w_L1_nand2_n,
w_L1_nand2_p,
C_ld_predec_blk_out,
p_to_n_sz_ratio,
is_dram_, false,
g_tp.max_w_nmos_);
} else if (number_inputs_L1_gate == 3) {
w_L1_nand3_n[0] = 3 * g_tp.min_w_nmos_;
w_L1_nand3_p[0] = p_to_n_sz_ratio * g_tp.min_w_nmos_;
F = gnand3 * C_ld_predec_blk_out /
(gate_C(w_L1_nand3_n[0], 0, is_dram_) +
gate_C(w_L1_nand3_p[0], 0, is_dram_));
number_gates_L1_nand3_path = logical_effort(
min_number_gates_L1,
gnand3,
F,
w_L1_nand3_n,
w_L1_nand3_p,
C_ld_predec_blk_out,
p_to_n_sz_ratio,
is_dram_, false,
g_tp.max_w_nmos_);
}
}
}
void PredecBlk::compute_area() {
if (exist) { // First check whether a predecoder block is needed
int num_L1_nand2 = 0;
int num_L1_nand3 = 0;
int num_L2 = 0;
double tot_area_L1_nand3 = 0;
double leak_L1_nand3 = 0;
double gate_leak_L1_nand3 = 0;
double tot_area_L1_nand2 = compute_gate_area(NAND, 2, w_L1_nand2_p[0], w_L1_nand2_n[0], g_tp.cell_h_def);
double leak_L1_nand2 = cmos_Isub_leakage(w_L1_nand2_n[0], w_L1_nand2_p[0], 2, nand, is_dram_);
double gate_leak_L1_nand2 = cmos_Ig_leakage(w_L1_nand2_n[0], w_L1_nand2_p[0], 2, nand, is_dram_);
if (number_inputs_L1_gate != 3) {
tot_area_L1_nand3 = 0;
leak_L1_nand3 = 0;
gate_leak_L1_nand3 = 0;
} else {
tot_area_L1_nand3 = compute_gate_area(NAND, 3, w_L1_nand3_p[0], w_L1_nand3_n[0], g_tp.cell_h_def);
leak_L1_nand3 = cmos_Isub_leakage(w_L1_nand3_n[0], w_L1_nand3_p[0], 3, nand);
gate_leak_L1_nand3 = cmos_Ig_leakage(w_L1_nand3_n[0], w_L1_nand3_p[0], 3, nand);
}
switch (number_input_addr_bits) {
case 1: //2 NAND2 gates
num_L1_nand2 = 2;
num_L2 = 0;
num_L1_active_nand2_path = 1;
num_L1_active_nand3_path = 0;
break;
case 2: //4 NAND2 gates
num_L1_nand2 = 4;
num_L2 = 0;
num_L1_active_nand2_path = 1;
num_L1_active_nand3_path = 0;
break;
case 3: //8 NAND3 gates
num_L1_nand3 = 8;
num_L2 = 0;
num_L1_active_nand2_path = 0;
num_L1_active_nand3_path = 1;
break;
case 4: //4 + 4 NAND2 gates
num_L1_nand2 = 8;
num_L2 = 16;
num_L1_active_nand2_path = 2;
num_L1_active_nand3_path = 0;
break;
case 5: //4 NAND2 gates, 8 NAND3 gates
num_L1_nand2 = 4;
num_L1_nand3 = 8;
num_L2 = 32;
num_L1_active_nand2_path = 1;
num_L1_active_nand3_path = 1;
break;
case 6: //8 + 8 NAND3 gates
num_L1_nand3 = 16;
num_L2 = 64;
num_L1_active_nand2_path = 0;
num_L1_active_nand3_path = 2;
break;
case 7: //4 + 4 NAND2 gates, 8 NAND3 gates
num_L1_nand2 = 8;
num_L1_nand3 = 8;
num_L2 = 128;
num_L1_active_nand2_path = 2;
num_L1_active_nand3_path = 1;
break;
case 8: //4 NAND2 gates, 8 + 8 NAND3 gates
num_L1_nand2 = 4;
num_L1_nand3 = 16;
num_L2 = 256;
num_L1_active_nand2_path = 2;
num_L1_active_nand3_path = 2;
break;
case 9: //8 + 8 + 8 NAND3 gates
num_L1_nand3 = 24;
num_L2 = 512;
num_L1_active_nand2_path = 0;
num_L1_active_nand3_path = 3;
break;
default:
break;
}
for (int i = 1; i < number_gates_L1_nand2_path; ++i) {
tot_area_L1_nand2 += compute_gate_area(INV, 1, w_L1_nand2_p[i], w_L1_nand2_n[i], g_tp.cell_h_def);
leak_L1_nand2 += cmos_Isub_leakage(w_L1_nand2_n[i], w_L1_nand2_p[i], 2, nand, is_dram_);
gate_leak_L1_nand2 += cmos_Ig_leakage(w_L1_nand2_n[i], w_L1_nand2_p[i], 2, nand, is_dram_);
}
tot_area_L1_nand2 *= num_L1_nand2;
leak_L1_nand2 *= num_L1_nand2;
gate_leak_L1_nand2 *= num_L1_nand2;
for (int i = 1; i < number_gates_L1_nand3_path; ++i) {
tot_area_L1_nand3 += compute_gate_area(INV, 1, w_L1_nand3_p[i], w_L1_nand3_n[i], g_tp.cell_h_def);
leak_L1_nand3 += cmos_Isub_leakage(w_L1_nand3_n[i], w_L1_nand3_p[i], 3, nand, is_dram_);
gate_leak_L1_nand3 += cmos_Ig_leakage(w_L1_nand3_n[i], w_L1_nand3_p[i], 3, nand, is_dram_);
}
tot_area_L1_nand3 *= num_L1_nand3;
leak_L1_nand3 *= num_L1_nand3;
gate_leak_L1_nand3 *= num_L1_nand3;
double cumulative_area_L1 = tot_area_L1_nand2 + tot_area_L1_nand3;
double cumulative_area_L2 = 0.0;
double leakage_L2 = 0.0;
double gate_leakage_L2 = 0.0;
if (flag_L2_gate == 2) {
cumulative_area_L2 = compute_gate_area(NAND, 2, w_L2_p[0], w_L2_n[0], g_tp.cell_h_def);
leakage_L2 = cmos_Isub_leakage(w_L2_n[0], w_L2_p[0], 2, nand, is_dram_);
gate_leakage_L2 = cmos_Ig_leakage(w_L2_n[0], w_L2_p[0], 2, nand, is_dram_);
} else if (flag_L2_gate == 3) {
cumulative_area_L2 = compute_gate_area(NAND, 3, w_L2_p[0], w_L2_n[0], g_tp.cell_h_def);
leakage_L2 = cmos_Isub_leakage(w_L2_n[0], w_L2_p[0], 3, nand, is_dram_);
gate_leakage_L2 = cmos_Ig_leakage(w_L2_n[0], w_L2_p[0], 3, nand, is_dram_);
}
for (int i = 1; i < number_gates_L2; ++i) {
cumulative_area_L2 += compute_gate_area(INV, 1, w_L2_p[i], w_L2_n[i], g_tp.cell_h_def);
leakage_L2 += cmos_Isub_leakage(w_L2_n[i], w_L2_p[i], 2, inv, is_dram_);
gate_leakage_L2 += cmos_Ig_leakage(w_L2_n[i], w_L2_p[i], 2, inv, is_dram_);
}
cumulative_area_L2 *= num_L2;
leakage_L2 *= num_L2;
gate_leakage_L2 *= num_L2;
power_nand2_path.readOp.leakage = leak_L1_nand2 * g_tp.peri_global.Vdd;
power_nand3_path.readOp.leakage = leak_L1_nand3 * g_tp.peri_global.Vdd;
power_L2.readOp.leakage = leakage_L2 * g_tp.peri_global.Vdd;
area.set_area(cumulative_area_L1 + cumulative_area_L2);
power_nand2_path.readOp.gate_leakage = gate_leak_L1_nand2 * g_tp.peri_global.Vdd;
power_nand3_path.readOp.gate_leakage = gate_leak_L1_nand3 * g_tp.peri_global.Vdd;
power_L2.readOp.gate_leakage = gate_leakage_L2 * g_tp.peri_global.Vdd;
}
}
pair<double, double> PredecBlk::compute_delays(
pair<double, double> inrisetime) { // <nand2, nand3>
pair<double, double> ret_val;
ret_val.first = 0; // outrisetime_nand2_path
ret_val.second = 0; // outrisetime_nand3_path
double inrisetime_nand2_path = inrisetime.first;
double inrisetime_nand3_path = inrisetime.second;
int i;
double rd, c_load, c_intrinsic, tf, this_delay;
double Vdd = g_tp.peri_global.Vdd;
// TODO: following delay calculation part can be greatly simplified.
// first check whether a predecoder block is required
if (exist) {
//Find delay in first level of predecoder block
//First find delay in path
if ((flag_two_unique_paths) || (number_inputs_L1_gate == 2)) {
//First gate is a NAND2 gate
rd = tr_R_on(w_L1_nand2_n[0], NCH, 2, is_dram_);
c_load = gate_C(w_L1_nand2_n[1] + w_L1_nand2_p[1], 0.0, is_dram_);
c_intrinsic = 2 * drain_C_(w_L1_nand2_p[0], PCH, 1, 1, g_tp.cell_h_def, is_dram_) +
drain_C_(w_L1_nand2_n[0], NCH, 2, 1, g_tp.cell_h_def, is_dram_);
tf = rd * (c_intrinsic + c_load);
this_delay = horowitz(inrisetime_nand2_path, tf, 0.5, 0.5, RISE);
delay_nand2_path += this_delay;
inrisetime_nand2_path = this_delay / (1.0 - 0.5);
power_nand2_path.readOp.dynamic += (c_load + c_intrinsic) * Vdd * Vdd;
//Add delays of all but the last inverter in the chain
for (i = 1; i < number_gates_L1_nand2_path - 1; ++i) {
rd = tr_R_on(w_L1_nand2_n[i], NCH, 1, is_dram_);
c_load = gate_C(w_L1_nand2_n[i+1] + w_L1_nand2_p[i+1], 0.0, is_dram_);
c_intrinsic = drain_C_(w_L1_nand2_p[i], PCH, 1, 1, g_tp.cell_h_def, is_dram_) +
drain_C_(w_L1_nand2_n[i], NCH, 1, 1, g_tp.cell_h_def, is_dram_);
tf = rd * (c_intrinsic + c_load);
this_delay = horowitz(inrisetime_nand2_path, tf, 0.5, 0.5, RISE);
delay_nand2_path += this_delay;
inrisetime_nand2_path = this_delay / (1.0 - 0.5);
power_nand2_path.readOp.dynamic += (c_intrinsic + c_load) * Vdd * Vdd;
}
//Add delay of the last inverter
i = number_gates_L1_nand2_path - 1;
rd = tr_R_on(w_L1_nand2_n[i], NCH, 1, is_dram_);
if (flag_L2_gate) {
c_load = branch_effort_nand2_gate_output *
(gate_C(w_L2_n[0], 0, is_dram_) +
gate_C(w_L2_p[0], 0, is_dram_));
c_intrinsic = drain_C_(w_L1_nand2_p[i], PCH, 1, 1, g_tp.cell_h_def, is_dram_) +
drain_C_(w_L1_nand2_n[i], NCH, 1, 1, g_tp.cell_h_def, is_dram_);
tf = rd * (c_intrinsic + c_load);
this_delay = horowitz(inrisetime_nand2_path, tf, 0.5, 0.5, RISE);
delay_nand2_path += this_delay;
inrisetime_nand2_path = this_delay / (1.0 - 0.5);
power_nand2_path.readOp.dynamic += (c_intrinsic + c_load) * Vdd * Vdd;
} else { //First level directly drives decoder output load
c_load = C_ld_predec_blk_out;
c_intrinsic = drain_C_(w_L1_nand2_p[i], PCH, 1, 1, g_tp.cell_h_def, is_dram_) +
drain_C_(w_L1_nand2_n[i], NCH, 1, 1, g_tp.cell_h_def, is_dram_);
tf = rd * (c_intrinsic + c_load) + R_wire_predec_blk_out * c_load / 2;
this_delay = horowitz(inrisetime_nand2_path, tf, 0.5, 0.5, RISE);
delay_nand2_path += this_delay;
ret_val.first = this_delay / (1.0 - 0.5);
power_nand2_path.readOp.dynamic += (c_intrinsic + c_load) * Vdd * Vdd;
}
}
if ((flag_two_unique_paths) || (number_inputs_L1_gate == 3)) {
//Check if the number of gates in the first level is more than 1.
//First gate is a NAND3 gate
rd = tr_R_on(w_L1_nand3_n[0], NCH, 3, is_dram_);
c_load = gate_C(w_L1_nand3_n[1] + w_L1_nand3_p[1], 0.0, is_dram_);
c_intrinsic = 3 * drain_C_(w_L1_nand3_p[0], PCH, 1, 1, g_tp.cell_h_def, is_dram_) +
drain_C_(w_L1_nand3_n[0], NCH, 3, 1, g_tp.cell_h_def, is_dram_);
tf = rd * (c_intrinsic + c_load);
this_delay = horowitz(inrisetime_nand3_path, tf, 0.5, 0.5, RISE);
delay_nand3_path += this_delay;
inrisetime_nand3_path = this_delay / (1.0 - 0.5);
power_nand3_path.readOp.dynamic += (c_intrinsic + c_load) * Vdd * Vdd;
//Add delays of all but the last inverter in the chain
for (i = 1; i < number_gates_L1_nand3_path - 1; ++i) {
rd = tr_R_on(w_L1_nand3_n[i], NCH, 1, is_dram_);
c_load = gate_C(w_L1_nand3_n[i+1] + w_L1_nand3_p[i+1], 0.0, is_dram_);
c_intrinsic = drain_C_(w_L1_nand3_p[i], PCH, 1, 1, g_tp.cell_h_def, is_dram_) +
drain_C_(w_L1_nand3_n[i], NCH, 1, 1, g_tp.cell_h_def, is_dram_);
tf = rd * (c_intrinsic + c_load);
this_delay = horowitz(inrisetime_nand3_path, tf, 0.5, 0.5, RISE);
delay_nand3_path += this_delay;
inrisetime_nand3_path = this_delay / (1.0 - 0.5);
power_nand3_path.readOp.dynamic += (c_intrinsic + c_load) * Vdd * Vdd;
}
//Add delay of the last inverter
i = number_gates_L1_nand3_path - 1;
rd = tr_R_on(w_L1_nand3_n[i], NCH, 1, is_dram_);
if (flag_L2_gate) {
c_load = branch_effort_nand3_gate_output *
(gate_C(w_L2_n[0], 0, is_dram_) + gate_C(w_L2_p[0], 0,
is_dram_));
c_intrinsic = drain_C_(w_L1_nand3_p[i], PCH, 1, 1, g_tp.cell_h_def, is_dram_) +
drain_C_(w_L1_nand3_n[i], NCH, 1, 1, g_tp.cell_h_def, is_dram_);
tf = rd * (c_intrinsic + c_load);
this_delay = horowitz(inrisetime_nand3_path, tf, 0.5, 0.5, RISE);
delay_nand3_path += this_delay;
inrisetime_nand3_path = this_delay / (1.0 - 0.5);
power_nand3_path.readOp.dynamic += (c_intrinsic + c_load) * Vdd * Vdd;
} else { //First level directly drives decoder output load
c_load = C_ld_predec_blk_out;
c_intrinsic = drain_C_(w_L1_nand3_p[i], PCH, 1, 1, g_tp.cell_h_def, is_dram_) +
drain_C_(w_L1_nand3_n[i], NCH, 1, 1, g_tp.cell_h_def, is_dram_);
tf = rd * (c_intrinsic + c_load) + R_wire_predec_blk_out * c_load / 2;
this_delay = horowitz(inrisetime_nand3_path, tf, 0.5, 0.5, RISE);
delay_nand3_path += this_delay;
ret_val.second = this_delay / (1.0 - 0.5);
power_nand3_path.readOp.dynamic += (c_intrinsic + c_load) * Vdd * Vdd;
}
}
// Find delay through second level
if (flag_L2_gate) {
if (flag_L2_gate == 2) {
rd = tr_R_on(w_L2_n[0], NCH, 2, is_dram_);
c_load = gate_C(w_L2_n[1] + w_L2_p[1], 0.0, is_dram_);
c_intrinsic = 2 * drain_C_(w_L2_p[0], PCH, 1, 1, g_tp.cell_h_def, is_dram_) +
drain_C_(w_L2_n[0], NCH, 2, 1, g_tp.cell_h_def, is_dram_);
tf = rd * (c_intrinsic + c_load);
this_delay = horowitz(inrisetime_nand2_path, tf, 0.5, 0.5, RISE);
delay_nand2_path += this_delay;
inrisetime_nand2_path = this_delay / (1.0 - 0.5);
power_L2.readOp.dynamic += (c_intrinsic + c_load) * Vdd * Vdd;
} else { // flag_L2_gate = 3
rd = tr_R_on(w_L2_n[0], NCH, 3, is_dram_);
c_load = gate_C(w_L2_n[1] + w_L2_p[1], 0.0, is_dram_);
c_intrinsic = 3 * drain_C_(w_L2_p[0], PCH, 1, 1, g_tp.cell_h_def, is_dram_) +
drain_C_(w_L2_n[0], NCH, 3, 1, g_tp.cell_h_def, is_dram_);
tf = rd * (c_intrinsic + c_load);
this_delay = horowitz(inrisetime_nand3_path, tf, 0.5, 0.5, RISE);
delay_nand3_path += this_delay;
inrisetime_nand3_path = this_delay / (1.0 - 0.5);
power_L2.readOp.dynamic += (c_intrinsic + c_load) * Vdd * Vdd;
}
for (i = 1; i < number_gates_L2 - 1; ++i) {
rd = tr_R_on(w_L2_n[i], NCH, 1, is_dram_);
c_load = gate_C(w_L2_n[i+1] + w_L2_p[i+1], 0.0, is_dram_);
c_intrinsic = drain_C_(w_L2_p[i], PCH, 1, 1, g_tp.cell_h_def, is_dram_) +
drain_C_(w_L2_n[i], NCH, 1, 1, g_tp.cell_h_def, is_dram_);
tf = rd * (c_intrinsic + c_load);
this_delay = horowitz(inrisetime_nand2_path, tf, 0.5, 0.5, RISE);
delay_nand2_path += this_delay;
inrisetime_nand2_path = this_delay / (1.0 - 0.5);
this_delay = horowitz(inrisetime_nand3_path, tf, 0.5, 0.5, RISE);
delay_nand3_path += this_delay;
inrisetime_nand3_path = this_delay / (1.0 - 0.5);
power_L2.readOp.dynamic += (c_intrinsic + c_load) * Vdd * Vdd;
}
//Add delay of final inverter that drives the wordline decoders
i = number_gates_L2 - 1;
c_load = C_ld_predec_blk_out;
rd = tr_R_on(w_L2_n[i], NCH, 1, is_dram_);
c_intrinsic = drain_C_(w_L2_p[i], PCH, 1, 1, g_tp.cell_h_def, is_dram_) +
drain_C_(w_L2_n[i], NCH, 1, 1, g_tp.cell_h_def, is_dram_);
tf = rd * (c_intrinsic + c_load) + R_wire_predec_blk_out * c_load / 2;
this_delay = horowitz(inrisetime_nand2_path, tf, 0.5, 0.5, RISE);
delay_nand2_path += this_delay;
ret_val.first = this_delay / (1.0 - 0.5);
this_delay = horowitz(inrisetime_nand3_path, tf, 0.5, 0.5, RISE);
delay_nand3_path += this_delay;
ret_val.second = this_delay / (1.0 - 0.5);
power_L2.readOp.dynamic += (c_intrinsic + c_load) * Vdd * Vdd;
}
}
delay = (ret_val.first > ret_val.second) ? ret_val.first : ret_val.second;
return ret_val;
}
void PredecBlk::leakage_feedback(double temperature)
{
if (exist)
{ // First check whether a predecoder block is needed
int num_L1_nand2 = 0;
int num_L1_nand3 = 0;
int num_L2 = 0;
double leak_L1_nand3 =0;
double gate_leak_L1_nand3 =0;
double leak_L1_nand2 = cmos_Isub_leakage(w_L1_nand2_n[0], w_L1_nand2_p[0], 2, nand, is_dram_);
double gate_leak_L1_nand2 = cmos_Ig_leakage(w_L1_nand2_n[0], w_L1_nand2_p[0], 2, nand, is_dram_);
if (number_inputs_L1_gate != 3) {
leak_L1_nand3 = 0;
gate_leak_L1_nand3 =0;
}
else {
leak_L1_nand3 = cmos_Isub_leakage(w_L1_nand3_n[0], w_L1_nand3_p[0], 3, nand);
gate_leak_L1_nand3 = cmos_Ig_leakage(w_L1_nand3_n[0], w_L1_nand3_p[0], 3, nand);
}
switch (number_input_addr_bits)
{
case 1: //2 NAND2 gates
num_L1_nand2 = 2;
num_L2 = 0;
num_L1_active_nand2_path =1;
num_L1_active_nand3_path =0;
break;
case 2: //4 NAND2 gates
num_L1_nand2 = 4;
num_L2 = 0;
num_L1_active_nand2_path =1;
num_L1_active_nand3_path =0;
break;
case 3: //8 NAND3 gates
num_L1_nand3 = 8;
num_L2 = 0;
num_L1_active_nand2_path =0;
num_L1_active_nand3_path =1;
break;
case 4: //4 + 4 NAND2 gates
num_L1_nand2 = 8;
num_L2 = 16;
num_L1_active_nand2_path =2;
num_L1_active_nand3_path =0;
break;
case 5: //4 NAND2 gates, 8 NAND3 gates
num_L1_nand2 = 4;
num_L1_nand3 = 8;
num_L2 = 32;
num_L1_active_nand2_path =1;
num_L1_active_nand3_path =1;
break;
case 6: //8 + 8 NAND3 gates
num_L1_nand3 = 16;
num_L2 = 64;
num_L1_active_nand2_path =0;
num_L1_active_nand3_path =2;
break;
case 7: //4 + 4 NAND2 gates, 8 NAND3 gates
num_L1_nand2 = 8;
num_L1_nand3 = 8;
num_L2 = 128;
num_L1_active_nand2_path =2;
num_L1_active_nand3_path =1;
break;
case 8: //4 NAND2 gates, 8 + 8 NAND3 gates
num_L1_nand2 = 4;
num_L1_nand3 = 16;
num_L2 = 256;
num_L1_active_nand2_path =2;
num_L1_active_nand3_path =2;
break;
case 9: //8 + 8 + 8 NAND3 gates
num_L1_nand3 = 24;
num_L2 = 512;
num_L1_active_nand2_path =0;
num_L1_active_nand3_path =3;
break;
default:
break;
}
for (int i = 1; i < number_gates_L1_nand2_path; ++i)
{
leak_L1_nand2 += cmos_Isub_leakage(w_L1_nand2_n[i], w_L1_nand2_p[i], 2, nand, is_dram_);
gate_leak_L1_nand2 += cmos_Ig_leakage(w_L1_nand2_n[i], w_L1_nand2_p[i], 2, nand, is_dram_);
}
leak_L1_nand2 *= num_L1_nand2;
gate_leak_L1_nand2 *= num_L1_nand2;
for (int i = 1; i < number_gates_L1_nand3_path; ++i)
{
leak_L1_nand3 += cmos_Isub_leakage(w_L1_nand3_n[i], w_L1_nand3_p[i], 3, nand, is_dram_);
gate_leak_L1_nand3 += cmos_Ig_leakage(w_L1_nand3_n[i], w_L1_nand3_p[i], 3, nand, is_dram_);
}
leak_L1_nand3 *= num_L1_nand3;
gate_leak_L1_nand3 *= num_L1_nand3;
double leakage_L2 = 0.0;
double gate_leakage_L2 = 0.0;
if (flag_L2_gate == 2)
{
leakage_L2 = cmos_Isub_leakage(w_L2_n[0], w_L2_p[0], 2, nand, is_dram_);
gate_leakage_L2 = cmos_Ig_leakage(w_L2_n[0], w_L2_p[0], 2, nand, is_dram_);
}
else if (flag_L2_gate == 3)
{
leakage_L2 = cmos_Isub_leakage(w_L2_n[0], w_L2_p[0], 3, nand, is_dram_);
gate_leakage_L2 = cmos_Ig_leakage(w_L2_n[0], w_L2_p[0], 3, nand, is_dram_);
}
for (int i = 1; i < number_gates_L2; ++i)
{
leakage_L2 += cmos_Isub_leakage(w_L2_n[i], w_L2_p[i], 2, inv, is_dram_);
gate_leakage_L2 += cmos_Ig_leakage(w_L2_n[i], w_L2_p[i], 2, inv, is_dram_);
}
leakage_L2 *= num_L2;
gate_leakage_L2 *= num_L2;
power_nand2_path.readOp.leakage = leak_L1_nand2 * g_tp.peri_global.Vdd;
power_nand3_path.readOp.leakage = leak_L1_nand3 * g_tp.peri_global.Vdd;
power_L2.readOp.leakage = leakage_L2 * g_tp.peri_global.Vdd;
power_nand2_path.readOp.gate_leakage = gate_leak_L1_nand2 * g_tp.peri_global.Vdd;
power_nand3_path.readOp.gate_leakage = gate_leak_L1_nand3 * g_tp.peri_global.Vdd;
power_L2.readOp.gate_leakage = gate_leakage_L2 * g_tp.peri_global.Vdd;
}
}
PredecBlkDrv::PredecBlkDrv(
int way_select_,
PredecBlk * blk_,
bool is_dram)
: flag_driver_exists(0),
number_gates_nand2_path(0),
number_gates_nand3_path(0),
min_number_gates(2),
num_buffers_driving_1_nand2_load(0),
num_buffers_driving_2_nand2_load(0),
num_buffers_driving_4_nand2_load(0),
num_buffers_driving_2_nand3_load(0),
num_buffers_driving_8_nand3_load(0),
num_buffers_nand3_path(0),
c_load_nand2_path_out(0),
c_load_nand3_path_out(0),
r_load_nand2_path_out(0),
r_load_nand3_path_out(0),
delay_nand2_path(0),
delay_nand3_path(0),
power_nand2_path(),
power_nand3_path(),
blk(blk_), dec(blk->dec),
is_dram_(is_dram),
way_select(way_select_) {
for (int i = 0; i < MAX_NUMBER_GATES_STAGE; i++) {
width_nand2_path_n[i] = 0;
width_nand2_path_p[i] = 0;
width_nand3_path_n[i] = 0;
width_nand3_path_p[i] = 0;
}
number_input_addr_bits = blk->number_input_addr_bits;
if (way_select > 1) {
flag_driver_exists = 1;
number_input_addr_bits = way_select;
if (dec->num_in_signals == 2) {
c_load_nand2_path_out = gate_C(dec->w_dec_n[0] + dec->w_dec_p[0], 0, is_dram_);
num_buffers_driving_2_nand2_load = number_input_addr_bits;
} else if (dec->num_in_signals == 3) {
c_load_nand3_path_out = gate_C(dec->w_dec_n[0] + dec->w_dec_p[0], 0, is_dram_);
num_buffers_driving_2_nand3_load = number_input_addr_bits;
}
} else if (way_select == 0) {
if (blk->exist) {
flag_driver_exists = 1;
}
}
compute_widths();
compute_area();
}
void PredecBlkDrv::compute_widths() {
// The predecode block driver accepts as input the address bits from the h-tree network. For
// each addr bit it then generates addr and addrbar as outputs. For now ignore the effect of
// inversion to generate addrbar and simply treat addrbar as addr.
double F;
double p_to_n_sz_ratio = pmos_to_nmos_sz_ratio(is_dram_);
if (flag_driver_exists) {
double C_nand2_gate_blk = gate_C(blk->w_L1_nand2_n[0] + blk->w_L1_nand2_p[0], 0, is_dram_);
double C_nand3_gate_blk = gate_C(blk->w_L1_nand3_n[0] + blk->w_L1_nand3_p[0], 0, is_dram_);
if (way_select == 0) {
if (blk->number_input_addr_bits == 1) {
//2 NAND2 gates
num_buffers_driving_2_nand2_load = 1;
c_load_nand2_path_out = 2 * C_nand2_gate_blk;
} else if (blk->number_input_addr_bits == 2) {
//4 NAND2 gates one 2-4 decoder
num_buffers_driving_4_nand2_load = 2;
c_load_nand2_path_out = 4 * C_nand2_gate_blk;
} else if (blk->number_input_addr_bits == 3) {
//8 NAND3 gates one 3-8 decoder
num_buffers_driving_8_nand3_load = 3;
c_load_nand3_path_out = 8 * C_nand3_gate_blk;
} else if (blk->number_input_addr_bits == 4) {
//4 + 4 NAND2 gates two 2-4 decoder
num_buffers_driving_4_nand2_load = 4;
c_load_nand2_path_out = 4 * C_nand2_gate_blk;
} else if (blk->number_input_addr_bits == 5) {
//4 NAND2 gates, 8 NAND3 gates one 2-4 decoder and one 3-8
//decoder
num_buffers_driving_4_nand2_load = 2;
num_buffers_driving_8_nand3_load = 3;
c_load_nand2_path_out = 4 * C_nand2_gate_blk;
c_load_nand3_path_out = 8 * C_nand3_gate_blk;
} else if (blk->number_input_addr_bits == 6) {
//8 + 8 NAND3 gates two 3-8 decoder
num_buffers_driving_8_nand3_load = 6;
c_load_nand3_path_out = 8 * C_nand3_gate_blk;
} else if (blk->number_input_addr_bits == 7) {
//4 + 4 NAND2 gates, 8 NAND3 gates two 2-4 decoder and one 3-8
//decoder
num_buffers_driving_4_nand2_load = 4;
num_buffers_driving_8_nand3_load = 3;
c_load_nand2_path_out = 4 * C_nand2_gate_blk;
c_load_nand3_path_out = 8 * C_nand3_gate_blk;
} else if (blk->number_input_addr_bits == 8) {
//4 NAND2 gates, 8 + 8 NAND3 gates one 2-4 decoder and two 3-8
//decoder
num_buffers_driving_4_nand2_load = 2;
num_buffers_driving_8_nand3_load = 6;
c_load_nand2_path_out = 4 * C_nand2_gate_blk;
c_load_nand3_path_out = 8 * C_nand3_gate_blk;
} else if (blk->number_input_addr_bits == 9) {
//8 + 8 + 8 NAND3 gates three 3-8 decoder
num_buffers_driving_8_nand3_load = 9;
c_load_nand3_path_out = 8 * C_nand3_gate_blk;
}
}
if ((blk->flag_two_unique_paths) ||
(blk->number_inputs_L1_gate == 2) ||
(number_input_addr_bits == 0) ||
((way_select) && (dec->num_in_signals == 2))) {
//this means that way_select is driving NAND2 in decoder.
width_nand2_path_n[0] = g_tp.min_w_nmos_;
width_nand2_path_p[0] = p_to_n_sz_ratio * width_nand2_path_n[0];
F = c_load_nand2_path_out / gate_C(width_nand2_path_n[0] + width_nand2_path_p[0], 0, is_dram_);
number_gates_nand2_path = logical_effort(
min_number_gates,
1,
F,
width_nand2_path_n,
width_nand2_path_p,
c_load_nand2_path_out,
p_to_n_sz_ratio,
is_dram_, false, g_tp.max_w_nmos_);
}
if ((blk->flag_two_unique_paths) ||
(blk->number_inputs_L1_gate == 3) ||
((way_select) && (dec->num_in_signals == 3))) {
//this means that way_select is driving NAND3 in decoder.
width_nand3_path_n[0] = g_tp.min_w_nmos_;
width_nand3_path_p[0] = p_to_n_sz_ratio * width_nand3_path_n[0];
F = c_load_nand3_path_out / gate_C(width_nand3_path_n[0] + width_nand3_path_p[0], 0, is_dram_);
number_gates_nand3_path = logical_effort(
min_number_gates,
1,
F,
width_nand3_path_n,
width_nand3_path_p,
c_load_nand3_path_out,
p_to_n_sz_ratio,
is_dram_, false, g_tp.max_w_nmos_);
}
}
}
void PredecBlkDrv::compute_area() {
double area_nand2_path = 0;
double area_nand3_path = 0;
double leak_nand2_path = 0;
double leak_nand3_path = 0;
double gate_leak_nand2_path = 0;
double gate_leak_nand3_path = 0;
if (flag_driver_exists) {
// first check whether a predecoder block driver is needed
for (int i = 0; i < number_gates_nand2_path; ++i) {
area_nand2_path +=
compute_gate_area(INV, 1, width_nand2_path_p[i],
width_nand2_path_n[i], g_tp.cell_h_def);
leak_nand2_path +=
cmos_Isub_leakage(width_nand2_path_n[i], width_nand2_path_p[i],
1, inv, is_dram_);
gate_leak_nand2_path +=
cmos_Ig_leakage(width_nand2_path_n[i], width_nand2_path_p[i],
1, inv, is_dram_);
}
area_nand2_path *= (num_buffers_driving_1_nand2_load +
num_buffers_driving_2_nand2_load +
num_buffers_driving_4_nand2_load);
leak_nand2_path *= (num_buffers_driving_1_nand2_load +
num_buffers_driving_2_nand2_load +
num_buffers_driving_4_nand2_load);
gate_leak_nand2_path *= (num_buffers_driving_1_nand2_load +
num_buffers_driving_2_nand2_load +
num_buffers_driving_4_nand2_load);
for (int i = 0; i < number_gates_nand3_path; ++i) {
area_nand3_path +=
compute_gate_area(INV, 1, width_nand3_path_p[i],
width_nand3_path_n[i], g_tp.cell_h_def);
leak_nand3_path +=
cmos_Isub_leakage(width_nand3_path_n[i], width_nand3_path_p[i],
1, inv, is_dram_);
gate_leak_nand3_path +=
cmos_Ig_leakage(width_nand3_path_n[i], width_nand3_path_p[i],
1, inv, is_dram_);
}
area_nand3_path *= (num_buffers_driving_2_nand3_load + num_buffers_driving_8_nand3_load);
leak_nand3_path *= (num_buffers_driving_2_nand3_load + num_buffers_driving_8_nand3_load);
gate_leak_nand3_path *= (num_buffers_driving_2_nand3_load + num_buffers_driving_8_nand3_load);
power_nand2_path.readOp.leakage = leak_nand2_path * g_tp.peri_global.Vdd;
power_nand3_path.readOp.leakage = leak_nand3_path * g_tp.peri_global.Vdd;
power_nand2_path.readOp.gate_leakage = gate_leak_nand2_path * g_tp.peri_global.Vdd;
power_nand3_path.readOp.gate_leakage = gate_leak_nand3_path * g_tp.peri_global.Vdd;
area.set_area(area_nand2_path + area_nand3_path);
}
}
pair<double, double> PredecBlkDrv::compute_delays(
double inrisetime_nand2_path,
double inrisetime_nand3_path) {
pair<double, double> ret_val;
ret_val.first = 0; // outrisetime_nand2_path
ret_val.second = 0; // outrisetime_nand3_path
int i;
double rd, c_gate_load, c_load, c_intrinsic, tf, this_delay;
double Vdd = g_tp.peri_global.Vdd;
if (flag_driver_exists) {
for (i = 0; i < number_gates_nand2_path - 1; ++i) {
rd = tr_R_on(width_nand2_path_n[i], NCH, 1, is_dram_);
c_gate_load = gate_C(width_nand2_path_p[i+1] + width_nand2_path_n[i+1], 0.0, is_dram_);
c_intrinsic = drain_C_(width_nand2_path_p[i], PCH, 1, 1, g_tp.cell_h_def, is_dram_) +
drain_C_(width_nand2_path_n[i], NCH, 1, 1, g_tp.cell_h_def, is_dram_);
tf = rd * (c_intrinsic + c_gate_load);
this_delay = horowitz(inrisetime_nand2_path, tf, 0.5, 0.5, RISE);
delay_nand2_path += this_delay;
inrisetime_nand2_path = this_delay / (1.0 - 0.5);
power_nand2_path.readOp.dynamic += (c_gate_load + c_intrinsic) * 0.5 * Vdd * Vdd;
}
// Final inverter drives the predecoder block or the decoder output load
if (number_gates_nand2_path != 0) {
i = number_gates_nand2_path - 1;
rd = tr_R_on(width_nand2_path_n[i], NCH, 1, is_dram_);
c_intrinsic = drain_C_(width_nand2_path_p[i], PCH, 1, 1, g_tp.cell_h_def, is_dram_) +
drain_C_(width_nand2_path_n[i], NCH, 1, 1, g_tp.cell_h_def, is_dram_);
c_load = c_load_nand2_path_out;
tf = rd * (c_intrinsic + c_load) + r_load_nand2_path_out * c_load / 2;
this_delay = horowitz(inrisetime_nand2_path, tf, 0.5, 0.5, RISE);
delay_nand2_path += this_delay;
ret_val.first = this_delay / (1.0 - 0.5);
power_nand2_path.readOp.dynamic += (c_intrinsic + c_load) * 0.5 * Vdd * Vdd;
// cout<< "c_intrinsic = " << c_intrinsic << "c_load" << c_load <<endl;
}
for (i = 0; i < number_gates_nand3_path - 1; ++i) {
rd = tr_R_on(width_nand3_path_n[i], NCH, 1, is_dram_);
c_gate_load = gate_C(width_nand3_path_p[i+1] + width_nand3_path_n[i+1], 0.0, is_dram_);
c_intrinsic = drain_C_(width_nand3_path_p[i], PCH, 1, 1, g_tp.cell_h_def, is_dram_) +
drain_C_(width_nand3_path_n[i], NCH, 1, 1, g_tp.cell_h_def, is_dram_);
tf = rd * (c_intrinsic + c_gate_load);
this_delay = horowitz(inrisetime_nand3_path, tf, 0.5, 0.5, RISE);
delay_nand3_path += this_delay;
inrisetime_nand3_path = this_delay / (1.0 - 0.5);
power_nand3_path.readOp.dynamic += (c_gate_load + c_intrinsic) * 0.5 * Vdd * Vdd;
}
// Final inverter drives the predecoder block or the decoder output load
if (number_gates_nand3_path != 0) {
i = number_gates_nand3_path - 1;
rd = tr_R_on(width_nand3_path_n[i], NCH, 1, is_dram_);
c_intrinsic = drain_C_(width_nand3_path_p[i], PCH, 1, 1, g_tp.cell_h_def, is_dram_) +
drain_C_(width_nand3_path_n[i], NCH, 1, 1, g_tp.cell_h_def, is_dram_);
c_load = c_load_nand3_path_out;
tf = rd * (c_intrinsic + c_load) + r_load_nand3_path_out * c_load / 2;
this_delay = horowitz(inrisetime_nand3_path, tf, 0.5, 0.5, RISE);
delay_nand3_path += this_delay;
ret_val.second = this_delay / (1.0 - 0.5);
power_nand3_path.readOp.dynamic += (c_intrinsic + c_load) * 0.5 * Vdd * Vdd;
}
}
return ret_val;
}
double PredecBlkDrv::get_rdOp_dynamic_E(int num_act_mats_hor_dir) {
return (num_addr_bits_nand2_path()*power_nand2_path.readOp.dynamic +
num_addr_bits_nand3_path()*power_nand3_path.readOp.dynamic) * num_act_mats_hor_dir;
}
Predec::Predec(
PredecBlkDrv * drv1_,
PredecBlkDrv * drv2_)
: blk1(drv1_->blk), blk2(drv2_->blk), drv1(drv1_), drv2(drv2_) {
driver_power.readOp.leakage = drv1->power_nand2_path.readOp.leakage +
drv1->power_nand3_path.readOp.leakage +
drv2->power_nand2_path.readOp.leakage +
drv2->power_nand3_path.readOp.leakage;
block_power.readOp.leakage = blk1->power_nand2_path.readOp.leakage +
blk1->power_nand3_path.readOp.leakage +
blk1->power_L2.readOp.leakage +
blk2->power_nand2_path.readOp.leakage +
blk2->power_nand3_path.readOp.leakage +
blk2->power_L2.readOp.leakage;
power.readOp.leakage = driver_power.readOp.leakage + block_power.readOp.leakage;
driver_power.readOp.gate_leakage = drv1->power_nand2_path.readOp.gate_leakage +
drv1->power_nand3_path.readOp.gate_leakage +
drv2->power_nand2_path.readOp.gate_leakage +
drv2->power_nand3_path.readOp.gate_leakage;
block_power.readOp.gate_leakage = blk1->power_nand2_path.readOp.gate_leakage +
blk1->power_nand3_path.readOp.gate_leakage +
blk1->power_L2.readOp.gate_leakage +
blk2->power_nand2_path.readOp.gate_leakage +
blk2->power_nand3_path.readOp.gate_leakage +
blk2->power_L2.readOp.gate_leakage;
power.readOp.gate_leakage = driver_power.readOp.gate_leakage + block_power.readOp.gate_leakage;
}
void PredecBlkDrv::leakage_feedback(double temperature)
{
double leak_nand2_path = 0;
double leak_nand3_path = 0;
double gate_leak_nand2_path = 0;
double gate_leak_nand3_path = 0;
if (flag_driver_exists)
{ // first check whether a predecoder block driver is needed
for (int i = 0; i < number_gates_nand2_path; ++i)
{
leak_nand2_path += cmos_Isub_leakage(width_nand2_path_n[i], width_nand2_path_p[i], 1, inv,is_dram_);
gate_leak_nand2_path += cmos_Ig_leakage(width_nand2_path_n[i], width_nand2_path_p[i], 1, inv,is_dram_);
}
leak_nand2_path *= (num_buffers_driving_1_nand2_load +
num_buffers_driving_2_nand2_load +
num_buffers_driving_4_nand2_load);
gate_leak_nand2_path *= (num_buffers_driving_1_nand2_load +
num_buffers_driving_2_nand2_load +
num_buffers_driving_4_nand2_load);
for (int i = 0; i < number_gates_nand3_path; ++i)
{
leak_nand3_path += cmos_Isub_leakage(width_nand3_path_n[i], width_nand3_path_p[i], 1, inv,is_dram_);
gate_leak_nand3_path += cmos_Ig_leakage(width_nand3_path_n[i], width_nand3_path_p[i], 1, inv,is_dram_);
}
leak_nand3_path *= (num_buffers_driving_2_nand3_load + num_buffers_driving_8_nand3_load);
gate_leak_nand3_path *= (num_buffers_driving_2_nand3_load + num_buffers_driving_8_nand3_load);
power_nand2_path.readOp.leakage = leak_nand2_path * g_tp.peri_global.Vdd;
power_nand3_path.readOp.leakage = leak_nand3_path * g_tp.peri_global.Vdd;
power_nand2_path.readOp.gate_leakage = gate_leak_nand2_path * g_tp.peri_global.Vdd;
power_nand3_path.readOp.gate_leakage = gate_leak_nand3_path * g_tp.peri_global.Vdd;
}
}
double Predec::compute_delays(double inrisetime) {
// TODO: Jung Ho thinks that predecoder block driver locates between decoder and predecoder block.
pair<double, double> tmp_pair1, tmp_pair2;
tmp_pair1 = drv1->compute_delays(inrisetime, inrisetime);
tmp_pair1 = blk1->compute_delays(tmp_pair1);
tmp_pair2 = drv2->compute_delays(inrisetime, inrisetime);
tmp_pair2 = blk2->compute_delays(tmp_pair2);
tmp_pair1 = get_max_delay_before_decoder(tmp_pair1, tmp_pair2);
driver_power.readOp.dynamic =
drv1->num_addr_bits_nand2_path() * drv1->power_nand2_path.readOp.dynamic +
drv1->num_addr_bits_nand3_path() * drv1->power_nand3_path.readOp.dynamic +
drv2->num_addr_bits_nand2_path() * drv2->power_nand2_path.readOp.dynamic +
drv2->num_addr_bits_nand3_path() * drv2->power_nand3_path.readOp.dynamic;
block_power.readOp.dynamic =
blk1->power_nand2_path.readOp.dynamic * blk1->num_L1_active_nand2_path +
blk1->power_nand3_path.readOp.dynamic * blk1->num_L1_active_nand3_path +
blk1->power_L2.readOp.dynamic +
blk2->power_nand2_path.readOp.dynamic * blk1->num_L1_active_nand2_path +
blk2->power_nand3_path.readOp.dynamic * blk1->num_L1_active_nand3_path +
blk2->power_L2.readOp.dynamic;
power.readOp.dynamic = driver_power.readOp.dynamic + block_power.readOp.dynamic;
delay = tmp_pair1.first;
return tmp_pair1.second;
}
void Predec::leakage_feedback(double temperature)
{
drv1->leakage_feedback(temperature);
drv2->leakage_feedback(temperature);
blk1->leakage_feedback(temperature);
blk2->leakage_feedback(temperature);
driver_power.readOp.leakage = drv1->power_nand2_path.readOp.leakage +
drv1->power_nand3_path.readOp.leakage +
drv2->power_nand2_path.readOp.leakage +
drv2->power_nand3_path.readOp.leakage;
block_power.readOp.leakage = blk1->power_nand2_path.readOp.leakage +
blk1->power_nand3_path.readOp.leakage +
blk1->power_L2.readOp.leakage +
blk2->power_nand2_path.readOp.leakage +
blk2->power_nand3_path.readOp.leakage +
blk2->power_L2.readOp.leakage;
power.readOp.leakage = driver_power.readOp.leakage + block_power.readOp.leakage;
driver_power.readOp.gate_leakage = drv1->power_nand2_path.readOp.gate_leakage +
drv1->power_nand3_path.readOp.gate_leakage +
drv2->power_nand2_path.readOp.gate_leakage +
drv2->power_nand3_path.readOp.gate_leakage;
block_power.readOp.gate_leakage = blk1->power_nand2_path.readOp.gate_leakage +
blk1->power_nand3_path.readOp.gate_leakage +
blk1->power_L2.readOp.gate_leakage +
blk2->power_nand2_path.readOp.gate_leakage +
blk2->power_nand3_path.readOp.gate_leakage +
blk2->power_L2.readOp.gate_leakage;
power.readOp.gate_leakage = driver_power.readOp.gate_leakage + block_power.readOp.gate_leakage;
}
// returns <delay, risetime>
pair<double, double> Predec::get_max_delay_before_decoder(
pair<double, double> input_pair1,
pair<double, double> input_pair2) {
pair<double, double> ret_val;
double delay;
delay = drv1->delay_nand2_path + blk1->delay_nand2_path;
ret_val.first = delay;
ret_val.second = input_pair1.first;
delay = drv1->delay_nand3_path + blk1->delay_nand3_path;
if (ret_val.first < delay) {
ret_val.first = delay;
ret_val.second = input_pair1.second;
}
delay = drv2->delay_nand2_path + blk2->delay_nand2_path;
if (ret_val.first < delay) {
ret_val.first = delay;
ret_val.second = input_pair2.first;
}
delay = drv2->delay_nand3_path + blk2->delay_nand3_path;
if (ret_val.first < delay) {
ret_val.first = delay;
ret_val.second = input_pair2.second;
}
return ret_val;
}
Driver::Driver(double c_gate_load_, double c_wire_load_, double r_wire_load_,
bool is_dram)
: number_gates(0),
min_number_gates(2),
c_gate_load(c_gate_load_),
c_wire_load(c_wire_load_),
r_wire_load(r_wire_load_),
delay(0),
power(),
is_dram_(is_dram) {
for (int i = 0; i < MAX_NUMBER_GATES_STAGE; i++) {
width_n[i] = 0;
width_p[i] = 0;
}
compute_widths();
}
void Driver::compute_widths() {
double p_to_n_sz_ratio = pmos_to_nmos_sz_ratio(is_dram_);
double c_load = c_gate_load + c_wire_load;
width_n[0] = g_tp.min_w_nmos_;
width_p[0] = p_to_n_sz_ratio * g_tp.min_w_nmos_;
double F = c_load / gate_C(width_n[0] + width_p[0], 0, is_dram_);
number_gates = logical_effort(
min_number_gates,
1,
F,
width_n,
width_p,
c_load,
p_to_n_sz_ratio,
is_dram_, false,
g_tp.max_w_nmos_);
}
double Driver::compute_delay(double inrisetime) {
int i;
double rd, c_load, c_intrinsic, tf;
double this_delay = 0;
for (i = 0; i < number_gates - 1; ++i) {
rd = tr_R_on(width_n[i], NCH, 1, is_dram_);
c_load = gate_C(width_n[i+1] + width_p[i+1], 0.0, is_dram_);
c_intrinsic = drain_C_(width_p[i], PCH, 1, 1, g_tp.cell_h_def, is_dram_) +
drain_C_(width_n[i], NCH, 1, 1, g_tp.cell_h_def, is_dram_);
tf = rd * (c_intrinsic + c_load);
this_delay = horowitz(inrisetime, tf, 0.5, 0.5, RISE);
delay += this_delay;
inrisetime = this_delay / (1.0 - 0.5);
power.readOp.dynamic += (c_intrinsic + c_load) * g_tp.peri_global.Vdd *
g_tp.peri_global.Vdd;
power.readOp.leakage +=
cmos_Isub_leakage(width_n[i], width_p[i], 1, inv, is_dram_) *
g_tp.peri_global.Vdd;
power.readOp.gate_leakage +=
cmos_Ig_leakage(width_n[i], width_p[i], 1, inv, is_dram_) *
g_tp.peri_global.Vdd;
}
i = number_gates - 1;
c_load = c_gate_load + c_wire_load;
rd = tr_R_on(width_n[i], NCH, 1, is_dram_);
c_intrinsic = drain_C_(width_p[i], PCH, 1, 1, g_tp.cell_h_def, is_dram_) +
drain_C_(width_n[i], NCH, 1, 1, g_tp.cell_h_def, is_dram_);
tf = rd * (c_intrinsic + c_load) + r_wire_load *
(c_wire_load / 2 + c_gate_load);
this_delay = horowitz(inrisetime, tf, 0.5, 0.5, RISE);
delay += this_delay;
power.readOp.dynamic += (c_intrinsic + c_load) * g_tp.peri_global.Vdd *
g_tp.peri_global.Vdd;
power.readOp.leakage +=
cmos_Isub_leakage(width_n[i], width_p[i], 1, inv, is_dram_) *
g_tp.peri_global.Vdd;
power.readOp.gate_leakage +=
cmos_Ig_leakage(width_n[i], width_p[i], 1, inv, is_dram_) *
g_tp.peri_global.Vdd;
return this_delay / (1.0 - 0.5);
}