diff options
author | Nilay Vaish <nilay@cs.wisc.edu> | 2014-10-11 15:02:23 -0500 |
---|---|---|
committer | Nilay Vaish <nilay@cs.wisc.edu> | 2014-10-11 15:02:23 -0500 |
commit | e8ed7b1d1b5bef31e9874f679a5797c2e00d06f1 (patch) | |
tree | 421c9c50377aa664958685914f5504c4c019e21f /ext/dsent/model/std_cells | |
parent | a098fad174d8559037602b248b8e6f7f46bfebbb (diff) | |
download | gem5-e8ed7b1d1b5bef31e9874f679a5797c2e00d06f1.tar.xz |
ext: add the source code for DSENT
This patch adds a tool called DSENT to the ext/ directory. DSENT
is a tool that models power and area for on-chip networks. The next
patch adds a script for using the tool.
Diffstat (limited to 'ext/dsent/model/std_cells')
28 files changed, 5151 insertions, 0 deletions
diff --git a/ext/dsent/model/std_cells/ADDF.cc b/ext/dsent/model/std_cells/ADDF.cc new file mode 100644 index 000000000..99ebcdb6b --- /dev/null +++ b/ext/dsent/model/std_cells/ADDF.cc @@ -0,0 +1,671 @@ +#include "model/std_cells/ADDF.h" + +#include <cmath> + +#include "model/PortInfo.h" +#include "model/EventInfo.h" +#include "model/TransitionInfo.h" +#include "model/std_cells/StdCellLib.h" +#include "model/std_cells/CellMacros.h" +#include "model/timing_graph/ElectricalNet.h" +#include "model/timing_graph/ElectricalDriver.h" +#include "model/timing_graph/ElectricalLoad.h" +#include "model/timing_graph/ElectricalDelay.h" + +namespace DSENT +{ + using std::ceil; + using std::max; + + ADDF::ADDF(const String& instance_name_, const TechModel* tech_model_) + : StdCell(instance_name_, tech_model_) + { + initParameters(); + initProperties(); + } + + ADDF::~ADDF() + {} + + void ADDF::initProperties() + { + return; + } + + void ADDF::constructModel() + { + // All constructModel should do is create Area/NDDPower/Energy Results as + // well as instantiate any sub-instances using only the hard parameters + + createInputPort("A"); + createInputPort("B"); + createInputPort("CI"); + createOutputPort("S"); + createOutputPort("CO"); + + createLoad("A_Cap"); + createLoad("B_Cap"); + createLoad("CI_Cap"); + createDelay("A_to_S_delay"); + createDelay("B_to_S_delay"); + createDelay("CI_to_S_delay"); + createDelay("A_to_CO_delay"); + createDelay("B_to_CO_delay"); + createDelay("CI_to_CO_delay"); + createDriver("S_Ron", true); + createDriver("CO_Ron", true); + + ElectricalLoad* a_cap = getLoad("A_Cap"); + ElectricalLoad* b_cap = getLoad("B_Cap"); + ElectricalLoad* ci_cap = getLoad("CI_Cap"); + ElectricalDelay* a_to_s_delay = getDelay("A_to_S_delay"); + ElectricalDelay* b_to_s_delay = getDelay("B_to_S_delay"); + ElectricalDelay* ci_to_s_delay = getDelay("CI_to_S_delay"); + ElectricalDelay* a_to_co_delay = getDelay("A_to_CO_delay"); + ElectricalDelay* b_to_co_delay = getDelay("B_to_CO_delay"); + ElectricalDelay* ci_to_co_delay = getDelay("CI_to_CO_delay"); + ElectricalDriver* s_ron = getDriver("S_Ron"); + ElectricalDriver* co_ron = getDriver("CO_Ron"); + + getNet("A")->addDownstreamNode(a_cap); + getNet("B")->addDownstreamNode(b_cap); + getNet("CI")->addDownstreamNode(ci_cap); + a_cap->addDownstreamNode(a_to_s_delay); + b_cap->addDownstreamNode(b_to_s_delay); + ci_cap->addDownstreamNode(ci_to_s_delay); + a_cap->addDownstreamNode(a_to_co_delay); + b_cap->addDownstreamNode(b_to_co_delay); + ci_cap->addDownstreamNode(ci_to_co_delay); + + a_to_s_delay->addDownstreamNode(s_ron); + b_to_s_delay->addDownstreamNode(s_ron); + ci_to_s_delay->addDownstreamNode(s_ron); + a_to_co_delay->addDownstreamNode(co_ron); + b_to_co_delay->addDownstreamNode(co_ron); + ci_to_co_delay->addDownstreamNode(co_ron); + + s_ron->addDownstreamNode(getNet("S")); + co_ron->addDownstreamNode(getNet("CO")); + + // Create Area result + // Create NDD Power result + createElectricalAtomicResults(); + // Create ADDF Event Energy Result + createElectricalEventAtomicResult("ADDF"); + + getEventInfo("Idle")->setStaticTransitionInfos(); + + return; + } + + void ADDF::updateModel() + { + // Get parameters + double drive_strength = getDrivingStrength(); + Map<double>* cache = getTechModel()->getStdCellLib()->getStdCellCache(); + + // Standard cell cache string + String cell_name = "ADDF_X" + (String) drive_strength; + + // Get timing parameters + getLoad("A_Cap")->setLoadCap(cache->get(cell_name + "->Cap->A")); + getLoad("B_Cap")->setLoadCap(cache->get(cell_name + "->Cap->B")); + getLoad("CI_Cap")->setLoadCap(cache->get(cell_name + "->Cap->CI")); + + getDelay("A_to_S_delay")->setDelay(cache->get(cell_name + "->Delay->A_to_S")); + getDelay("B_to_S_delay")->setDelay(cache->get(cell_name + "->Delay->B_to_S")); + getDelay("CI_to_S_delay")->setDelay(cache->get(cell_name + "->Delay->CI_to_S")); + getDelay("A_to_CO_delay")->setDelay(cache->get(cell_name + "->Delay->A_to_CO")); + getDelay("B_to_CO_delay")->setDelay(cache->get(cell_name + "->Delay->B_to_CO")); + getDelay("CI_to_CO_delay")->setDelay(cache->get(cell_name + "->Delay->CI_to_CO")); + + getDriver("S_Ron")->setOutputRes(cache->get(cell_name + "->DriveRes->S")); + getDriver("CO_Ron")->setOutputRes(cache->get(cell_name + "->DriveRes->CO")); + + // Set the cell area + getAreaResult("Active")->setValue(cache->get(cell_name + "->Area->Active")); + getAreaResult("Metal1Wire")->setValue(cache->get(cell_name + "->Area->Metal1Wire")); + + return; + } + + void ADDF::evaluateModel() + { + return; + } + + void ADDF::useModel() + { + // Get parameters + double drive_strength = getDrivingStrength(); + Map<double>* cache = getTechModel()->getStdCellLib()->getStdCellCache(); + + // Standard cell cache string + String cell_name = "ADDF_X" + (String) drive_strength; + + // Propagate the transition info and get the 0->1 transition count + propagateTransitionInfo(); + double P_A = getInputPort("A")->getTransitionInfo().getProbability1(); + double P_B = getInputPort("B")->getTransitionInfo().getProbability1(); + double P_CI = getInputPort("CI")->getTransitionInfo().getProbability1(); + double A_num_trans_01 = getInputPort("A")->getTransitionInfo().getNumberTransitions01(); + double B_num_trans_01 = getInputPort("B")->getTransitionInfo().getNumberTransitions01(); + double CI_num_trans_01 = getInputPort("CI")->getTransitionInfo().getNumberTransitions01(); + double P_num_trans_01 = m_trans_P_.getNumberTransitions01(); + double G_num_trans_01 = m_trans_G_.getNumberTransitions01(); + double CP_num_trans_01 = m_trans_CP_.getNumberTransitions01(); + double S_num_trans_01 = getOutputPort("S")->getTransitionInfo().getNumberTransitions01(); + double CO_num_trans_01 = getOutputPort("CO")->getTransitionInfo().getNumberTransitions01(); + + // Calculate leakage + double leakage = 0; + leakage += cache->get(cell_name + "->Leakage->!A!B!CI") * (1 - P_A) * (1 - P_B) * (1 - P_CI); + leakage += cache->get(cell_name + "->Leakage->!A!BCI") * (1 - P_A) * (1 - P_B) * P_CI; + leakage += cache->get(cell_name + "->Leakage->!AB!CI") * (1 - P_A) * P_B * (1 - P_CI); + leakage += cache->get(cell_name + "->Leakage->!ABCI") * (1 - P_A) * P_B * P_CI; + leakage += cache->get(cell_name + "->Leakage->A!B!CI") * P_A * (1 - P_B) * (1 - P_CI); + leakage += cache->get(cell_name + "->Leakage->A!BCI") * P_A * (1 - P_B) * P_CI; + leakage += cache->get(cell_name + "->Leakage->AB!CI") * P_A * P_B * (1 - P_CI); + leakage += cache->get(cell_name + "->Leakage->ABCI") * P_A * P_B * P_CI; + getNddPowerResult("Leakage")->setValue(leakage); + + // Get VDD + double vdd = getTechModel()->get("Vdd"); + + // Get capacitances + double a_b_cap = cache->get(cell_name + "->Cap->A_b"); + double b_b_cap = cache->get(cell_name + "->Cap->B_b"); + double ci_b_cap = cache->get(cell_name + "->Cap->CI_b"); + double p_cap = cache->get(cell_name + "->Cap->P"); + double p_b_cap = cache->get(cell_name + "->Cap->P_b"); + double s_cap = cache->get(cell_name + "->Cap->S"); + double cp_cap = cache->get(cell_name + "->Cap->CP"); + double g_cap = cache->get(cell_name + "->Cap->G"); + double co_cap = cache->get(cell_name + "->Cap->CO"); + double s_load_cap = getNet("S")->getTotalDownstreamCap(); + double co_load_cap = getNet("CO")->getTotalDownstreamCap(); + + // Calculate ADDF Event energy + double addf_event_energy = 0.0; + addf_event_energy += a_b_cap * A_num_trans_01; + addf_event_energy += b_b_cap * B_num_trans_01; + addf_event_energy += ci_b_cap * CI_num_trans_01; + addf_event_energy += (p_cap + p_b_cap) * P_num_trans_01; + addf_event_energy += (s_cap + s_load_cap) * S_num_trans_01; + addf_event_energy += cp_cap * CP_num_trans_01; + addf_event_energy += g_cap * G_num_trans_01; + addf_event_energy += (co_cap + co_load_cap) * CO_num_trans_01; + addf_event_energy *= vdd * vdd; + getEventResult("ADDF")->setValue(addf_event_energy); + + return; + } + + void ADDF::propagateTransitionInfo() + { + const TransitionInfo& trans_A = getInputPort("A")->getTransitionInfo(); + const TransitionInfo& trans_B = getInputPort("B")->getTransitionInfo(); + const TransitionInfo& trans_CI = getInputPort("CI")->getTransitionInfo(); + + double max_freq_mult = max(max(trans_A.getFrequencyMultiplier(), trans_B.getFrequencyMultiplier()), trans_CI.getFrequencyMultiplier()); + const TransitionInfo& scaled_trans_A = trans_A.scaleFrequencyMultiplier(max_freq_mult); + const TransitionInfo& scaled_trans_B = trans_B.scaleFrequencyMultiplier(max_freq_mult); + const TransitionInfo& scaled_trans_CI = trans_CI.scaleFrequencyMultiplier(max_freq_mult); + + double A_prob_00 = scaled_trans_A.getNumberTransitions00() / max_freq_mult; + double A_prob_01 = scaled_trans_A.getNumberTransitions01() / max_freq_mult; + double A_prob_10 = A_prob_01; + double A_prob_11 = scaled_trans_A.getNumberTransitions11() / max_freq_mult; + double B_prob_00 = scaled_trans_B.getNumberTransitions00() / max_freq_mult; + double B_prob_01 = scaled_trans_B.getNumberTransitions01() / max_freq_mult; + double B_prob_10 = B_prob_01; + double B_prob_11 = scaled_trans_B.getNumberTransitions11() / max_freq_mult; + double CI_prob_00 = scaled_trans_CI.getNumberTransitions00() / max_freq_mult; + double CI_prob_01 = scaled_trans_CI.getNumberTransitions01() / max_freq_mult; + double CI_prob_10 = CI_prob_01; + double CI_prob_11 = scaled_trans_CI.getNumberTransitions11() / max_freq_mult; + + // Set P transition info + double P_prob_00 = A_prob_00 * B_prob_00 + + A_prob_01 * B_prob_01 + + A_prob_10 * B_prob_10 + + A_prob_11 * B_prob_11; + double P_prob_01 = A_prob_00 * B_prob_01 + + A_prob_01 * B_prob_00 + + A_prob_10 * B_prob_11 + + A_prob_11 * B_prob_10; + double P_prob_10 = P_prob_01; + double P_prob_11 = A_prob_00 * B_prob_11 + + A_prob_01 * B_prob_10 + + A_prob_10 * B_prob_01 + + A_prob_11 * B_prob_00; + + // Set G transition info + double G_prob_00 = A_prob_11 * B_prob_11; + double G_prob_01 = A_prob_11 * B_prob_10 + + A_prob_10 * (B_prob_11 + B_prob_10); + double G_prob_10 = G_prob_01; + double G_prob_11 = A_prob_00 + + A_prob_01 * (B_prob_00 + B_prob_10) + + A_prob_10 * (B_prob_00 + B_prob_01) + + A_prob_11 * B_prob_00; + + // Set CP transition info + double CP_prob_00 = P_prob_11 * CI_prob_11; + double CP_prob_01 = P_prob_11 * CI_prob_10 + + P_prob_10 * (CI_prob_11 + CI_prob_10); + double CP_prob_10 = CP_prob_01; + double CP_prob_11 = P_prob_00 + + P_prob_01 * (CI_prob_00 + CI_prob_10) + + P_prob_10 * (CI_prob_00 + CI_prob_01) + + P_prob_11 * CI_prob_00; + + // Set S transition info + double S_prob_00 = P_prob_00 * CI_prob_00 + + P_prob_01 * CI_prob_01 + + P_prob_10 * CI_prob_10 + + P_prob_11 * CI_prob_11; + double S_prob_01 = P_prob_00 * CI_prob_01 + + P_prob_01 * CI_prob_00 + + P_prob_10 * CI_prob_11 + + P_prob_11 * CI_prob_10; + double S_prob_11 = P_prob_00 * CI_prob_11 + + P_prob_01 * CI_prob_10 + + P_prob_10 * CI_prob_01 + + P_prob_11 * CI_prob_00; + + // Set CO transition info + double CO_prob_00 = G_prob_11 * CP_prob_11; + double CO_prob_01 = G_prob_11 * CP_prob_10 + + G_prob_10 * (CP_prob_11 + CP_prob_10); + double CO_prob_11 = G_prob_00 + + G_prob_01 * (CP_prob_00 + CP_prob_10) + + G_prob_10 * (CP_prob_00 + CP_prob_01) + + G_prob_11 * CP_prob_00; + + m_trans_P_ = TransitionInfo(P_prob_00 * max_freq_mult, P_prob_01 * max_freq_mult, P_prob_11 * max_freq_mult); + m_trans_G_ = TransitionInfo(G_prob_00 * max_freq_mult, G_prob_01 * max_freq_mult, G_prob_11 * max_freq_mult); + m_trans_CP_ = TransitionInfo(CP_prob_00 * max_freq_mult, CP_prob_01 * max_freq_mult, CP_prob_11 * max_freq_mult); + + // Check that probabilities add up to 1.0 with some finite tolerance + ASSERT(LibUtil::Math::isEqual((S_prob_00 + S_prob_01 + S_prob_01 + S_prob_11), 1.0), + "[Error] " + getInstanceName() + "Output S transition probabilities must add up to 1 (" + + (String) S_prob_00 + ", " + (String) S_prob_01 + ", " + (String) S_prob_11 + ")!"); + + // Check that probabilities add up to 1.0 with some finite tolerance + ASSERT(LibUtil::Math::isEqual((CO_prob_00 + CO_prob_01 + CO_prob_01 + CO_prob_11), 1.0), + "[Error] " + getInstanceName() + "Output S transition probabilities must add up to 1 (" + + (String) CO_prob_00 + ", " + (String) CO_prob_01 + ", " + (String) CO_prob_11 + ")!"); + + // Turn probability of transitions per cycle into number of transitions per time unit + TransitionInfo trans_S(S_prob_00 * max_freq_mult, S_prob_01 * max_freq_mult, S_prob_11 * max_freq_mult); + getOutputPort("S")->setTransitionInfo(trans_S); + TransitionInfo trans_CO(CO_prob_00 * max_freq_mult, CO_prob_01 * max_freq_mult, CO_prob_11 * max_freq_mult); + getOutputPort("CO")->setTransitionInfo(trans_CO); + return; + } + + // Creates the standard cell, characterizes and abstracts away the details + void ADDF::cacheStdCell(StdCellLib* cell_lib_, double drive_strength_) + { + // Get parameters + double gate_pitch = cell_lib_->getTechModel()->get("Gate->PitchContacted"); + Map<double>* cache = cell_lib_->getStdCellCache(); + + // Standard cell cache string + String cell_name = "ADDF_X" + (String) drive_strength_; + + Log::printLine("=== " + cell_name + " ==="); + + // Now actually build the full standard cell model + createInputPort("A"); + createInputPort("B"); + createInputPort("CI"); + createOutputPort("S"); + createOutputPort("CO"); + + createNet("A_b"); + createNet("B_b"); + createNet("CI_b"); + createNet("P"); + createNet("P_b"); + createNet("G"); //actually G_b since it is NAND'ed + createNet("CP"); //actually (CP)_b since it is NAND'ed + + // Adds macros + CellMacros::addInverter(this, "INV1", false, true, "A", "A_b"); + CellMacros::addInverter(this, "INV2", false, true, "B", "B_b"); + CellMacros::addInverter(this, "INV3", false, true, "CI", "CI_b"); + CellMacros::addInverter(this, "INV4", false, true, "P", "P_b"); + CellMacros::addTristate(this, "INVZ1", false, true, true, true, "B", "A", "A_b", "P"); + CellMacros::addTristate(this, "INVZ2", false, true, true, true, "B_b", "A_b", "A", "P"); + CellMacros::addTristate(this, "INVZ3", true, true, true, true, "P", "CI", "CI_b", "S"); + CellMacros::addTristate(this, "INVZ4", true, true, true, true, "P_b", "CI_b", "CI", "S"); + CellMacros::addNand2(this, "NAND1", false, true, true, "CI", "P", "CP"); + CellMacros::addNand2(this, "NAND2", false, true, true, "A", "B", "G"); + CellMacros::addNand2(this, "NAND3", true, true, true, "CP", "G", "CO"); + + // I have no idea how to size each of the parts haha + CellMacros::updateInverter(this, "INV1", drive_strength_ * 0.250); + CellMacros::updateInverter(this, "INV2", drive_strength_ * 0.250); + CellMacros::updateInverter(this, "INV3", drive_strength_ * 0.250); + CellMacros::updateInverter(this, "INV4", drive_strength_ * 0.500); + CellMacros::updateTristate(this, "INVZ1", drive_strength_ * 0.250); + CellMacros::updateTristate(this, "INVZ2", drive_strength_ * 0.250); + CellMacros::updateTristate(this, "INVZ3", drive_strength_ * 0.500); + CellMacros::updateTristate(this, "INVZ4", drive_strength_ * 0.500); + CellMacros::updateNand2(this, "NAND1", drive_strength_ * 0.500); + CellMacros::updateNand2(this, "NAND2", drive_strength_ * 0.500); + CellMacros::updateNand2(this, "NAND3", drive_strength_ * 1.000); + + // Cache area result + double area = 0.0; + area += gate_pitch * getTotalHeight() * 1; + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INV1_GatePitches").toDouble(); + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INV2_GatePitches").toDouble(); + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INV3_GatePitches").toDouble(); + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INV4_GatePitches").toDouble(); + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INVZ1_GatePitches").toDouble(); + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INVZ2_GatePitches").toDouble(); + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INVZ3_GatePitches").toDouble(); + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INVZ4_GatePitches").toDouble(); + area += gate_pitch * getTotalHeight() * getGenProperties()->get("NAND1_GatePitches").toDouble(); + area += gate_pitch * getTotalHeight() * getGenProperties()->get("NAND2_GatePitches").toDouble(); + area += gate_pitch * getTotalHeight() * getGenProperties()->get("NAND3_GatePitches").toDouble(); + cache->set(cell_name + "->Area->Active", area); + cache->set(cell_name + "->Area->Metal1Wire", area); + Log::printLine(cell_name + "->Area->Active=" + (String) area); + Log::printLine(cell_name + "->Area->Metal1Wire=" + (String) area); + + // -------------------------------------------------------------------- + // Leakage Model Calculation + // -------------------------------------------------------------------- + // Cache leakage power results (for every single signal combination) + double leakage_000 = 0; //!A, !B, !CI + double leakage_001 = 0; //!A, !B, CI + double leakage_010 = 0; //!A, B, !CI + double leakage_011 = 0; //!A, B, CI + double leakage_100 = 0; //A, !B, !CI + double leakage_101 = 0; //A, !B, CI + double leakage_110 = 0; //A, B, !CI + double leakage_111 = 0; //A, B, CI + + //This is so painful... + leakage_000 += getGenProperties()->get("INV1_LeakagePower_0").toDouble(); + leakage_000 += getGenProperties()->get("INV2_LeakagePower_0").toDouble(); + leakage_000 += getGenProperties()->get("INV3_LeakagePower_0").toDouble(); + leakage_000 += getGenProperties()->get("INV4_LeakagePower_0").toDouble(); + leakage_000 += getGenProperties()->get("INVZ1_LeakagePower_010_0").toDouble(); + leakage_000 += getGenProperties()->get("INVZ2_LeakagePower_101_0").toDouble(); + leakage_000 += getGenProperties()->get("INVZ3_LeakagePower_010_0").toDouble(); + leakage_000 += getGenProperties()->get("INVZ4_LeakagePower_101_0").toDouble(); + leakage_000 += getGenProperties()->get("NAND1_LeakagePower_00").toDouble(); + leakage_000 += getGenProperties()->get("NAND2_LeakagePower_00").toDouble(); + leakage_000 += getGenProperties()->get("NAND3_LeakagePower_11").toDouble(); + + leakage_001 += getGenProperties()->get("INV1_LeakagePower_0").toDouble(); + leakage_001 += getGenProperties()->get("INV2_LeakagePower_0").toDouble(); + leakage_001 += getGenProperties()->get("INV3_LeakagePower_1").toDouble(); + leakage_001 += getGenProperties()->get("INV4_LeakagePower_0").toDouble(); + leakage_001 += getGenProperties()->get("INVZ1_LeakagePower_010_0").toDouble(); + leakage_001 += getGenProperties()->get("INVZ2_LeakagePower_101_0").toDouble(); + leakage_001 += getGenProperties()->get("INVZ3_LeakagePower_100_1").toDouble(); + leakage_001 += getGenProperties()->get("INVZ4_LeakagePower_011_1").toDouble(); + leakage_001 += getGenProperties()->get("NAND1_LeakagePower_10").toDouble(); + leakage_001 += getGenProperties()->get("NAND2_LeakagePower_00").toDouble(); + leakage_001 += getGenProperties()->get("NAND3_LeakagePower_11").toDouble(); + + leakage_010 += getGenProperties()->get("INV1_LeakagePower_0").toDouble(); + leakage_010 += getGenProperties()->get("INV2_LeakagePower_1").toDouble(); + leakage_010 += getGenProperties()->get("INV3_LeakagePower_0").toDouble(); + leakage_010 += getGenProperties()->get("INV4_LeakagePower_1").toDouble(); + leakage_010 += getGenProperties()->get("INVZ1_LeakagePower_011_1").toDouble(); + leakage_010 += getGenProperties()->get("INVZ2_LeakagePower_100_1").toDouble(); + leakage_010 += getGenProperties()->get("INVZ3_LeakagePower_011_1").toDouble(); + leakage_010 += getGenProperties()->get("INVZ4_LeakagePower_100_1").toDouble(); + leakage_010 += getGenProperties()->get("NAND1_LeakagePower_01").toDouble(); + leakage_010 += getGenProperties()->get("NAND2_LeakagePower_01").toDouble(); + leakage_010 += getGenProperties()->get("NAND3_LeakagePower_11").toDouble(); + + leakage_011 += getGenProperties()->get("INV1_LeakagePower_0").toDouble(); + leakage_011 += getGenProperties()->get("INV2_LeakagePower_1").toDouble(); + leakage_011 += getGenProperties()->get("INV3_LeakagePower_1").toDouble(); + leakage_011 += getGenProperties()->get("INV4_LeakagePower_1").toDouble(); + leakage_011 += getGenProperties()->get("INVZ1_LeakagePower_011_1").toDouble(); + leakage_011 += getGenProperties()->get("INVZ2_LeakagePower_100_1").toDouble(); + leakage_011 += getGenProperties()->get("INVZ3_LeakagePower_101_0").toDouble(); + leakage_011 += getGenProperties()->get("INVZ4_LeakagePower_010_0").toDouble(); + leakage_011 += getGenProperties()->get("NAND1_LeakagePower_11").toDouble(); + leakage_011 += getGenProperties()->get("NAND2_LeakagePower_01").toDouble(); + leakage_011 += getGenProperties()->get("NAND3_LeakagePower_01").toDouble(); + + leakage_100 += getGenProperties()->get("INV1_LeakagePower_1").toDouble(); + leakage_100 += getGenProperties()->get("INV2_LeakagePower_0").toDouble(); + leakage_100 += getGenProperties()->get("INV3_LeakagePower_0").toDouble(); + leakage_100 += getGenProperties()->get("INV4_LeakagePower_1").toDouble(); + leakage_100 += getGenProperties()->get("INVZ1_LeakagePower_100_1").toDouble(); + leakage_100 += getGenProperties()->get("INVZ2_LeakagePower_011_1").toDouble(); + leakage_100 += getGenProperties()->get("INVZ3_LeakagePower_011_1").toDouble(); + leakage_100 += getGenProperties()->get("INVZ4_LeakagePower_100_1").toDouble(); + leakage_100 += getGenProperties()->get("NAND1_LeakagePower_01").toDouble(); + leakage_100 += getGenProperties()->get("NAND2_LeakagePower_10").toDouble(); + leakage_100 += getGenProperties()->get("NAND3_LeakagePower_11").toDouble(); + + leakage_101 += getGenProperties()->get("INV1_LeakagePower_1").toDouble(); + leakage_101 += getGenProperties()->get("INV2_LeakagePower_0").toDouble(); + leakage_101 += getGenProperties()->get("INV3_LeakagePower_1").toDouble(); + leakage_101 += getGenProperties()->get("INV4_LeakagePower_1").toDouble(); + leakage_101 += getGenProperties()->get("INVZ1_LeakagePower_100_1").toDouble(); + leakage_101 += getGenProperties()->get("INVZ2_LeakagePower_011_1").toDouble(); + leakage_101 += getGenProperties()->get("INVZ3_LeakagePower_101_0").toDouble(); + leakage_101 += getGenProperties()->get("INVZ4_LeakagePower_010_0").toDouble(); + leakage_101 += getGenProperties()->get("NAND1_LeakagePower_11").toDouble(); + leakage_101 += getGenProperties()->get("NAND2_LeakagePower_10").toDouble(); + leakage_101 += getGenProperties()->get("NAND3_LeakagePower_01").toDouble(); + + leakage_110 += getGenProperties()->get("INV1_LeakagePower_1").toDouble(); + leakage_110 += getGenProperties()->get("INV2_LeakagePower_1").toDouble(); + leakage_110 += getGenProperties()->get("INV3_LeakagePower_0").toDouble(); + leakage_110 += getGenProperties()->get("INV4_LeakagePower_0").toDouble(); + leakage_110 += getGenProperties()->get("INVZ1_LeakagePower_101_0").toDouble(); + leakage_110 += getGenProperties()->get("INVZ2_LeakagePower_010_0").toDouble(); + leakage_110 += getGenProperties()->get("INVZ3_LeakagePower_010_0").toDouble(); + leakage_110 += getGenProperties()->get("INVZ4_LeakagePower_101_0").toDouble(); + leakage_110 += getGenProperties()->get("NAND1_LeakagePower_00").toDouble(); + leakage_110 += getGenProperties()->get("NAND2_LeakagePower_11").toDouble(); + leakage_110 += getGenProperties()->get("NAND3_LeakagePower_10").toDouble(); + + leakage_111 += getGenProperties()->get("INV1_LeakagePower_1").toDouble(); + leakage_111 += getGenProperties()->get("INV2_LeakagePower_1").toDouble(); + leakage_111 += getGenProperties()->get("INV3_LeakagePower_1").toDouble(); + leakage_111 += getGenProperties()->get("INV4_LeakagePower_0").toDouble(); + leakage_111 += getGenProperties()->get("INVZ1_LeakagePower_101_0").toDouble(); + leakage_111 += getGenProperties()->get("INVZ2_LeakagePower_010_0").toDouble(); + leakage_111 += getGenProperties()->get("INVZ3_LeakagePower_100_1").toDouble(); + leakage_111 += getGenProperties()->get("INVZ4_LeakagePower_011_1").toDouble(); + leakage_111 += getGenProperties()->get("NAND1_LeakagePower_10").toDouble(); + leakage_111 += getGenProperties()->get("NAND2_LeakagePower_11").toDouble(); + leakage_111 += getGenProperties()->get("NAND3_LeakagePower_10").toDouble(); + + cache->set(cell_name + "->Leakage->!A!B!CI", leakage_000); + cache->set(cell_name + "->Leakage->!A!BCI", leakage_001); + cache->set(cell_name + "->Leakage->!AB!CI", leakage_010); + cache->set(cell_name + "->Leakage->!ABCI", leakage_011); + cache->set(cell_name + "->Leakage->A!B!CI", leakage_100); + cache->set(cell_name + "->Leakage->A!BCI", leakage_101); + cache->set(cell_name + "->Leakage->AB!CI", leakage_110); + cache->set(cell_name + "->Leakage->ABCI", leakage_111); + Log::printLine(cell_name + "->Leakage->!A!B!CI=" + (String) leakage_000); + Log::printLine(cell_name + "->Leakage->!A!BCI=" + (String) leakage_001); + Log::printLine(cell_name + "->Leakage->!AB!CI=" + (String) leakage_010); + Log::printLine(cell_name + "->Leakage->!ABCI=" + (String) leakage_011); + Log::printLine(cell_name + "->Leakage->A!B!CI=" + (String) leakage_100); + Log::printLine(cell_name + "->Leakage->A!BCI=" + (String) leakage_101); + Log::printLine(cell_name + "->Leakage->AB!CI=" + (String) leakage_110); + Log::printLine(cell_name + "->Leakage->ABCI=" + (String) leakage_111); + // -------------------------------------------------------------------- + + /* + // Cache event energy results + double event_a_flip = 0.0; + event_a_flip += getGenProperties()->get("INV1_A_Flip").toDouble() + getGenProperties()->get("INV1_ZN_Flip").toDouble(); + event_a_flip += getGenProperties()->get("INVZ1_OE_Flip").toDouble() + getGenProperties()->get("INVZ1_OEN_Flip").toDouble(); + event_a_flip += getGenProperties()->get("INVZ2_OE_Flip").toDouble() + getGenProperties()->get("INVZ2_OEN_Flip").toDouble(); + event_a_flip += getGenProperties()->get("NAND2_A1_Flip").toDouble(); + cache->set(cell_name + "->Event_A_Flip", event_a_flip); + Log::printLine(cell_name + "->Event_A_Flip=" + (String) event_a_flip); + + double event_b_flip = 0.0; + event_b_flip += getGenProperties()->get("INV2_A_Flip").toDouble() + getGenProperties()->get("INV2_ZN_Flip").toDouble(); + event_b_flip += getGenProperties()->get("INVZ1_A_Flip").toDouble(); + event_b_flip += getGenProperties()->get("INVZ2_A_Flip").toDouble(); + event_b_flip += getGenProperties()->get("NAND2_A1_Flip").toDouble(); + cache->set(cell_name + "->Event_B_Flip", event_b_flip); + Log::printLine(cell_name + "->Event_B_Flip=" + (String) event_b_flip); + + double event_ci_flip = 0.0; + event_ci_flip += getGenProperties()->get("INV3_A_Flip").toDouble() + getGenProperties()->get("INV3_ZN_Flip").toDouble(); + event_ci_flip += getGenProperties()->get("INVZ3_OE_Flip").toDouble() + getGenProperties()->get("INVZ3_OEN_Flip").toDouble(); + event_ci_flip += getGenProperties()->get("INVZ4_OE_Flip").toDouble() + getGenProperties()->get("INVZ4_OEN_Flip").toDouble(); + event_ci_flip += getGenProperties()->get("NAND1_A1_Flip").toDouble(); + cache->set(cell_name + "->Event_CI_Flip", event_ci_flip); + Log::printLine(cell_name + "->Event_CI_Flip=" + (String) event_ci_flip); + + double event_p_flip = 0.0; + event_p_flip += getGenProperties()->get("INV4_A_Flip").toDouble() + getGenProperties()->get("INV4_ZN_Flip").toDouble(); + event_p_flip += getGenProperties()->get("INVZ1_ZN_Flip").toDouble(); + event_p_flip += getGenProperties()->get("INVZ2_ZN_Flip").toDouble(); + event_p_flip += getGenProperties()->get("NAND1_A2_Flip").toDouble(); + cache->set(cell_name + "->Event_P_Flip", event_p_flip); + Log::printLine(cell_name + "->Event_P_Flip=" + (String) event_p_flip); + + double event_s_flip = 0.0; + event_s_flip += getGenProperties()->get("INVZ3_ZN_Flip").toDouble(); + event_s_flip += getGenProperties()->get("INVZ4_ZN_Flip").toDouble(); + cache->set(cell_name + "->Event_S_Flip", event_s_flip); + Log::printLine(cell_name + "->Event_S_Flip=" + (String) event_s_flip); + + double event_cp_flip = 0.0; + event_cp_flip += getGenProperties()->get("NAND1_ZN_Flip").toDouble(); + event_cp_flip += getGenProperties()->get("NAND3_A2_Flip").toDouble(); + cache->set(cell_name + "->Event_CP_Flip", event_cp_flip); + Log::printLine(cell_name + "->Event_CP_Flip=" + (String) event_cp_flip); + + double event_g_flip = 0.0; + event_g_flip += getGenProperties()->get("NAND2_ZN_Flip").toDouble(); + event_g_flip += getGenProperties()->get("NAND3_A2_Flip").toDouble(); + cache->set(cell_name + "->Event_G_Flip", event_g_flip); + Log::printLine(cell_name + "->Event_G_Flip=" + (String) event_g_flip); + + double event_co_flip = 0.0; + event_co_flip += getGenProperties()->get("NAND3_ZN_Flip").toDouble(); + cache->set(cell_name + "->Event_CO_Flip", event_co_flip); + Log::printLine(cell_name + "->Event_CO_Flip=" + (String) event_co_flip); + */ + // -------------------------------------------------------------------- + // Get Node Capacitances + // -------------------------------------------------------------------- + double a_cap = getNet("A")->getTotalDownstreamCap(); + double b_cap = getNet("B")->getTotalDownstreamCap(); + double ci_cap = getNet("CI")->getTotalDownstreamCap(); + double a_b_cap = getNet("A_b")->getTotalDownstreamCap(); + double b_b_cap = getNet("B_b")->getTotalDownstreamCap(); + double ci_b_cap = getNet("CI_b")->getTotalDownstreamCap(); + double p_cap = getNet("P")->getTotalDownstreamCap(); + double p_b_cap = getNet("P_b")->getTotalDownstreamCap(); + double s_cap = getNet("S")->getTotalDownstreamCap(); + double cp_cap = getNet("CP")->getTotalDownstreamCap(); + double g_cap = getNet("G")->getTotalDownstreamCap(); + double co_cap = getNet("CO")->getTotalDownstreamCap(); + + cache->set(cell_name + "->Cap->A", a_cap); + cache->set(cell_name + "->Cap->B", b_cap); + cache->set(cell_name + "->Cap->CI", ci_cap); + cache->set(cell_name + "->Cap->A_b", a_b_cap); + cache->set(cell_name + "->Cap->B_b", b_b_cap); + cache->set(cell_name + "->Cap->CI_b", ci_b_cap); + cache->set(cell_name + "->Cap->P", p_cap); + cache->set(cell_name + "->Cap->P_b", p_b_cap); + cache->set(cell_name + "->Cap->S", s_cap); + cache->set(cell_name + "->Cap->CP", cp_cap); + cache->set(cell_name + "->Cap->G", g_cap); + cache->set(cell_name + "->Cap->CO", co_cap); + + Log::printLine(cell_name + "->Cap->A=" + (String) a_cap); + Log::printLine(cell_name + "->Cap->B=" + (String) b_cap); + Log::printLine(cell_name + "->Cap->CI=" + (String) ci_cap); + Log::printLine(cell_name + "->Cap->A_b=" + (String) a_b_cap); + Log::printLine(cell_name + "->Cap->B_b=" + (String) b_b_cap); + Log::printLine(cell_name + "->Cap->CI_b=" + (String) ci_b_cap); + Log::printLine(cell_name + "->Cap->P=" + (String) p_cap); + Log::printLine(cell_name + "->Cap->P_b=" + (String) p_b_cap); + Log::printLine(cell_name + "->Cap->S=" + (String) s_cap); + Log::printLine(cell_name + "->Cap->CP=" + (String) cp_cap); + Log::printLine(cell_name + "->Cap->G=" + (String) g_cap); + Log::printLine(cell_name + "->Cap->CO=" + (String) co_cap); + // -------------------------------------------------------------------- + + // -------------------------------------------------------------------- + // Build Internal Delay Model + // -------------------------------------------------------------------- + // Build abstracted timing model + double s_ron = (getDriver("INVZ3_RonZN")->getOutputRes() + getDriver("INVZ4_RonZN")->getOutputRes()) / 2; + double co_ron = getDriver("NAND3_RonZN")->getOutputRes(); + + double a_to_s_delay = 0.0; + a_to_s_delay += getDriver("INV1_RonZN")->calculateDelay(); + a_to_s_delay += max(getDriver("INVZ1_RonZN")->calculateDelay(), getDriver("INVZ2_RonZN")->calculateDelay()); + a_to_s_delay += max(getDriver("INVZ3_RonZN")->calculateDelay(), getDriver("INV4_RonZN")->calculateDelay() + getDriver("INVZ4_RonZN")->calculateDelay()); + + double b_to_s_delay = 0.0; + b_to_s_delay += max(getDriver("INVZ1_RonZN")->calculateDelay(), getDriver("INV2_RonZN")->calculateDelay() + getDriver("INVZ2_RonZN")->calculateDelay()); + b_to_s_delay += max(getDriver("INVZ3_RonZN")->calculateDelay(), getDriver("INV4_RonZN")->calculateDelay() + getDriver("INVZ4_RonZN")->calculateDelay()); + + double ci_to_s_delay = 0.0; + ci_to_s_delay += getDriver("INV3_RonZN")->calculateDelay(); + ci_to_s_delay += max(getDriver("INVZ3_RonZN")->calculateDelay(), getDriver("INVZ4_RonZN")->calculateDelay()); + + double a_to_co_delay = 0.0; + a_to_co_delay += max(getDriver("NAND2_RonZN")->calculateDelay(), //Generate path + getDriver("INV1_RonZN")->calculateDelay() + //Carry propagate path + max(getDriver("INVZ1_RonZN")->calculateDelay(), getDriver("INVZ2_RonZN")->calculateDelay()) + + getDriver("NAND1_RonZN")->calculateDelay()); + a_to_co_delay += getDriver("NAND3_RonZN")->calculateDelay(); + + double b_to_co_delay = 0.0; + b_to_co_delay += max(getDriver("NAND2_RonZN")->calculateDelay(), //Generate path + max(getDriver("INVZ1_RonZN")->calculateDelay(), //Carry propagate path + getDriver("INV2_RonZN")->calculateDelay() + getDriver("INVZ2_RonZN")->calculateDelay()) + + getDriver("NAND1_RonZN")->calculateDelay()); + b_to_co_delay += getDriver("NAND3_RonZN")->calculateDelay(); + + double ci_to_co_delay = 0.0; + ci_to_co_delay += getDriver("NAND1_RonZN")->calculateDelay(); + ci_to_co_delay += getDriver("NAND3_RonZN")->calculateDelay(); + + cache->set(cell_name + "->DriveRes->S", s_ron); + cache->set(cell_name + "->DriveRes->CO", co_ron); + + cache->set(cell_name + "->Delay->A_to_S", a_to_s_delay); + cache->set(cell_name + "->Delay->B_to_S", b_to_s_delay); + cache->set(cell_name + "->Delay->CI_to_S", ci_to_s_delay); + cache->set(cell_name + "->Delay->A_to_CO", a_to_co_delay); + cache->set(cell_name + "->Delay->B_to_CO", b_to_co_delay); + cache->set(cell_name + "->Delay->CI_to_CO", ci_to_co_delay); + + Log::printLine(cell_name + "->DriveRes->S=" + (String) s_ron); + Log::printLine(cell_name + "->DriveRes->CO=" + (String) co_ron); + Log::printLine(cell_name + "->Delay->A_to_S=" + (String) a_to_s_delay); + Log::printLine(cell_name + "->Delay->B_to_S=" + (String) b_to_s_delay); + Log::printLine(cell_name + "->Delay->CI_to_S=" + (String) ci_to_s_delay); + Log::printLine(cell_name + "->Delay->A_to_CO=" + (String) a_to_co_delay); + Log::printLine(cell_name + "->Delay->B_to_CO=" + (String) b_to_co_delay); + Log::printLine(cell_name + "->Delay->CI_to_CO=" + (String) ci_to_co_delay); + // -------------------------------------------------------------------- + + return; + + } + +} // namespace DSENT + diff --git a/ext/dsent/model/std_cells/ADDF.h b/ext/dsent/model/std_cells/ADDF.h new file mode 100644 index 000000000..03bae5d4f --- /dev/null +++ b/ext/dsent/model/std_cells/ADDF.h @@ -0,0 +1,39 @@ +#ifndef __DSENT_MODEL_STD_CELLS_ADDF_H__ +#define __DSENT_MODEL_STD_CELLS_ADDF_H__ + +#include "util/CommonType.h" +#include "model/std_cells/StdCell.h" +#include "model/TransitionInfo.h" + +namespace DSENT +{ + // A full adder standard cell + class ADDF : public StdCell + { + public: + ADDF(const String& instance_name_, const TechModel* tech_model_); + virtual ~ADDF(); + + public: + // Set a list of properties needed to update model + void initProperties(); + // Cache the standard cell + void cacheStdCell(StdCellLib* cell_lib_, double drive_strength_); + private: + TransitionInfo m_trans_P_; + TransitionInfo m_trans_G_; + TransitionInfo m_trans_CP_; + + protected: + // Build the model + virtual void constructModel(); + virtual void updateModel(); + virtual void evaluateModel(); + virtual void useModel(); + virtual void propagateTransitionInfo(); + + }; // class ADDF +} // namespace DSENT + +#endif // __DSENT_MODEL_STD_CELLS_ADDF_H__ + diff --git a/ext/dsent/model/std_cells/AND2.cc b/ext/dsent/model/std_cells/AND2.cc new file mode 100644 index 000000000..2113c2397 --- /dev/null +++ b/ext/dsent/model/std_cells/AND2.cc @@ -0,0 +1,272 @@ +#include "model/std_cells/AND2.h" + +#include <cmath> + +#include "model/PortInfo.h" +#include "model/TransitionInfo.h" +#include "model/EventInfo.h" +#include "model/std_cells/StdCellLib.h" +#include "model/std_cells/CellMacros.h" +#include "model/timing_graph/ElectricalNet.h" +#include "model/timing_graph/ElectricalDriver.h" +#include "model/timing_graph/ElectricalLoad.h" +#include "model/timing_graph/ElectricalDelay.h" + +namespace DSENT +{ + using std::max; + + AND2::AND2(const String& instance_name_, const TechModel* tech_model_) + : StdCell(instance_name_, tech_model_) + { + initProperties(); + } + + AND2::~AND2() + {} + + void AND2::initProperties() + { + return; + } + + void AND2::constructModel() + { + // All constructModel should do is create Area/NDDPower/Energy Results as + // well as instantiate any sub-instances using only the hard parameters + + createInputPort("A"); + createInputPort("B"); + createOutputPort("Y"); + + createLoad("A_Cap"); + createLoad("B_Cap"); + createDelay("A_to_Y_delay"); + createDelay("B_to_Y_delay"); + createDriver("Y_Ron", true); + + ElectricalLoad* a_cap = getLoad("A_Cap"); + ElectricalLoad* b_cap = getLoad("B_Cap"); + ElectricalDelay* a_to_y_delay = getDelay("A_to_Y_delay"); + ElectricalDelay* b_to_y_delay = getDelay("B_to_Y_delay"); + ElectricalDriver* y_ron = getDriver("Y_Ron"); + + getNet("A")->addDownstreamNode(a_cap); + getNet("B")->addDownstreamNode(b_cap); + a_cap->addDownstreamNode(a_to_y_delay); + b_cap->addDownstreamNode(b_to_y_delay); + a_to_y_delay->addDownstreamNode(y_ron); + b_to_y_delay->addDownstreamNode(y_ron); + y_ron->addDownstreamNode(getNet("Y")); + + // Create Area result + // Create NDD Power result + createElectricalAtomicResults(); + getEventInfo("Idle")->setStaticTransitionInfos(); + // Create AND Event Energy Result + createElectricalEventAtomicResult("AND2"); + + return; + } + + void AND2::updateModel() + { + // All updateModel should do is calculate numbers for the Area/NDDPower/Energy + // Results as anything else that needs to be done using either soft or hard parameters + + // Get parameters + double drive_strength = getDrivingStrength(); + Map<double>* cache = getTechModel()->getStdCellLib()->getStdCellCache(); + + // Standard cell cache string + String cell_name = "AND2_X" + (String) drive_strength; + + // Get timing parameters + getLoad("A_Cap")->setLoadCap(cache->get(cell_name + "->Cap->A")); + getLoad("B_Cap")->setLoadCap(cache->get(cell_name + "->Cap->B")); + getDelay("A_to_Y_delay")->setDelay(cache->get(cell_name + "->Delay->A_to_Y")); + getDelay("B_to_Y_delay")->setDelay(cache->get(cell_name + "->Delay->B_to_Y")); + getDriver("Y_Ron")->setOutputRes(cache->get(cell_name + "->DriveRes->Y")); + + // Set the cell area + getAreaResult("Active")->setValue(cache->get(cell_name + "->ActiveArea")); + getAreaResult("Metal1Wire")->setValue(cache->get(cell_name + "->ActiveArea")); + + return; + } + + void AND2::evaluateModel() + { + return; + } + + void AND2::useModel() + { + // Get parameters + double drive_strength = getDrivingStrength(); + Map<double>* cache = getTechModel()->getStdCellLib()->getStdCellCache(); + + // Standard cell cache string + String cell_name = "AND2_X" + (String) drive_strength; + + // Propagate the transition info and get the 0->1 transtion count + propagateTransitionInfo(); + double P_A = getInputPort("A")->getTransitionInfo().getProbability1(); + double P_B = getInputPort("B")->getTransitionInfo().getProbability1(); + double Y_num_trans_01 = getOutputPort("Y")->getTransitionInfo().getNumberTransitions01(); + + // Calculate leakage + double leakage = 0; + leakage += cache->get(cell_name + "->Leakage->!A!B") * (1 - P_A) * (1 - P_B); + leakage += cache->get(cell_name + "->Leakage->!AB") * (1 - P_A) * P_B; + leakage += cache->get(cell_name + "->Leakage->A!B") * P_A * (1 - P_B); + leakage += cache->get(cell_name + "->Leakage->AB") * P_A * P_B; + getNddPowerResult("Leakage")->setValue(leakage); + + // Get VDD + double vdd = getTechModel()->get("Vdd"); + + // Get capacitances + double y_b_cap = cache->get(cell_name + "->Cap->Y_b"); + double y_cap = cache->get(cell_name + "->Cap->Y"); + double y_load_cap = getNet("Y")->getTotalDownstreamCap(); + + // Calculate AND2Event energy + double energy_per_trans_01 = (y_b_cap + y_cap + y_load_cap) * vdd * vdd; + getEventResult("AND2")->setValue(energy_per_trans_01 * Y_num_trans_01); + + return; + } + + void AND2::propagateTransitionInfo() + { + // Get input signal transition info + const TransitionInfo& trans_A = getInputPort("A")->getTransitionInfo(); + const TransitionInfo& trans_B = getInputPort("B")->getTransitionInfo(); + + double max_freq_mult = max(trans_A.getFrequencyMultiplier(), trans_B.getFrequencyMultiplier()); + const TransitionInfo& scaled_trans_A = trans_A.scaleFrequencyMultiplier(max_freq_mult); + const TransitionInfo& scaled_trans_B = trans_B.scaleFrequencyMultiplier(max_freq_mult); + + double A_prob_00 = scaled_trans_A.getNumberTransitions00() / max_freq_mult; + double A_prob_01 = scaled_trans_A.getNumberTransitions01() / max_freq_mult; + double A_prob_10 = A_prob_01; + double A_prob_11 = scaled_trans_A.getNumberTransitions11() / max_freq_mult; + double B_prob_00 = scaled_trans_B.getNumberTransitions00() / max_freq_mult; + double B_prob_01 = scaled_trans_B.getNumberTransitions01() / max_freq_mult; + double B_prob_10 = B_prob_01; + double B_prob_11 = scaled_trans_B.getNumberTransitions11() / max_freq_mult; + + // Set output transition info + double Y_prob_00 = A_prob_00 + + A_prob_01 * (B_prob_00 + B_prob_10) + + A_prob_10 * (B_prob_00 + B_prob_01) + + A_prob_11 * B_prob_00; + double Y_prob_01 = A_prob_01 * (B_prob_01 + B_prob_11) + + A_prob_11 * B_prob_01; + double Y_prob_11 = A_prob_11 * B_prob_11; + + // Check that probabilities add up to 1.0 with some finite tolerance + ASSERT(LibUtil::Math::isEqual(Y_prob_00 + Y_prob_01 + Y_prob_01 + Y_prob_11, 1.0), "[Error] " + getInstanceName() + + "Output transition probabilities must add up to 1 (" + (String) Y_prob_00 + ", " + + (String) Y_prob_01 + ", " + (String) Y_prob_11 + ")!"); + + // Turn probability of transitions per cycle into number of transitions per time unit + TransitionInfo trans_Y(Y_prob_00 * max_freq_mult, Y_prob_01 * max_freq_mult, Y_prob_11 * max_freq_mult); + getOutputPort("Y")->setTransitionInfo(trans_Y); + return; + } + + void AND2::cacheStdCell(StdCellLib* cell_lib_, double drive_strength_) + { + // Standard cell cache string + String cell_name = "AND2_X" + (String) drive_strength_; + + Log::printLine("=== " + cell_name + " ==="); + + // Get parameters + double gate_pitch = cell_lib_->getTechModel()->get("Gate->PitchContacted"); + Map<double>* cache = cell_lib_->getStdCellCache(); + + // Now actually build the full standard cell model + // Create the two input ports + createInputPort("A"); + createInputPort("B"); + createOutputPort("Y"); + + createNet("Y_b"); + + // Adds macros + CellMacros::addNand2(this, "NAND2", false, true, true, "A", "B", "Y_b"); + CellMacros::addInverter(this, "INV", false, true, "Y_b", "Y"); + CellMacros::updateNand2(this, "NAND2", drive_strength_ * 0.5); + CellMacros::updateInverter(this, "INV", drive_strength_ * 1.0); + + // Cache area result + double area = 0.0; + area += gate_pitch * getTotalHeight() * 1; + area += gate_pitch * getTotalHeight() * getGenProperties()->get("NAND2_GatePitches").toDouble(); + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INV_GatePitches").toDouble(); + cache->set(cell_name + "->ActiveArea", area); + Log::printLine(cell_name + "->ActiveArea=" + (String) area); + + // -------------------------------------------------------------------- + // Leakage Model Calculation + // -------------------------------------------------------------------- + double leakage_00 = getGenProperties()->get("NAND2_LeakagePower_00").toDouble() + + getGenProperties()->get("INV_LeakagePower_0").toDouble(); + double leakage_01 = getGenProperties()->get("NAND2_LeakagePower_01").toDouble() + + getGenProperties()->get("INV_LeakagePower_0").toDouble(); + double leakage_10 = getGenProperties()->get("NAND2_LeakagePower_10").toDouble() + + getGenProperties()->get("INV_LeakagePower_0").toDouble(); + double leakage_11 = getGenProperties()->get("NAND2_LeakagePower_11").toDouble() + + getGenProperties()->get("INV_LeakagePower_1").toDouble(); + cache->set(cell_name + "->Leakage->!A!B", leakage_00); + cache->set(cell_name + "->Leakage->!AB", leakage_01); + cache->set(cell_name + "->Leakage->A!B", leakage_10); + cache->set(cell_name + "->Leakage->AB", leakage_11); + Log::printLine(cell_name + "->Leakage->!A!B=" + (String) leakage_00); + Log::printLine(cell_name + "->Leakage->!AB=" + (String) leakage_01); + Log::printLine(cell_name + "->Leakage->A!B=" + (String) leakage_10); + Log::printLine(cell_name + "->Leakage->AB=" + (String) leakage_11); + // -------------------------------------------------------------------- + + // -------------------------------------------------------------------- + // Get Node Capacitances + // -------------------------------------------------------------------- + double a_cap = getNet("A")->getTotalDownstreamCap(); + double b_cap = getNet("B")->getTotalDownstreamCap(); + double y_b_cap = getNet("Y_b")->getTotalDownstreamCap(); + double y_cap = getNet("Y")->getTotalDownstreamCap(); + + cache->set(cell_name + "->Cap->A", a_cap); + cache->set(cell_name + "->Cap->B", b_cap); + cache->set(cell_name + "->Cap->Y_b", y_b_cap); + cache->set(cell_name + "->Cap->Y", y_cap); + Log::printLine(cell_name + "->Cap->A=" + (String) a_cap); + Log::printLine(cell_name + "->Cap->B=" + (String) b_cap); + Log::printLine(cell_name + "->Cap->Y=" + (String) y_b_cap); + Log::printLine(cell_name + "->Cap->Y=" + (String) y_cap); + // -------------------------------------------------------------------- + + // -------------------------------------------------------------------- + // Build Internal Delay Model + // -------------------------------------------------------------------- + double y_ron = getDriver("INV_RonZN")->getOutputRes(); + double a_to_y_delay = getDriver("NAND2_RonZN")->calculateDelay() + + getDriver("INV_RonZN")->calculateDelay(); + double b_to_y_delay = getDriver("NAND2_RonZN")->calculateDelay() + + getDriver("INV_RonZN")->calculateDelay(); + + cache->set(cell_name + "->DriveRes->Y", y_ron); + cache->set(cell_name + "->Delay->A_to_Y", a_to_y_delay); + cache->set(cell_name + "->Delay->B_to_Y", b_to_y_delay); + Log::printLine(cell_name + "->DriveRes->Y=" + (String) y_ron); + Log::printLine(cell_name + "->Delay->A_to_Y=" + (String) a_to_y_delay); + Log::printLine(cell_name + "->Delay->B_to_Y=" + (String) b_to_y_delay); + // -------------------------------------------------------------------- + + return; + + } +} // namespace DSENT diff --git a/ext/dsent/model/std_cells/AND2.h b/ext/dsent/model/std_cells/AND2.h new file mode 100644 index 000000000..67fe36be1 --- /dev/null +++ b/ext/dsent/model/std_cells/AND2.h @@ -0,0 +1,32 @@ +#ifndef __DSENT_MODEL_STD_CELLS_AND2_H__ +#define __DSENT_MODEL_STD_CELLS_AND2_H__ + +#include "util/CommonType.h" +#include "model/std_cells/StdCell.h" + +namespace DSENT +{ + class AND2 : public StdCell + { + public: + AND2(const String& instance_name_, const TechModel* tech_model_); + virtual ~AND2(); + + public: + // Set a list of properties' name needed to construct model + void initProperties(); + // Cache the standard cell + void cacheStdCell(StdCellLib* cell_lib_, double drive_strength_); + + protected: + // Build the model + virtual void constructModel(); + virtual void updateModel(); + virtual void evaluateModel(); + virtual void useModel(); + virtual void propagateTransitionInfo(); + }; // class AND2 +} // namespace DSENT + +#endif // __DSENT_MODEL_STD_CELLS_AND2_H__ + diff --git a/ext/dsent/model/std_cells/BUF.cc b/ext/dsent/model/std_cells/BUF.cc new file mode 100644 index 000000000..61c7dac4b --- /dev/null +++ b/ext/dsent/model/std_cells/BUF.cc @@ -0,0 +1,216 @@ +#include "model/std_cells/BUF.h" + +#include <cmath> + +#include "model/PortInfo.h" +#include "model/TransitionInfo.h" +#include "model/EventInfo.h" +#include "model/std_cells/StdCellLib.h" +#include "model/std_cells/CellMacros.h" +#include "model/timing_graph/ElectricalNet.h" +#include "model/timing_graph/ElectricalDriver.h" +#include "model/timing_graph/ElectricalLoad.h" +#include "model/timing_graph/ElectricalDelay.h" + +namespace DSENT +{ + using std::max; + + BUF::BUF(const String& instance_name_, const TechModel* tech_model_) + : StdCell(instance_name_, tech_model_) + { + initProperties(); + } + + BUF::~BUF() + {} + + void BUF::initProperties() + { + return; + } + + void BUF::constructModel() + { + createInputPort("A"); + createOutputPort("Y"); + + createLoad("A_Cap"); + createDelay("A_to_Y_delay"); + createDriver("Y_Ron", true); + + ElectricalLoad* a_cap = getLoad("A_Cap"); + ElectricalDelay* a_to_y_delay = getDelay("A_to_Y_delay"); + ElectricalDriver* y_ron = getDriver("Y_Ron"); + + getNet("A")->addDownstreamNode(a_cap); + a_cap->addDownstreamNode(a_to_y_delay); + a_to_y_delay->addDownstreamNode(y_ron); + y_ron->addDownstreamNode(getNet("Y")); + + // Create Area result + // Create NDD Power result + createElectricalAtomicResults(); + // Create OR Event Energy Result + createElectricalEventAtomicResult("BUF"); + + getEventInfo("Idle")->setStaticTransitionInfos(); + + return; + } + + void BUF::updateModel() + { + // Get parameters + double drive_strength = getDrivingStrength(); + Map<double>* cache = getTechModel()->getStdCellLib()->getStdCellCache(); + + // Standard cell cache string + const String& cell_name = "BUF_X" + (String) drive_strength; + + // Get timing parameters + getLoad("A_Cap")->setLoadCap(cache->get(cell_name + "->Cap->A")); + getDelay("A_to_Y_delay")->setDelay(cache->get(cell_name + "->Delay->A_to_Y")); + getDriver("Y_Ron")->setOutputRes(cache->get(cell_name + "->DriveRes->Y")); + + // Set the cell area + getAreaResult("Active")->setValue(cache->get(cell_name + "->ActiveArea")); + getAreaResult("Metal1Wire")->setValue(cache->get(cell_name + "->ActiveArea")); + + return; + } + + void BUF::evaluateModel() + { + return; + } + + void BUF::useModel() + { + // Get parameters + double drive_strength = getDrivingStrength(); + Map<double>* cache = getTechModel()->getStdCellLib()->getStdCellCache(); + + // Stadard cell cache string + const String& cell_name = "BUF_X" + (String) drive_strength; + + // Propagate the transition info and get the 0->1 transtion count + propagateTransitionInfo(); + double P_A = getInputPort("A")->getTransitionInfo().getProbability1(); + double Y_num_trans_01 = getOutputPort("Y")->getTransitionInfo().getNumberTransitions01(); + + // Calculate leakage + double leakage = 0; + leakage += cache->get(cell_name + "->Leakage->!A") * (1 - P_A); + leakage += cache->get(cell_name + "->Leakage->A") * P_A; + getNddPowerResult("Leakage")->setValue(leakage); + + // Get VDD + double vdd = getTechModel()->get("Vdd"); + + // Get capacitances + double y_b_cap = cache->get(cell_name + "->Cap->Y_b"); + double y_cap = cache->get(cell_name + "->Cap->Y"); + double y_load_cap = getNet("Y")->getTotalDownstreamCap(); + + // Calculate BUFEvent energy + double energy_per_trans_01 = (y_b_cap + y_cap + y_load_cap) * vdd * vdd; + getEventResult("BUF")->setValue(energy_per_trans_01 * Y_num_trans_01); + + return; + } + + void BUF::propagateTransitionInfo() + { + // Get input signal transition info + const TransitionInfo& trans_A = getInputPort("A")->getTransitionInfo(); + + getOutputPort("Y")->setTransitionInfo(trans_A); + return; + } + + // Creates the standard cell, characterizes and abstracts away the details + void BUF::cacheStdCell(StdCellLib* cell_lib_, double drive_strength_) + { + // Get parameters + double gate_pitch = cell_lib_->getTechModel()->get("Gate->PitchContacted"); + Map<double>* cache = cell_lib_->getStdCellCache(); + + // Stadard cell cache string + const String& cell_name = "BUF_X" + (String) drive_strength_; + + Log::printLine("=== " + cell_name + " ==="); + + // Now actually build the full standard cell model + createInputPort("A"); + createOutputPort("Y"); + + createNet("Y_b"); + + // Adds macros + CellMacros::addInverter(this, "INV0", false, true, "A", "Y_b"); + CellMacros::addInverter(this, "INV1", false, true, "Y_b", "Y"); + + // Update macros + CellMacros::updateInverter(this, "INV0", drive_strength_ * 0.367); + CellMacros::updateInverter(this, "INV1", drive_strength_ * 1.0); + + // Cache area result + double area = 0.0; + area += gate_pitch * getTotalHeight() * 1; + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INV0_GatePitches").toDouble(); + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INV1_GatePitches").toDouble(); + cache->set(cell_name + "->ActiveArea", area); + Log::printLine(cell_name + "->ActiveArea=" + (String)area); + + // -------------------------------------------------------------------- + // Leakage Model Calculation + // -------------------------------------------------------------------- + // Cache leakage power results (for every single signal combination) + double leakage_0 = 0.0; // !A + double leakage_1 = 0.0; // A + + leakage_0 += getGenProperties()->get("INV0_LeakagePower_0").toDouble(); + leakage_0 += getGenProperties()->get("INV1_LeakagePower_1").toDouble(); + + leakage_1 += getGenProperties()->get("INV0_LeakagePower_1").toDouble(); + leakage_1 += getGenProperties()->get("INV1_LeakagePower_0").toDouble(); + + cache->set(cell_name + "->Leakage->!A", leakage_0); + cache->set(cell_name + "->Leakage->A", leakage_1); + Log::printLine(cell_name + "->Leakage->!A=" + (String) leakage_0); + Log::printLine(cell_name + "->Leakage->A=" + (String) leakage_1); + // -------------------------------------------------------------------- + + // -------------------------------------------------------------------- + // Get Node Capacitances + // -------------------------------------------------------------------- + double a_cap = getNet("A")->getTotalDownstreamCap(); + double y_b_cap = getNet("Y_b")->getTotalDownstreamCap(); + double y_cap = getNet("Y")->getTotalDownstreamCap(); + + cache->set(cell_name + "->Cap->A", a_cap); + cache->set(cell_name + "->Cap->Y_b", y_b_cap); + cache->set(cell_name + "->Cap->Y", y_cap); + Log::printLine(cell_name + "->Cap->A_Cap=" + (String) a_cap); + Log::printLine(cell_name + "->Cap->Y_b_Cap=" + (String) y_b_cap); + Log::printLine(cell_name + "->Cap->Y_Cap=" + (String) y_cap); + // -------------------------------------------------------------------- + + // -------------------------------------------------------------------- + // Build Internal Delay Model + // -------------------------------------------------------------------- + double y_ron = getDriver("INV1_RonZN")->getOutputRes(); + double a_to_y_delay = getDriver("INV0_RonZN")->calculateDelay() + + getDriver("INV1_RonZN")->calculateDelay(); + + cache->set(cell_name + "->DriveRes->Y", y_ron); + cache->set(cell_name + "->Delay->A_to_Y", a_to_y_delay); + Log::printLine(cell_name + "->DriveRes->Y=" + (String) y_ron); + Log::printLine(cell_name + "->Delay->A_to_Y=" + (String) a_to_y_delay); + // -------------------------------------------------------------------- + + return; + } +} // namespace DSENT + diff --git a/ext/dsent/model/std_cells/BUF.h b/ext/dsent/model/std_cells/BUF.h new file mode 100644 index 000000000..1c85b2a44 --- /dev/null +++ b/ext/dsent/model/std_cells/BUF.h @@ -0,0 +1,33 @@ +#ifndef __DSENT_MODEL_STD_CELLS_BUF_H__ +#define __DSENT_MODEL_STD_CELLS_BUF_H__ + +#include "util/CommonType.h" +#include "model/std_cells/StdCell.h" + +namespace DSENT +{ + class BUF : public StdCell + { + public: + BUF(const String& instance_name_, const TechModel* tech_model_); + virtual ~BUF(); + + public: + // Set a list of properties' name needed to construct model + void initProperties(); + // Cache the standard cell + void cacheStdCell(StdCellLib* cell_lib_, double drive_strength_); + + protected: + // Build the model + virtual void constructModel(); + virtual void updateModel(); + virtual void evaluateModel(); + virtual void useModel(); + virtual void propagateTransitionInfo(); + + }; // class BUF +} // namespace DSENT + +#endif // __DSENT_MODEL_STD_CELLS_BUF_H__ + diff --git a/ext/dsent/model/std_cells/CellMacros.cc b/ext/dsent/model/std_cells/CellMacros.cc new file mode 100644 index 000000000..5b243942a --- /dev/null +++ b/ext/dsent/model/std_cells/CellMacros.cc @@ -0,0 +1,477 @@ +#include "model/std_cells/CellMacros.h" + +#include <cmath> +#include <vector> + +#include "model/std_cells/StdCell.h" +#include "model/timing_graph/ElectricalNet.h" +#include "model/timing_graph/ElectricalDriver.h" +#include "model/timing_graph/ElectricalLoad.h" + +namespace DSENT +{ + //------------------------------------------------------------------------- + // NOR2 Macro (TODO: Generalize to N-input macro once leakage calc is done) + //------------------------------------------------------------------------- + void CellMacros::addNor2(StdCell* cell_, const String& name_, + bool sizable_, bool a1_to_zn_path_, bool a2_to_zn_path_, + const String& a1_net_, const String& a2_net_, const String& zn_net_) + { + //Create electrical timing model for the nand + // Construct loads and drivers + cell_->createLoad(name_ + "_CgA1"); + cell_->createLoad(name_ + "_CgA2"); + cell_->createLoad(name_ + "_CdZN"); + cell_->createDriver(name_ + "_RonZN", sizable_); + + //Get references to loads and drivers + ElectricalLoad* gate_a1_load = cell_->getLoad(name_ + "_CgA1"); + ElectricalLoad* gate_a2_load = cell_->getLoad(name_ + "_CgA2"); + ElectricalLoad* drain_load = cell_->getLoad(name_ + "_CdZN"); + ElectricalDriver* zn_drive = cell_->getDriver(name_ + "_RonZN"); + ElectricalNet* a1_net = cell_->getNet(a1_net_); + ElectricalNet* a2_net = cell_->getNet(a2_net_); + ElectricalNet* zn_net = cell_->getNet(zn_net_); + + //Add loads and drivers to the specified nets + a1_net->addDownstreamNode(gate_a1_load); + a2_net->addDownstreamNode(gate_a2_load); + zn_net->addDownstreamNode(drain_load); + if (a1_to_zn_path_) gate_a1_load->addDownstreamNode(zn_drive); + if (a2_to_zn_path_) gate_a2_load->addDownstreamNode(zn_drive); + zn_drive->addDownstreamNode(zn_net); + + return; + } + + void CellMacros::updateNor2(StdCell* cell_, const String& name_, double normalized_size_) + { + ASSERT(normalized_size_ >= 0.0, "[Error] " + cell_->getInstanceName() + + " -> Cannot update a macro with a negative normalized size!"); + + //Grab pointer to tech model + const TechModel* tech = cell_->getTechModel(); + + // Get technology parameters + double vdd = tech->get("Vdd"); + double gate_cap = tech->get("Gate->CapPerWidth"); + double drain_cap = tech->get("Drain->CapPerWidth"); + double nmos_eff_res = tech->get("Nmos->EffResWidth"); + double pmos_eff_res = tech->get("Pmos->EffResWidth"); + double pmos_eff_res_stack_ratio = tech->get("Pmos->EffResStackRatio"); + double gate_pitch_contacted = tech->get("Gate->PitchContacted"); + double metal1_wire_min_width = tech->get("Wire->Metal1->MinWidth"); + + //Calculate number of folds and gate pitches needed + unsigned int folds = (normalized_size_ < 1.0) ? 1 : (unsigned int)ceil(normalized_size_); + cell_->getGenProperties()->set(name_ + "_GatePitches", 2 * folds); + + //Calculate widths, making sure they are above the minimum width + double nmos_width = std::max(calculateNmosWidth(cell_, 1, 2, 1) * normalized_size_ / folds, (double) tech->get("Gate->MinWidth")); + double pmos_width = std::max(calculatePmosWidth(cell_, 1, 2, 2) * normalized_size_ / folds, (double) tech->get("Gate->MinWidth")); + + //Calculate leakage power for each given input state + double leakage_power_00 = vdd * folds * 2 * tech->calculateNmosLeakageCurrent(1, nmos_width, 0x0); + double leakage_power_01 = vdd * folds * tech->calculatePmosLeakageCurrent(2, pmos_width, ~0x1); + double leakage_power_10 = vdd * folds * tech->calculatePmosLeakageCurrent(2, pmos_width, ~0x2); + double leakage_power_11 = vdd * folds * tech->calculatePmosLeakageCurrent(2, pmos_width, ~0x3); + cell_->getGenProperties()->set(name_ + "_LeakagePower_00", leakage_power_00); + cell_->getGenProperties()->set(name_ + "_LeakagePower_01", leakage_power_01); + cell_->getGenProperties()->set(name_ + "_LeakagePower_10", leakage_power_10); + cell_->getGenProperties()->set(name_ + "_LeakagePower_11", leakage_power_11); + + //Calculate R_on and capacitances + double pmos_stack2_balance = 1.0 + pmos_eff_res_stack_ratio; + double c_g = (nmos_width + pmos_width) * gate_cap * folds; + double c_d = (2 * pmos_width + 2 * nmos_width) * drain_cap * folds; + double r_on = (nmos_eff_res / nmos_width + pmos_stack2_balance * pmos_eff_res / pmos_width) / (folds * 2.0); + + // Estimate the wire cap and add them all at the output + double cell_height = cell_->getTotalHeight(); + double wire_width = metal1_wire_min_width; + double wire_spacing = gate_pitch_contacted - metal1_wire_min_width; + double wire_length = 2.0 * folds * cell_height; + double wire_cap = tech->calculateWireCapacitance("Metal1", wire_width, wire_spacing, wire_length); + + // Construct equivalent load and drive strength + cell_->getLoad(name_ + "_CgA1")->setLoadCap(c_g); + cell_->getLoad(name_ + "_CgA2")->setLoadCap(c_g); + cell_->getLoad(name_ + "_CdZN")->setLoadCap(c_d + wire_cap); + cell_->getDriver(name_ + "_RonZN")->setOutputRes(r_on); + + // Calculate flip energies + double zn_flip_energy = 0.5 * (c_d + wire_cap) * vdd * vdd; + double a1_flip_energy = 0.5 * c_g * vdd * vdd; + double a2_flip_energy = 0.5 * c_g * vdd * vdd; + cell_->getGenProperties()->set(name_ + "_ZN_Flip", zn_flip_energy); + cell_->getGenProperties()->set(name_ + "_A1_Flip", a1_flip_energy); + cell_->getGenProperties()->set(name_ + "_A2_Flip", a2_flip_energy); + } + //------------------------------------------------------------------------- + + //------------------------------------------------------------------------- + // NAND2 Macro (TODO: Generalize to N-input macro once leakage calc is done) + //------------------------------------------------------------------------- + //Adds a NAND2 to the standard cell, normalized to some size + void CellMacros::addNand2(StdCell* cell_, const String& name_, + bool sizable_, bool a1_to_zn_path_, bool a2_to_zn_path_, + const String& a1_net_, const String& a2_net_, const String& zn_net_) + { + //Create electrical timing model for the nor + // Construct loads and drivers + cell_->createLoad(name_ + "_CgA1"); + cell_->createLoad(name_ + "_CgA2"); + cell_->createLoad(name_ + "_CdZN"); + cell_->createDriver(name_ + "_RonZN", sizable_); + + //Get references to loads and drivers + ElectricalLoad* gate_a1_load = cell_->getLoad(name_ + "_CgA1"); + ElectricalLoad* gate_a2_load = cell_->getLoad(name_ + "_CgA2"); + ElectricalLoad* drain_load = cell_->getLoad(name_ + "_CdZN"); + ElectricalDriver* zn_drive = cell_->getDriver(name_ + "_RonZN"); + ElectricalNet* a1_net = cell_->getNet(a1_net_); + ElectricalNet* a2_net = cell_->getNet(a2_net_); + ElectricalNet* zn_net = cell_->getNet(zn_net_); + + a1_net->addDownstreamNode(gate_a1_load); + a2_net->addDownstreamNode(gate_a2_load); + zn_net->addDownstreamNode(drain_load); + if (a1_to_zn_path_) gate_a1_load->addDownstreamNode(zn_drive); + if (a2_to_zn_path_) gate_a2_load->addDownstreamNode(zn_drive); + zn_drive->addDownstreamNode(zn_net); + + return; + } + + //Updates a NAND2 to to the standard cell, normalized to some size + void CellMacros::updateNand2(StdCell* cell_, const String& name_, double normalized_size_) + { + ASSERT(normalized_size_ >= 0.0, "[Error] " + cell_->getInstanceName() + + " -> Cannot update a macro with a negative normalized size!"); + + //Grab pointer to tech model + const TechModel* tech = cell_->getTechModel(); + + // Get technology parameters + double vdd = tech->get("Vdd"); + double gate_cap = tech->get("Gate->CapPerWidth"); + double drain_cap = tech->get("Drain->CapPerWidth"); + double nmos_eff_res = tech->get("Nmos->EffResWidth"); + double pmos_eff_res = tech->get("Pmos->EffResWidth"); + double nmos_eff_res_stack_ratio = tech->get("Nmos->EffResStackRatio"); + double gate_pitch_contacted = tech->get("Gate->PitchContacted"); + double metal1_wire_min_width = tech->get("Wire->Metal1->MinWidth"); + + //Calculate number of folds needed + unsigned int folds = (normalized_size_ < 1.0) ? 1 : (unsigned int)ceil(normalized_size_); + cell_->getGenProperties()->set(name_ + "_GatePitches", 2 * folds); + + //Calculate widths, making sure they are above the minimum width + double nmos_width = std::max(calculateNmosWidth(cell_, 2, 1, 2) * normalized_size_ / folds, (double) tech->get("Gate->MinWidth")); + double pmos_width = std::max(calculatePmosWidth(cell_, 2, 1, 1) * normalized_size_ / folds, (double) tech->get("Gate->MinWidth")); + + // Leakage power calculation + double leakage_power_00 = vdd * folds * tech->calculateNmosLeakageCurrent(2, nmos_width, 0x0); + double leakage_power_01 = vdd * folds * tech->calculateNmosLeakageCurrent(2, nmos_width, 0x1); + double leakage_power_10 = vdd * folds * tech->calculateNmosLeakageCurrent(2, nmos_width, 0x2); + double leakage_power_11 = vdd * folds * 2 * tech->calculatePmosLeakageCurrent(1, pmos_width, ~0x3); + cell_->getGenProperties()->set(name_ + "_LeakagePower_00", leakage_power_00); + cell_->getGenProperties()->set(name_ + "_LeakagePower_01", leakage_power_01); + cell_->getGenProperties()->set(name_ + "_LeakagePower_10", leakage_power_10); + cell_->getGenProperties()->set(name_ + "_LeakagePower_11", leakage_power_11); + + // Get input parameters + double nmos_stack2_balance = 1.0 + nmos_eff_res_stack_ratio; + + //Calculate caps + double c_g = (nmos_width + pmos_width) * gate_cap * folds; + double c_d = (2 * pmos_width + 2 * nmos_width) * drain_cap * folds; + double r_on = (nmos_stack2_balance * nmos_eff_res / nmos_width + pmos_eff_res / pmos_width) / (folds * 2.0); + + // Estimate the wire cap and add them all at the output + double cell_height = cell_->getTotalHeight(); + double wire_width = metal1_wire_min_width; + double wire_spacing = gate_pitch_contacted - metal1_wire_min_width; + double wire_length = 2.0 * folds * cell_height; + double wire_cap = tech->calculateWireCapacitance("Metal1", wire_width, wire_spacing, wire_length); + + // Construct equivalent load and drive strength + cell_->getLoad(name_ + "_CgA1")->setLoadCap(c_g); + cell_->getLoad(name_ + "_CgA2")->setLoadCap(c_g); + cell_->getLoad(name_ + "_CdZN")->setLoadCap(c_d + wire_cap); + cell_->getDriver(name_ + "_RonZN")->setOutputRes(r_on); + + // Calculate flip energies + double zn_flip_energy = 0.5 * (c_d + wire_cap) * vdd * vdd; + double a1_flip_energy = 0.5 * c_g * vdd * vdd; + double a2_flip_energy = 0.5 * c_g * vdd * vdd; + cell_->getGenProperties()->set(name_ + "_ZN_Flip", zn_flip_energy); + cell_->getGenProperties()->set(name_ + "_A1_Flip", a1_flip_energy); + cell_->getGenProperties()->set(name_ + "_A2_Flip", a2_flip_energy); + } + //------------------------------------------------------------------------- + + //------------------------------------------------------------------------- + // INV Macro + //------------------------------------------------------------------------- + //Adds an inverter to the model, normalized to some size + void CellMacros::addInverter(StdCell* cell_, const String& name_, + bool sizable_, bool a_to_zn_path_, + const String& a_net_, const String& zn_net_) + { + //Create electrical timing model for the inverter + // Construct loads and drivers + cell_->createLoad(name_ + "_CgA"); + cell_->createLoad(name_ + "_CdZN"); + cell_->createDriver(name_ + "_RonZN", sizable_); + + //Get references to loads and drivers + ElectricalLoad* gate_load = cell_->getLoad(name_ + "_CgA"); + ElectricalLoad* drain_load = cell_->getLoad(name_ + "_CdZN"); + ElectricalDriver* out_drive = cell_->getDriver(name_ + "_RonZN"); + ElectricalNet* a_net = cell_->getNet(a_net_); + ElectricalNet* zn_net = cell_->getNet(zn_net_); + + // Setup connectivity of loads and drivers + a_net->addDownstreamNode(gate_load); + if (a_to_zn_path_) gate_load->addDownstreamNode(out_drive); + zn_net->addDownstreamNode(drain_load); + out_drive->addDownstreamNode(zn_net); + + return; + } + + //Updates the numbers of an inverter for some normalized size + void CellMacros::updateInverter(StdCell* cell_, const String& name_, double normalized_size_) + { + ASSERT(normalized_size_ >= 0.0, "[Error] " + cell_->getInstanceName() + + " -> Cannot update a macro with a negative normalized size!"); + + //Grab pointer to tech model + const TechModel* tech = cell_->getTechModel(); + + //Get values from technology library + double vdd = tech->get("Vdd"); + double gate_cap = tech->get("Gate->CapPerWidth"); + double drain_cap = tech->get("Drain->CapPerWidth"); + double nmos_eff_res = tech->get("Nmos->EffResWidth"); + double pmos_eff_res = tech->get("Pmos->EffResWidth"); + double gate_pitch_contacted = tech->get("Gate->PitchContacted"); + double metal1_wire_min_width = tech->get("Wire->Metal1->MinWidth"); + + //Calculate number of folds needed + unsigned int folds = (normalized_size_ < 1.0) ? 1 : (unsigned int)ceil(normalized_size_); + cell_->getGenProperties()->set(name_ + "_GatePitches", folds); + + //Calculate widths, making sure they are above the minimum width + double nmos_width = std::max(calculateNmosWidth(cell_, 1, 1, 1) * normalized_size_ / folds, (double) tech->get("Gate->MinWidth")); + double pmos_width = std::max(calculatePmosWidth(cell_, 1, 1, 1) * normalized_size_ / folds, (double) tech->get("Gate->MinWidth")); + + //Calculate leakage power for each given input state + double leakage_power_0 = vdd * folds * tech->calculateNmosLeakageCurrent(1, nmos_width, 0x0); + double leakage_power_1 = vdd * folds * tech->calculatePmosLeakageCurrent(1, pmos_width, ~0x1); + cell_->getGenProperties()->set(name_ + "_LeakagePower_0", leakage_power_0); + cell_->getGenProperties()->set(name_ + "_LeakagePower_1", leakage_power_1); + + //Calculate caps + double c_g = (nmos_width + pmos_width) * gate_cap * folds; + double c_d = (pmos_width + nmos_width) * drain_cap * folds; + double r_on = (nmos_eff_res / nmos_width + pmos_eff_res / pmos_width) / (folds * 2.0); + + // Estimate the wire cap and add them all at the output + double cell_height = cell_->getTotalHeight(); + double wire_width = metal1_wire_min_width; + double wire_spacing = gate_pitch_contacted - metal1_wire_min_width; + double wire_length = folds * cell_height; + double wire_cap = tech->calculateWireCapacitance("Metal1", wire_width, wire_spacing, wire_length); + + // Construct equivalent load and drive strength + cell_->getLoad(name_ + "_CgA")->setLoadCap(c_g); + cell_->getLoad(name_ + "_CdZN")->setLoadCap(c_d + wire_cap); + cell_->getDriver(name_ + "_RonZN")->setOutputRes(r_on); + + // Calculate flip energy (output flip) + // Calculate flip energies + double zn_flip_energy = 0.5 * (c_d + wire_cap) * vdd * vdd; + double a_flip_energy = 0.5 * c_g * vdd * vdd; + cell_->getGenProperties()->set(name_ + "_ZN_Flip", zn_flip_energy); + cell_->getGenProperties()->set(name_ + "_A_Flip", a_flip_energy); + + return; + } + //------------------------------------------------------------------------- + + //------------------------------------------------------------------------- + // INVZ Macro + //------------------------------------------------------------------------- + //Adds a tristated inverter to the model, normalized to some size + void CellMacros::addTristate(StdCell* cell_, const String& name_, + bool sizable_, bool a_to_zn_path_, bool oe_to_zn_path_, bool oen_to_zn_path_, + const String& a_net_, const String& oe_net_, const String& oen_net_, const String& zn_net_) + { + // Construct loads and drivers + cell_->createLoad(name_ + "_CgA"); + cell_->createLoad(name_ + "_CgOE"); + cell_->createLoad(name_ + "_CgOEN"); + cell_->createLoad(name_ + "_CdZN"); + cell_->createDriver(name_ + "_RonZN", sizable_); + + // Get references to loads, nets and drivers + ElectricalLoad* gate_a_load = cell_->getLoad(name_ + "_CgA"); + ElectricalLoad* gate_oe_load = cell_->getLoad(name_ + "_CgOE"); + ElectricalLoad* gate_oen_load = cell_->getLoad(name_ + "_CgOEN"); + ElectricalLoad* drain_load = cell_->getLoad(name_ + "_CdZN"); + ElectricalDriver* out_drive = cell_->getDriver(name_ + "_RonZN"); + ElectricalNet* a_net = cell_->getNet(a_net_); + ElectricalNet* oe_net = cell_->getNet(oe_net_); + ElectricalNet* oen_net = cell_->getNet(oen_net_); + ElectricalNet* zn_net = cell_->getNet(zn_net_); + + // Setup connectivity of loads and drivers + a_net->addDownstreamNode(gate_a_load); + oe_net->addDownstreamNode(gate_oe_load); + oen_net->addDownstreamNode(gate_oen_load); + if (a_to_zn_path_) gate_a_load->addDownstreamNode(out_drive); + if (oe_to_zn_path_) gate_oe_load->addDownstreamNode(out_drive); + if (oen_to_zn_path_) gate_oen_load->addDownstreamNode(out_drive); + zn_net->addDownstreamNode(drain_load); + out_drive->addDownstreamNode(zn_net); + + return; + } + + //Updates the numbers of an inverter for some normalized size + void CellMacros::updateTristate(StdCell* cell_, const String& name_, double normalized_size_) + { + ASSERT(normalized_size_ >= 0.0, "[Error] " + cell_->getInstanceName() + + " -> Cannot update a macro with a negative normalized size!"); + + //Grab pointer to tech model + const TechModel* tech = cell_->getTechModel(); + + //Get values from technology library + double vdd = tech->get("Vdd"); + double gate_cap = tech->get("Gate->CapPerWidth"); + double drain_cap = tech->get("Drain->CapPerWidth"); + double nmos_eff_res = tech->get("Nmos->EffResWidth"); + double pmos_eff_res = tech->get("Pmos->EffResWidth"); + double pmos_eff_res_stack_ratio = tech->get("Pmos->EffResStackRatio"); + double nmos_eff_res_stack_ratio = tech->get("Nmos->EffResStackRatio"); + double gate_pitch_contacted = tech->get("Gate->PitchContacted"); + double metal1_wire_min_width = tech->get("Wire->Metal1->MinWidth"); + + //Calculate number of folds and gate pitches needed + unsigned int folds = (normalized_size_ < 1.0) ? 1 : (unsigned int)ceil(normalized_size_); + cell_->getGenProperties()->set(name_ + "_GatePitches", 2 * folds); + + //Calculate widths, making sure they are above the minimum width + double nmos_width = std::max(calculateNmosWidth(cell_, 2, 2, 2) * normalized_size_ / folds, (double) tech->get("Gate->MinWidth")); + double pmos_width = std::max(calculatePmosWidth(cell_, 2, 2, 2) * normalized_size_ / folds, (double) tech->get("Gate->MinWidth")); + + //Calculate leakage power for each given input state + //if output_enable = 0, then it is possible that the PMOS may leak (if output = 0), + //or the NMOS will leak (if output = 1) + + //OE OEN A _ ZN + double leakage_power_010_0 = vdd * folds * tech->calculatePmosLeakageCurrent(2, pmos_width, ~0x2); + double leakage_power_010_1 = vdd * folds * tech->calculateNmosLeakageCurrent(2, nmos_width, 0x0); + double leakage_power_011_0 = vdd * folds * tech->calculatePmosLeakageCurrent(2, pmos_width, ~0x3); + double leakage_power_011_1 = vdd * folds * tech->calculateNmosLeakageCurrent(2, nmos_width, 0x1); + double leakage_power_100_1 = vdd * folds * tech->calculateNmosLeakageCurrent(2, nmos_width, 0x2); + double leakage_power_101_0 = vdd * folds * tech->calculatePmosLeakageCurrent(2, pmos_width, ~0x1); + cell_->getGenProperties()->set(name_ + "_LeakagePower_010_0", leakage_power_010_0); + cell_->getGenProperties()->set(name_ + "_LeakagePower_010_1", leakage_power_010_1); + cell_->getGenProperties()->set(name_ + "_LeakagePower_011_0", leakage_power_011_0); + cell_->getGenProperties()->set(name_ + "_LeakagePower_011_1", leakage_power_011_1); + cell_->getGenProperties()->set(name_ + "_LeakagePower_100_1", leakage_power_100_1); + cell_->getGenProperties()->set(name_ + "_LeakagePower_101_0", leakage_power_101_0); + + //Caculate stack balance + double pmos_stack2_balance = 1.0 + pmos_eff_res_stack_ratio; + double nmos_stack2_balance = 1.0 + nmos_eff_res_stack_ratio; + + //Calculate caps + double c_g_a = (nmos_width + pmos_width) * gate_cap * folds; + double c_g_oe = nmos_width * gate_cap * folds; + double c_g_oen = pmos_width * gate_cap * folds; + double c_d = (2 * pmos_width + 2 * nmos_width) * drain_cap * folds; + double r_on = (nmos_stack2_balance * nmos_eff_res / nmos_width + pmos_stack2_balance * pmos_eff_res / pmos_width) / (folds * 2.0); + + // Estimate the wire cap and add them all at the output + double cell_height = cell_->getTotalHeight(); + double wire_width = metal1_wire_min_width; + double wire_spacing = gate_pitch_contacted - metal1_wire_min_width; + double wire_length = 2.0 * folds * cell_height; + double wire_cap = tech->calculateWireCapacitance("Metal1", wire_width, wire_spacing, wire_length); + + // Construct equivalent load and drive strength + cell_->getLoad(name_ + "_CgA")->setLoadCap(c_g_a); + cell_->getLoad(name_ + "_CgOE")->setLoadCap(c_g_oe); + cell_->getLoad(name_ + "_CgOEN")->setLoadCap(c_g_oen); + cell_->getLoad(name_ + "_CdZN")->setLoadCap(c_d + wire_cap); + cell_->getDriver(name_ + "_RonZN")->setOutputRes(r_on); + + // Calculate flip energy (output flip) + double zn_flip_energy = 0.5 * (c_d + wire_cap) * vdd * vdd; + double a_flip_energy = 0.5 * c_g_a * vdd * vdd; + double oe_flip_energy = 0.5 * c_g_oe * vdd * vdd; + double oen_flip_energy = 0.5 * c_g_oen * vdd * vdd; + cell_->getGenProperties()->set(name_ + "_ZN_Flip", zn_flip_energy); + cell_->getGenProperties()->set(name_ + "_A_Flip", a_flip_energy); + cell_->getGenProperties()->set(name_ + "_OE_Flip", oe_flip_energy); + cell_->getGenProperties()->set(name_ + "_OEN_Flip", oen_flip_energy); + return; + } + //------------------------------------------------------------------------- + + + //------------------------------------------------------------------------- + // Helper Functions + //------------------------------------------------------------------------- + //Returns the width of NMOS transistors, given the NMOS and PMOS stacking + double CellMacros::calculateNmosWidth(const StdCell* cell_, unsigned int max_stacked_nmos_, unsigned int max_stacked_pmos_, unsigned int current_stacked_nmos_) + { + //Grab pointer to tech model + const TechModel* tech = cell_->getTechModel(); + + double nmos_eff_res_stack_ratio = tech->get("Nmos->EffResStackRatio"); + double pmos_eff_res_stack_ratio = tech->get("Pmos->EffResStackRatio"); + + double nmos_stack_balance = 1.0 + nmos_eff_res_stack_ratio * (double) (max_stacked_nmos_ - 1); + double pmos_stack_balance = 1.0 + pmos_eff_res_stack_ratio * (double) (max_stacked_pmos_ - 1); + double current_nmos_stack_balance = 1.0 + nmos_eff_res_stack_ratio * (double) (current_stacked_nmos_ - 1); + + double pn_ratio = cell_->getPToNRatio(); + double active_height = cell_->getActiveHeight(); + + //Calculate the width of the current device + double nmos_width = active_height * current_nmos_stack_balance / (nmos_stack_balance + pn_ratio * pmos_stack_balance); + + return nmos_width; + } + + //Returns the width of PMOS transistors, given the NMOS and PMOS stacking + double CellMacros::calculatePmosWidth(const StdCell* cell_, unsigned int max_stacked_nmos_, unsigned int max_stacked_pmos_, unsigned int current_stacked_pmos_) + { + //Grab pointer to tech model + const TechModel* tech = cell_->getTechModel(); + + double nmos_eff_res_stack_ratio = tech->get("Nmos->EffResStackRatio"); + double pmos_eff_res_stack_ratio = tech->get("Pmos->EffResStackRatio"); + + double nmos_stack_balance = 1.0 + nmos_eff_res_stack_ratio * (double) (max_stacked_nmos_ - 1); + double pmos_stack_balance = 1.0 + pmos_eff_res_stack_ratio * (double) (max_stacked_pmos_ - 1); + double current_pmos_stack_balance = 1.0 + pmos_eff_res_stack_ratio * (double) (current_stacked_pmos_ - 1); + + double pn_ratio = cell_->getPToNRatio(); + double active_height = cell_->getActiveHeight(); + + //Calculate the width of the current device + double pmos_width = active_height * current_pmos_stack_balance * pn_ratio / (nmos_stack_balance + pn_ratio * pmos_stack_balance); + + return pmos_width; + } + //------------------------------------------------------------------------- + +} // namespace DSENT + diff --git a/ext/dsent/model/std_cells/CellMacros.h b/ext/dsent/model/std_cells/CellMacros.h new file mode 100644 index 000000000..ce4b54473 --- /dev/null +++ b/ext/dsent/model/std_cells/CellMacros.h @@ -0,0 +1,57 @@ +#ifndef __DSENT_MODEL_STD_CELLS_CELLMACROS_H__ +#define __DSENT_MODEL_STD_CELLS_CELLMACROS_H__ + +#include "util/CommonType.h" +#include "model/std_cells/StdCell.h" + +namespace DSENT +{ + class StdCell; + + // Contains cell macros that can be created within standard cells + class CellMacros + { + private : + CellMacros(); + ~CellMacros(); + + public: + //NOR2 Macro + //Adds a NOR2 to the standard cell, normalized to some size + static void addNor2(StdCell* cell_, const String& name_, bool sizable_, bool a1_to_zn_path_, bool a2_to_zn_path_, + const String& a1_net_, const String& a2_net_, const String& zn_net_); + //Updates a NOR2 to to the standard cell, normalized to some size + static void updateNor2(StdCell* cell_, const String& name_, double normalized_size_); + + //NAND2 Macro + //Adds a NAND2 to the standard cell, normalized to some size + static void addNand2(StdCell* cell_, const String& name_, bool sizable_, bool a1_to_zn_path_, bool a2_to_zn_path_, + const String& a1_net_, const String& a2_net_, const String& zn_net_); + //Updates a NAND2 to to the standard cell, normalized to some size + static void updateNand2(StdCell* cell_, const String& name_, double normalized_size_); + + //INVERTER Macro + //Adds a inverter to the standard cell, normalized to some size + static void addInverter(StdCell* cell_, const String& name_, bool sizable_, bool a_to_zn_path_, + const String& a_net_, const String& zn_net_); + //Updates an inverter to to the standard cell, normalized to some size + static void updateInverter(StdCell* cell_, const String& name_, double normalized_size_); + + //INVZ Macro + //Adds a tristated inverter to the standard cell, normalized to some size + static void addTristate(StdCell* cell_, const String& name_, bool sizable_, bool a_to_zn_path_, bool oe_to_zn_path_, bool oen_to_zn_path_, + const String& a_net_, const String& oe_net_, const String& oen_net_, const String& zn_net_); + //Updates an tristated inverter to to the standard cell, normalized to some size + static void updateTristate(StdCell* cell_, const String& name_, double normalized_size_); + + //Helper functions + //Returns the width of NMOS transistors, given the NMOS and PMOS stacking + static double calculateNmosWidth(const StdCell* cell_, unsigned int max_stacked_nmos_, unsigned int max_stacked_pmos_, unsigned int current_stack_nmos_); + //Returns the width of PMOS transistors, given the NMOS and PMOS stacking + static double calculatePmosWidth(const StdCell* cell_, unsigned int max_stacked_nmos_, unsigned int max_stacked_pmos_, unsigned int current_stack_pmos_); + + }; // class CellMacros +} // namespace DSENT + +#endif // __DSENT_MODEL_STD_CELLS_CELLMACROS_H__ + diff --git a/ext/dsent/model/std_cells/DFFQ.cc b/ext/dsent/model/std_cells/DFFQ.cc new file mode 100644 index 000000000..9080a7211 --- /dev/null +++ b/ext/dsent/model/std_cells/DFFQ.cc @@ -0,0 +1,536 @@ +#include "model/std_cells/DFFQ.h" + +#include <cmath> + +#include "model/PortInfo.h" +#include "model/EventInfo.h" +#include "model/TransitionInfo.h" +#include "model/std_cells/StdCellLib.h" +#include "model/std_cells/CellMacros.h" +#include "model/timing_graph/ElectricalNet.h" +#include "model/timing_graph/ElectricalDriver.h" +#include "model/timing_graph/ElectricalLoad.h" +#include "model/timing_graph/ElectricalDelay.h" + +namespace DSENT +{ + using std::ceil; + using std::max; + using std::min; + + DFFQ::DFFQ(const String& instance_name_, const TechModel* tech_model_) + : StdCell(instance_name_, tech_model_) + { + initProperties(); + } + + DFFQ::~DFFQ() + {} + + void DFFQ::initProperties() + { + return; + } + + void DFFQ::constructModel() + { + // All constructModel should do is create Area/NDDPower/Energy Results as + // well as instantiate any sub-instances using only the hard parameters + + createInputPort("D"); + createInputPort("CK"); + createOutputPort("Q"); + + createLoad("D_Cap"); + createLoad("CK_Cap"); + createDelay("D_Setup_delay"); + createDelay("CK_to_Q_delay"); + createDriver("Q_Ron", true); + + ElectricalLoad* d_cap = getLoad("D_Cap"); + ElectricalLoad* ck_cap = getLoad("CK_Cap"); + ElectricalDelay* d_setup_delay = getDelay("D_Setup_delay"); + ElectricalDelay* ck_to_q_delay = getDelay("CK_to_Q_delay"); + ElectricalDriver* q_ron = getDriver("Q_Ron"); + + getNet("D")->addDownstreamNode(d_cap); + getNet("CK")->addDownstreamNode(ck_cap); + d_cap->addDownstreamNode(d_setup_delay); + ck_cap->addDownstreamNode(ck_to_q_delay); + ck_to_q_delay->addDownstreamNode(q_ron); + q_ron->addDownstreamNode(getNet("Q")); + + // Create Area result + // Create NDD Power result + createElectricalAtomicResults(); + // Create CK Event Energy Result + createElectricalEventAtomicResult("CK"); + getEventInfo("CK")->setTransitionInfo("CK", TransitionInfo(0.0, 1.0, 0.0)); + // Create DFF Event Energy Result + createElectricalEventAtomicResult("DFFD"); + getEventInfo("DFFD")->setTransitionInfo("CK", TransitionInfo(0.0, 1.0, 0.0)); + createElectricalEventAtomicResult("DFFQ"); + getEventInfo("DFFQ")->setTransitionInfo("CK", TransitionInfo(0.0, 1.0, 0.0)); + + // Update Idle event for leakage + // CK pin is assumed to be on all the time + EventInfo* idle_event_info = getEventInfo("Idle"); + idle_event_info->setTransitionInfo("CK", TransitionInfo(0.0, 1.0, 0.0)); + idle_event_info->setTransitionInfo("D", TransitionInfo(0.5, 0.0, 0.5)); + + return; + } + + void DFFQ::updateModel() + { + // Get parameters + double drive_strength = getDrivingStrength(); + Map<double>* cache = getTechModel()->getStdCellLib()->getStdCellCache(); + + // Standard cell cache string + String cell_name = "DFFQ_X" + (String) drive_strength; + + // Get timing parameters + getLoad("D_Cap")->setLoadCap(cache->get(cell_name + "->Cap->D")); + getLoad("CK_Cap")->setLoadCap(cache->get(cell_name + "->Cap->CK")); + getDriver("Q_Ron")->setOutputRes(cache->get(cell_name + "->DriveRes->Q")); + getDelay("CK_to_Q_delay")->setDelay(cache->get(cell_name + "->Delay->CK_to_Q")); + getDelay("D_Setup_delay")->setDelay(cache->get(cell_name + "->Delay->D_Setup")); + + // Set the cell area + getAreaResult("Active")->setValue(cache->get(cell_name + "->Area->Active")); + getAreaResult("Metal1Wire")->setValue(cache->get(cell_name + "->Area->Metal1Wire")); + + return; + } + + void DFFQ::evaluateModel() + { + return; + } + + void DFFQ::useModel() + { + // Get parameters + double drive_strength = getDrivingStrength(); + Map<double>* cache = getTechModel()->getStdCellLib()->getStdCellCache(); + + // Standard cell cache string + String cell_name = "DFFQ_X" + (String) drive_strength; + + // Propagate the transition info and get P_D, P_M, and P_Q + propagateTransitionInfo(); + double P_D = getInputPort("D")->getTransitionInfo().getProbability1(); + double P_CK = getInputPort("CK")->getTransitionInfo().getProbability1(); + double P_Q = getOutputPort("Q")->getTransitionInfo().getProbability1(); + double CK_num_trans_01 = getInputPort("CK")->getTransitionInfo().getNumberTransitions01(); + double D_num_trans_01 = getInputPort("D")->getTransitionInfo().getNumberTransitions01(); + double M_num_trans_01 = m_trans_M_.getNumberTransitions01(); + double Q_num_trans_01 = getOutputPort("Q")->getTransitionInfo().getNumberTransitions01(); + + // Calculate leakage + double leakage = 0; + leakage += cache->get(cell_name + "->Leakage->!D!CK!Q") * (1 - P_D) * (1 - P_CK) * (1 - P_Q); + leakage += cache->get(cell_name + "->Leakage->!D!CKQ") * (1 - P_D) * (1 - P_CK) * P_Q; + leakage += cache->get(cell_name + "->Leakage->!DCK!Q") * (1 - P_D) * P_CK * (1 - P_Q); + leakage += cache->get(cell_name + "->Leakage->!DCKQ") * (1 - P_D) * P_CK * P_Q; + leakage += cache->get(cell_name + "->Leakage->D!CK!Q") * P_D * (1 - P_CK) * (1 - P_Q); + leakage += cache->get(cell_name + "->Leakage->D!CKQ") * P_D * (1 - P_CK) * P_Q; + leakage += cache->get(cell_name + "->Leakage->DCK!Q") * P_D * P_CK * (1 - P_Q); + leakage += cache->get(cell_name + "->Leakage->DCKQ") * P_D * P_CK * P_Q; + getNddPowerResult("Leakage")->setValue(leakage); + + // Get VDD + double vdd = getTechModel()->get("Vdd"); + + // Get capacitances + double ck_b_cap = cache->get(cell_name + "->Cap->CK_b"); + double ck_i_cap = cache->get(cell_name + "->Cap->CK_i"); + double d_b_cap = cache->get(cell_name + "->Cap->D_b"); + double m_b_cap = cache->get(cell_name + "->Cap->M_b"); + double m_cap = cache->get(cell_name + "->Cap->M"); + double m_i_cap = cache->get(cell_name + "->Cap->M_i"); + double q_b_cap = cache->get(cell_name + "->Cap->Q_b"); + double q_cap = cache->get(cell_name + "->Cap->Q"); + double q_load_cap = getNet("Q")->getTotalDownstreamCap(); + + // Calculate CK Event energy + double ck_event_energy = 0.0; + ck_event_energy += (ck_b_cap + ck_i_cap) * CK_num_trans_01; + ck_event_energy *= vdd * vdd; + getEventResult("CK")->setValue(ck_event_energy); + // Calculate DFFD Event energy + double dffd_event_energy = 0.0; + dffd_event_energy += (d_b_cap) * D_num_trans_01; + dffd_event_energy += (m_b_cap + m_cap) * M_num_trans_01; + dffd_event_energy *= vdd * vdd; + getEventResult("DFFD")->setValue(dffd_event_energy); + // Calculate DFFQ Event energy + double dffq_event_energy = 0.0; + dffq_event_energy += (m_i_cap + q_b_cap + q_cap + q_load_cap) * Q_num_trans_01; + dffq_event_energy *= vdd * vdd; + getEventResult("DFFQ")->setValue(dffq_event_energy); + + return; + } + + void DFFQ::propagateTransitionInfo() + { + const TransitionInfo& trans_CK = getInputPort("CK")->getTransitionInfo(); + const TransitionInfo& trans_D = getInputPort("D")->getTransitionInfo(); + + double CK_num_trans_01 = trans_CK.getNumberTransitions01(); + double CK_num_trans_10 = CK_num_trans_01; + double CK_num_trans_00 = trans_CK.getNumberTransitions00(); + double D_freq_mult = trans_D.getFrequencyMultiplier(); + + // If thre is no activity on the clock or D, assume M node is randomly distributed among 0 and 1 + if(LibUtil::Math::isEqual(CK_num_trans_10 + CK_num_trans_00, 0.0) || LibUtil::Math::isEqual(D_freq_mult, 0.0)) + { + m_trans_M_ = TransitionInfo(0.5, 0.0, 0.5); + } + // If the master latch is sampling just as fast or faster than input data signal + // Then it can capture all transitions (though it should be normalized to clock) + else if((CK_num_trans_10 + CK_num_trans_00) >= D_freq_mult) + { + m_trans_M_ = trans_D.scaleFrequencyMultiplier(CK_num_trans_10 + CK_num_trans_00); + } + // If the master latch is sampling slower than the input data signal, then input + // will look like they transition more + else + { + // Calculate scale ratio + double scale_ratio = (CK_num_trans_10 + CK_num_trans_00) / D_freq_mult; + // 00 and 11 transitions become fewer + double D_scaled_diff = 0.5 * (1 - scale_ratio) * (trans_D.getNumberTransitions00() + trans_D.getNumberTransitions11()); + double D_scaled_num_trans_00 = trans_D.getNumberTransitions00() * scale_ratio; + double D_scaled_num_trans_11 = trans_D.getNumberTransitions11() * scale_ratio; + // 01 and 10 transitions become more frequent + double D_scaled_num_trans_10 = trans_D.getNumberTransitions01() + D_scaled_diff; + + // Create final transition info, remembering to apply scaling ratio to normalize to CK + m_trans_M_ = TransitionInfo(D_scaled_num_trans_00 * scale_ratio, + D_scaled_num_trans_10 * scale_ratio, + D_scaled_num_trans_11 * scale_ratio); + } + + // If the clock activity is 0 or if D activity is 0, then we assume that the output is randomly distributed among 0 and 1 + if(LibUtil::Math::isEqual(CK_num_trans_01, 0.0) || LibUtil::Math::isEqual(D_freq_mult, 0.0)) + { + getOutputPort("Q")->setTransitionInfo(TransitionInfo(0.5, 0.0, 0.5)); + } + // If the DFF's CK is running at a higher frequency than D, Q is just D with a + // scaled up frequency multiplier + else if(CK_num_trans_01 >= D_freq_mult) + { + const TransitionInfo& trans_Q = trans_D.scaleFrequencyMultiplier(CK_num_trans_01); + getOutputPort("Q")->setTransitionInfo(trans_Q); + } + // If the DFF is sampling slower than the input data signal, then inputs + // will look like they transition more + else + { + // Calculate scale ratio + double scale_ratio = CK_num_trans_01 / D_freq_mult; + // 00 and 11 transitions become fewer + double D_scaled_diff = 0.5 * (1 - scale_ratio) * (trans_D.getNumberTransitions00() + trans_D.getNumberTransitions11()); + double D_scaled_num_trans_00 = trans_D.getNumberTransitions00() * scale_ratio; + double D_scaled_num_trans_11 = trans_D.getNumberTransitions11() * scale_ratio; + // 01 and 10 transitions become more frequent + double D_scaled_num_trans_10 = trans_D.getNumberTransitions01() + D_scaled_diff; + const TransitionInfo trans_Q( D_scaled_num_trans_00 * scale_ratio, + D_scaled_num_trans_10 * scale_ratio, + D_scaled_num_trans_11 * scale_ratio); + getOutputPort("Q")->setTransitionInfo(trans_Q); + } + return; + } + + // Creates the standard cell, characterizes and abstracts away the details + void DFFQ::cacheStdCell(StdCellLib* cell_lib_, double drive_strength_) + { + // Get parameters + double gate_pitch = cell_lib_->getTechModel()->get("Gate->PitchContacted"); + Map<double>* cache = cell_lib_->getStdCellCache(); + + // Standard cell cache string + String cell_name = "DFFQ_X" + (String) drive_strength_; + + Log::printLine("=== " + cell_name + " ==="); + + + // Now actually build the full standard cell model + createInputPort("D"); + createInputPort("CK"); + createOutputPort("Q"); + + createNet("D_b"); + createNet("M_b"); + createNet("M"); + createNet("M_i"); + createNet("Q_b"); + createNet("CK_b"); + createNet("CK_i"); + + // Adds macros + CellMacros::addInverter(this, "INV1", false, true, "D", "D_b"); + CellMacros::addInverter(this, "INV2", false, true, "M_b", "M"); + CellMacros::addInverter(this, "INV3", false, true, "M_i", "Q_b"); + CellMacros::addInverter(this, "INV4", true, true, "Q_b", "Q"); + CellMacros::addInverter(this, "INV5", false, true, "CK", "CK_b"); + CellMacros::addInverter(this, "INV6", false, true, "CK_b", "CK_i"); + CellMacros::addTristate(this, "INVZ1", false, true, false, false, "D_b", "CK_b", "CK_i", "M_b"); //trace timing through A->ZN path only + CellMacros::addTristate(this, "INVZ2", false, false, false, false, "M", "CK_i", "CK_b", "M_b"); //don't trace timing through the feedback path + CellMacros::addTristate(this, "INVZ3", false, false, true, true, "M", "CK_i", "CK_b", "M_i"); //trace timing from OE->ZN and OEN->ZN paths only + CellMacros::addTristate(this, "INVZ4", false, false, false, false, "Q_b", "CK_b", "CK_i", "M_i"); //don't trace timing through the feedback path + + // Update macros + CellMacros::updateInverter(this, "INV1", drive_strength_ * 0.125); + CellMacros::updateInverter(this, "INV2", drive_strength_ * 0.5); + CellMacros::updateInverter(this, "INV3", drive_strength_ * 0.5); + CellMacros::updateInverter(this, "INV4", drive_strength_ * 1.0); + CellMacros::updateInverter(this, "INV5", drive_strength_ * 0.125); + CellMacros::updateInverter(this, "INV6", drive_strength_ * 0.125); + CellMacros::updateTristate(this, "INVZ1", drive_strength_ * 0.5); + CellMacros::updateTristate(this, "INVZ2", drive_strength_ * 0.0625); + CellMacros::updateTristate(this, "INVZ3", drive_strength_ * 0.5); + CellMacros::updateTristate(this, "INVZ4", drive_strength_ * 0.0625); + + // Cache area result + double area = 0.0; + area += gate_pitch * getTotalHeight() * 1; + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INV1_GatePitches").toDouble(); + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INV2_GatePitches").toDouble(); + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INV3_GatePitches").toDouble(); + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INV4_GatePitches").toDouble(); + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INV5_GatePitches").toDouble(); + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INV6_GatePitches").toDouble(); + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INVZ1_GatePitches").toDouble(); + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INVZ2_GatePitches").toDouble(); + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INVZ3_GatePitches").toDouble(); + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INVZ4_GatePitches").toDouble(); + cache->set(cell_name + "->Area->Active", area); + cache->set(cell_name + "->Area->Metal1Wire", area); + Log::printLine(cell_name + "->Area->Active=" + (String) area); + Log::printLine(cell_name + "->Area->Metal1Wire=" + (String) area); + + // -------------------------------------------------------------------- + // Leakage Model Calculation + // -------------------------------------------------------------------- + // Cache leakage power results (for every single signal combination) + double leakage_000 = 0; //!D, !CK, !Q + double leakage_001 = 0; //!D, !CK, Q + double leakage_010 = 0; //!D, CK, !Q + double leakage_011 = 0; //!D, CK, Q + double leakage_100 = 0; //D, !CK, !Q + double leakage_101 = 0; //D, !CK, Q + double leakage_110 = 0; //D, CK, !Q + double leakage_111 = 0; //D, CK, Q + + //This is so painful... + leakage_000 += getGenProperties()->get("INV1_LeakagePower_0").toDouble(); + leakage_000 += getGenProperties()->get("INV2_LeakagePower_0").toDouble(); + leakage_000 += getGenProperties()->get("INV3_LeakagePower_0").toDouble(); + leakage_000 += getGenProperties()->get("INV4_LeakagePower_1").toDouble(); + leakage_000 += getGenProperties()->get("INV5_LeakagePower_0").toDouble(); + leakage_000 += getGenProperties()->get("INV6_LeakagePower_1").toDouble(); + leakage_000 += getGenProperties()->get("INVZ1_LeakagePower_101_0").toDouble(); + leakage_000 += getGenProperties()->get("INVZ2_LeakagePower_011_0").toDouble(); + leakage_000 += getGenProperties()->get("INVZ3_LeakagePower_011_0").toDouble(); + leakage_000 += getGenProperties()->get("INVZ4_LeakagePower_101_0").toDouble(); + + leakage_001 += getGenProperties()->get("INV1_LeakagePower_0").toDouble(); + leakage_001 += getGenProperties()->get("INV2_LeakagePower_0").toDouble(); + leakage_001 += getGenProperties()->get("INV3_LeakagePower_1").toDouble(); + leakage_001 += getGenProperties()->get("INV4_LeakagePower_0").toDouble(); + leakage_001 += getGenProperties()->get("INV5_LeakagePower_0").toDouble(); + leakage_001 += getGenProperties()->get("INV6_LeakagePower_1").toDouble(); + leakage_001 += getGenProperties()->get("INVZ1_LeakagePower_101_0").toDouble(); + leakage_001 += getGenProperties()->get("INVZ2_LeakagePower_011_0").toDouble(); + leakage_001 += getGenProperties()->get("INVZ3_LeakagePower_011_1").toDouble(); + leakage_001 += getGenProperties()->get("INVZ4_LeakagePower_100_1").toDouble(); + + leakage_010 += getGenProperties()->get("INV1_LeakagePower_0").toDouble(); + leakage_010 += getGenProperties()->get("INV2_LeakagePower_0").toDouble(); + leakage_010 += getGenProperties()->get("INV3_LeakagePower_0").toDouble(); + leakage_010 += getGenProperties()->get("INV4_LeakagePower_1").toDouble(); + leakage_010 += getGenProperties()->get("INV5_LeakagePower_1").toDouble(); + leakage_010 += getGenProperties()->get("INV6_LeakagePower_0").toDouble(); + leakage_010 += getGenProperties()->get("INVZ1_LeakagePower_011_0").toDouble(); + leakage_010 += getGenProperties()->get("INVZ2_LeakagePower_101_0").toDouble(); + leakage_010 += getGenProperties()->get("INVZ3_LeakagePower_101_0").toDouble(); + leakage_010 += getGenProperties()->get("INVZ4_LeakagePower_011_0").toDouble(); + + leakage_011 += getGenProperties()->get("INV1_LeakagePower_0").toDouble(); + leakage_011 += getGenProperties()->get("INV2_LeakagePower_1").toDouble(); + leakage_011 += getGenProperties()->get("INV3_LeakagePower_1").toDouble(); + leakage_011 += getGenProperties()->get("INV4_LeakagePower_0").toDouble(); + leakage_011 += getGenProperties()->get("INV5_LeakagePower_1").toDouble(); + leakage_011 += getGenProperties()->get("INV6_LeakagePower_0").toDouble(); + leakage_011 += getGenProperties()->get("INVZ1_LeakagePower_011_1").toDouble(); + leakage_011 += getGenProperties()->get("INVZ2_LeakagePower_100_1").toDouble(); + leakage_011 += getGenProperties()->get("INVZ3_LeakagePower_100_1").toDouble(); + leakage_011 += getGenProperties()->get("INVZ4_LeakagePower_010_1").toDouble(); + + leakage_100 += getGenProperties()->get("INV1_LeakagePower_1").toDouble(); + leakage_100 += getGenProperties()->get("INV2_LeakagePower_1").toDouble(); + leakage_100 += getGenProperties()->get("INV3_LeakagePower_0").toDouble(); + leakage_100 += getGenProperties()->get("INV4_LeakagePower_1").toDouble(); + leakage_100 += getGenProperties()->get("INV5_LeakagePower_0").toDouble(); + leakage_100 += getGenProperties()->get("INV6_LeakagePower_1").toDouble(); + leakage_100 += getGenProperties()->get("INVZ1_LeakagePower_100_1").toDouble(); + leakage_100 += getGenProperties()->get("INVZ2_LeakagePower_010_1").toDouble(); + leakage_100 += getGenProperties()->get("INVZ3_LeakagePower_010_0").toDouble(); + leakage_100 += getGenProperties()->get("INVZ4_LeakagePower_101_0").toDouble(); + + leakage_101 += getGenProperties()->get("INV1_LeakagePower_1").toDouble(); + leakage_101 += getGenProperties()->get("INV2_LeakagePower_1").toDouble(); + leakage_101 += getGenProperties()->get("INV3_LeakagePower_1").toDouble(); + leakage_101 += getGenProperties()->get("INV4_LeakagePower_0").toDouble(); + leakage_101 += getGenProperties()->get("INV5_LeakagePower_0").toDouble(); + leakage_101 += getGenProperties()->get("INV6_LeakagePower_1").toDouble(); + leakage_101 += getGenProperties()->get("INVZ1_LeakagePower_100_1").toDouble(); + leakage_101 += getGenProperties()->get("INVZ2_LeakagePower_010_1").toDouble(); + leakage_101 += getGenProperties()->get("INVZ3_LeakagePower_010_1").toDouble(); + leakage_101 += getGenProperties()->get("INVZ4_LeakagePower_100_1").toDouble(); + + leakage_110 += getGenProperties()->get("INV1_LeakagePower_1").toDouble(); + leakage_110 += getGenProperties()->get("INV2_LeakagePower_0").toDouble(); + leakage_110 += getGenProperties()->get("INV3_LeakagePower_0").toDouble(); + leakage_110 += getGenProperties()->get("INV4_LeakagePower_1").toDouble(); + leakage_110 += getGenProperties()->get("INV5_LeakagePower_1").toDouble(); + leakage_110 += getGenProperties()->get("INV6_LeakagePower_0").toDouble(); + leakage_110 += getGenProperties()->get("INVZ1_LeakagePower_010_0").toDouble(); + leakage_110 += getGenProperties()->get("INVZ2_LeakagePower_101_0").toDouble(); + leakage_110 += getGenProperties()->get("INVZ3_LeakagePower_101_0").toDouble(); + leakage_110 += getGenProperties()->get("INVZ4_LeakagePower_011_0").toDouble(); + + leakage_111 += getGenProperties()->get("INV1_LeakagePower_1").toDouble(); + leakage_111 += getGenProperties()->get("INV2_LeakagePower_1").toDouble(); + leakage_111 += getGenProperties()->get("INV3_LeakagePower_1").toDouble(); + leakage_111 += getGenProperties()->get("INV4_LeakagePower_0").toDouble(); + leakage_111 += getGenProperties()->get("INV5_LeakagePower_1").toDouble(); + leakage_111 += getGenProperties()->get("INV6_LeakagePower_0").toDouble(); + leakage_111 += getGenProperties()->get("INVZ1_LeakagePower_010_1").toDouble(); + leakage_111 += getGenProperties()->get("INVZ2_LeakagePower_100_1").toDouble(); + leakage_111 += getGenProperties()->get("INVZ3_LeakagePower_100_1").toDouble(); + leakage_111 += getGenProperties()->get("INVZ4_LeakagePower_010_1").toDouble(); + + cache->set(cell_name + "->Leakage->!D!CK!Q", leakage_000); + cache->set(cell_name + "->Leakage->!D!CKQ", leakage_001); + cache->set(cell_name + "->Leakage->!DCK!Q", leakage_010); + cache->set(cell_name + "->Leakage->!DCKQ", leakage_011); + cache->set(cell_name + "->Leakage->D!CK!Q", leakage_100); + cache->set(cell_name + "->Leakage->D!CKQ", leakage_101); + cache->set(cell_name + "->Leakage->DCK!Q", leakage_110); + cache->set(cell_name + "->Leakage->DCKQ", leakage_111); + Log::printLine(cell_name + "->Leakage->!D!CK!Q=" + (String) leakage_000); + Log::printLine(cell_name + "->Leakage->!D!CKQ=" + (String) leakage_001); + Log::printLine(cell_name + "->Leakage->!DCK!Q=" + (String) leakage_010); + Log::printLine(cell_name + "->Leakage->!DCKQ=" + (String) leakage_011); + Log::printLine(cell_name + "->Leakage->D!CK!Q=" + (String) leakage_100); + Log::printLine(cell_name + "->Leakage->D!CKQ=" + (String) leakage_101); + Log::printLine(cell_name + "->Leakage->DCK!Q=" + (String) leakage_110); + Log::printLine(cell_name + "->Leakage->DCKQ=" + (String) leakage_111); + // -------------------------------------------------------------------- + + /* + // Cache event energy results + double event_ck_flip = 0.0; + event_ck_flip += getGenProperties()->get("INV5_A_Flip").toDouble() + getGenProperties()->get("INV5_ZN_Flip").toDouble(); + event_ck_flip += getGenProperties()->get("INV6_A_Flip").toDouble() + getGenProperties()->get("INV6_ZN_Flip").toDouble(); + event_ck_flip += getGenProperties()->get("INVZ1_OE_Flip").toDouble() + getGenProperties()->get("INVZ1_OEN_Flip").toDouble(); + event_ck_flip += getGenProperties()->get("INVZ2_OE_Flip").toDouble() + getGenProperties()->get("INVZ2_OEN_Flip").toDouble(); + event_ck_flip += getGenProperties()->get("INVZ3_OE_Flip").toDouble() + getGenProperties()->get("INVZ3_OEN_Flip").toDouble(); + event_ck_flip += getGenProperties()->get("INVZ4_OE_Flip").toDouble() + getGenProperties()->get("INVZ4_OEN_Flip").toDouble(); + cache->set(cell_name + "->Event_CK_Flip", event_ck_flip); + Log::printLine(cell_name + "->Event_CK_Flip=" + (String) event_ck_flip); + + // Update D flip results + double event_d_flip = 0.0; + event_d_flip += getGenProperties()->get("INV1_A_Flip").toDouble() + getGenProperties()->get("INV1_ZN_Flip").toDouble(); + event_d_flip += getGenProperties()->get("INVZ1_A_Flip").toDouble(); + cache->set(cell_name + "->Event_D_Flip", event_d_flip); + Log::printLine(cell_name + "->Event_D_Flip=" + (String) event_d_flip); + // Update M flip results + double event_m_flip = 0.0; + event_m_flip += getGenProperties()->get("INVZ1_ZN_Flip").toDouble(); + event_m_flip += getGenProperties()->get("INV2_A_Flip").toDouble() + getGenProperties()->get("INV2_ZN_Flip").toDouble(); + event_m_flip += getGenProperties()->get("INVZ2_A_Flip").toDouble() + getGenProperties()->get("INVZ2_ZN_Flip").toDouble(); + event_m_flip += getGenProperties()->get("INVZ3_A_Flip").toDouble(); + cache->set(cell_name + "->Event_M_Flip", event_m_flip); + Log::printLine(cell_name + "->Event_M_Flip=" + (String) event_m_flip); + // Update Q flip results + double event_q_flip = 0.0; + event_q_flip += getGenProperties()->get("INVZ3_ZN_Flip").toDouble(); + event_q_flip += getGenProperties()->get("INV3_A_Flip").toDouble() + getGenProperties()->get("INV3_ZN_Flip").toDouble(); + event_q_flip += getGenProperties()->get("INVZ4_A_Flip").toDouble() + getGenProperties()->get("INVZ4_ZN_Flip").toDouble(); + event_q_flip += getGenProperties()->get("INV4_A_Flip").toDouble() + getGenProperties()->get("INV4_ZN_Flip").toDouble(); + cache->set(cell_name + "->Event_Q_Flip", event_q_flip); + Log::printLine(cell_name + "->Event_Q_Flip=" + (String) event_q_flip); + */ + + // -------------------------------------------------------------------- + // Get Node Capacitances + // -------------------------------------------------------------------- + double d_cap = getNet("D")->getTotalDownstreamCap(); + double d_b_cap = getNet("D_b")->getTotalDownstreamCap(); + double m_b_cap = getNet("M_b")->getTotalDownstreamCap(); + double m_cap = getNet("M")->getTotalDownstreamCap(); + double m_i_cap = getNet("M_i")->getTotalDownstreamCap(); + double q_b_cap = getNet("Q_b")->getTotalDownstreamCap(); + double q_cap = getNet("Q")->getTotalDownstreamCap(); + double ck_cap = getNet("CK")->getTotalDownstreamCap(); + double ck_b_cap = getNet("CK_b")->getTotalDownstreamCap(); + double ck_i_cap = getNet("CK_i")->getTotalDownstreamCap(); + + cache->set(cell_name + "->Cap->D", d_cap); + cache->set(cell_name + "->Cap->D_b", d_b_cap); + cache->set(cell_name + "->Cap->M_b", m_b_cap); + cache->set(cell_name + "->Cap->M", m_cap); + cache->set(cell_name + "->Cap->M_i", m_i_cap); + cache->set(cell_name + "->Cap->Q_b", q_b_cap); + cache->set(cell_name + "->Cap->Q", q_cap); + cache->set(cell_name + "->Cap->CK", ck_cap); + cache->set(cell_name + "->Cap->CK_b", ck_b_cap); + cache->set(cell_name + "->Cap->CK_i", ck_i_cap); + + Log::printLine(cell_name + "->Cap->D=" + (String) d_cap); + Log::printLine(cell_name + "->Cap->D_b=" + (String) d_b_cap); + Log::printLine(cell_name + "->Cap->M_b=" + (String) m_b_cap); + Log::printLine(cell_name + "->Cap->M=" + (String) m_cap); + Log::printLine(cell_name + "->Cap->M_i=" + (String) m_i_cap); + Log::printLine(cell_name + "->Cap->Q_b=" + (String) q_b_cap); + Log::printLine(cell_name + "->Cap->Q=" + (String) q_cap); + Log::printLine(cell_name + "->Cap->CK=" + (String) ck_cap); + Log::printLine(cell_name + "->Cap->CK_b=" + (String) ck_b_cap); + Log::printLine(cell_name + "->Cap->CK_i=" + (String) ck_i_cap); + // -------------------------------------------------------------------- + + // -------------------------------------------------------------------- + // Build Internal Delay Model + // -------------------------------------------------------------------- + double q_ron = getDriver("INV4_RonZN")->getOutputRes(); + + double d_setup_delay = getDriver("INV1_RonZN")->calculateDelay() + + getDriver("INVZ1_RonZN")->calculateDelay() + + getDriver("INV2_RonZN")->calculateDelay(); + double ck_to_q_delay = getDriver("INV5_RonZN")->calculateDelay() + + getDriver("INV6_RonZN")->calculateDelay() + + getDriver("INVZ3_RonZN")->calculateDelay() + + getDriver("INV3_RonZN")->calculateDelay() + + getDriver("INV4_RonZN")->calculateDelay(); + + cache->set(cell_name + "->DriveRes->Q", q_ron); + cache->set(cell_name + "->Delay->D_Setup", d_setup_delay); + cache->set(cell_name + "->Delay->CK_to_Q", ck_to_q_delay); + Log::printLine(cell_name + "->DriveRes->Q=" + (String) q_ron); + Log::printLine(cell_name + "->Delay->D_Setup=" + (String) d_setup_delay); + Log::printLine(cell_name + "->Delay->CK_to_Q=" + (String) ck_to_q_delay); + + return; + // -------------------------------------------------------------------- + } + +} // namespace DSENT + diff --git a/ext/dsent/model/std_cells/DFFQ.h b/ext/dsent/model/std_cells/DFFQ.h new file mode 100644 index 000000000..699e48627 --- /dev/null +++ b/ext/dsent/model/std_cells/DFFQ.h @@ -0,0 +1,38 @@ +#ifndef __DSENT_MODEL_STD_CELLS_DFFQ_H__ +#define __DSENT_MODEL_STD_CELLS_DFFQ_H__ + +#include "util/CommonType.h" +#include "model/std_cells/StdCell.h" +#include "model/TransitionInfo.h" + +namespace DSENT +{ + class DFFQ : public StdCell + { + // A DQ flip-flop + public: + DFFQ(const String& instance_name_, const TechModel* tech_model_); + virtual ~DFFQ(); + + public: + // Set a list of properties' name needed to construct model + void initProperties(); + // Cache the standard cell + void cacheStdCell(StdCellLib* cell_lib_, double drive_strength_); + + private: + TransitionInfo m_trans_M_; + + protected: + // Build the model + virtual void constructModel(); + virtual void updateModel(); + virtual void evaluateModel(); + virtual void useModel(); + virtual void propagateTransitionInfo(); + + }; // class DFFQ +} // namespace DSENT + +#endif // __DSENT_MODEL_STD_CELLS_INV_H__ + diff --git a/ext/dsent/model/std_cells/INV.cc b/ext/dsent/model/std_cells/INV.cc new file mode 100644 index 000000000..a6ea6c4f4 --- /dev/null +++ b/ext/dsent/model/std_cells/INV.cc @@ -0,0 +1,219 @@ +#include "model/std_cells/INV.h" + +#include <cmath> + +#include "model/PortInfo.h" +#include "model/TransitionInfo.h" +#include "model/EventInfo.h" +#include "model/std_cells/CellMacros.h" +#include "model/std_cells/StdCellLib.h" +#include "model/timing_graph/ElectricalNet.h" +#include "model/timing_graph/ElectricalDriver.h" +#include "model/timing_graph/ElectricalLoad.h" +#include "model/timing_graph/ElectricalDelay.h" + +namespace DSENT +{ + using std::ceil; + using std::max; + + INV::INV(const String& instance_name_, const TechModel* tech_model_) + : StdCell(instance_name_, tech_model_) + { + initProperties(); + } + + INV::~INV() + {} + + void INV::initProperties() + { + return; + } + + void INV::constructModel() + { + // All constructModel should do is create Area/NDDPower/Energy Results as + // well as instantiate any sub-instances using only the hard parameters + + // Build Electrical Connectivity + createInputPort("A"); + createOutputPort("Y"); + + createLoad("A_Cap"); + createDelay("A_to_Y_delay"); + createDriver("Y_Ron", true); + + ElectricalLoad* a_cap = getLoad("A_Cap"); + ElectricalDelay* a_to_y_delay = getDelay("A_to_Y_delay"); + ElectricalDriver* y_ron = getDriver("Y_Ron"); + + getNet("A")->addDownstreamNode(a_cap); + a_cap->addDownstreamNode(a_to_y_delay); + a_to_y_delay->addDownstreamNode(y_ron); + y_ron->addDownstreamNode(getNet("Y")); + + // Create Area result + // Create NDD Power result + createElectricalAtomicResults(); + // Create INV Event Energy Result + createElectricalEventAtomicResult("INV"); + + getEventInfo("Idle")->setStaticTransitionInfos(); + + return; + } + + void INV::updateModel() + { + // All updateModel should do is calculate numbers for the Area/NDDPower/Energy + // Results as anything else that needs to be done using either soft or hard parameters + + // Get parameters + double drive_strength = getDrivingStrength(); + Map<double>* cache = getTechModel()->getStdCellLib()->getStdCellCache(); + + // Standard cell cache string + String cell_name = "INV_X" + (String) drive_strength; + + // Get timing parameters + getLoad("A_Cap")->setLoadCap(cache->get(cell_name + "->Cap->A")); + getDriver("Y_Ron")->setOutputRes(cache->get(cell_name + "->DriveRes->Y")); + getDelay("A_to_Y_delay")->setDelay(cache->get(cell_name + "->Delay->A_to_Y")); + + // Set the cell area + getAreaResult("Active")->setValue(cache->get(cell_name + "->Area->Active")); + getAreaResult("Metal1Wire")->setValue(cache->get(cell_name + "->Area->Metal1Wire")); + + return; + } + + void INV::evaluateModel() + { + return; + } + + void INV::useModel() + { + // Get parameters + double drive_strength = getDrivingStrength(); + Map<double>* cache = getTechModel()->getStdCellLib()->getStdCellCache(); + + // Standard cell cache string + String cell_name = "INV_X" + (String) drive_strength; + + // Propagate the transition info and get the 0->1 transtion count + propagateTransitionInfo(); + double P_A = getInputPort("A")->getTransitionInfo().getProbability1(); + double Y_num_trans_01 = getOutputPort("Y")->getTransitionInfo().getNumberTransitions01(); + + // Calculate leakage + double leakage = 0; + leakage += cache->get(cell_name + "->Leakage->!A") * (1 - P_A); + leakage += cache->get(cell_name + "->Leakage->A") * P_A; + getNddPowerResult("Leakage")->setValue(leakage); + + // Get VDD + double vdd = getTechModel()->get("Vdd"); + + // Get capacitances + //double a_cap = cache->get(cell_name + "->Cap->A"); + double y_cap = cache->get(cell_name + "->Cap->Y"); + double y_load_cap = getNet("Y")->getTotalDownstreamCap(); + + // Calculate INV Event energy + double energy_per_trans_01 = (y_cap + y_load_cap) * vdd * vdd; + getEventResult("INV")->setValue(energy_per_trans_01 * Y_num_trans_01); + return; + } + + void INV::propagateTransitionInfo() + { + // Get input transition info + const TransitionInfo& trans_A = getInputPort("A")->getTransitionInfo(); + + // Set output transition info + double Y_num_trans_00 = trans_A.getNumberTransitions11(); + double Y_num_trans_01 = trans_A.getNumberTransitions01(); + double Y_num_trans_11 = trans_A.getNumberTransitions00(); + + TransitionInfo trans_Y(Y_num_trans_00, Y_num_trans_01, Y_num_trans_11); + getOutputPort("Y")->setTransitionInfo(trans_Y); + return; + } + + // Creates the standard cell, characterizes and abstracts away the details + void INV::cacheStdCell(StdCellLib* cell_lib_, double drive_strength_) + { + // Standard cell cache string + String cell_name = "INV_X" + (String) drive_strength_; + + Log::printLine("=== " + cell_name + " ==="); + + // Get parameters + double gate_pitch = cell_lib_->getTechModel()->get("Gate->PitchContacted"); + Map<double>* cache = cell_lib_->getStdCellCache(); + + // Now actually build the full standard cell model + // Create the two input ports + createInputPort("A"); + createOutputPort("Y"); + + // Adds macros + CellMacros::addInverter(this, "INV", true, true, "A", "Y"); + CellMacros::updateInverter(this, "INV", drive_strength_); + + // Cache area result + double area = gate_pitch * getTotalHeight() * (1 + getGenProperties()->get("INV_GatePitches").toDouble()); + cache->set(cell_name + "->Area->Active", area); + cache->set(cell_name + "->Area->Metal1Wire", area); + Log::printLine(cell_name + "->Area->Active=" + (String) area); + Log::printLine(cell_name + "->Area->Metal1Wire=" + (String) area); + + // -------------------------------------------------------------------- + // Leakage Model Calculation + // -------------------------------------------------------------------- + double leakage_a0 = getGenProperties()->get("INV_LeakagePower_0").toDouble(); + double leakage_a1 = getGenProperties()->get("INV_LeakagePower_1").toDouble(); + cache->set(cell_name + "->Leakage->!A", leakage_a0); + cache->set(cell_name + "->Leakage->A", leakage_a1); + Log::printLine(cell_name + "->Leakage->!A=" + (String) leakage_a0); + Log::printLine(cell_name + "->Leakage->A=" + (String) leakage_a1); + // -------------------------------------------------------------------- + + /* + // Cache event energy results + double event_a_flip = getGenProperties()->get("INV_A_Flip").toDouble() + getGenProperties()->get("INV_ZN_Flip").toDouble(); + cache->set(cell_name + "->Event_A_Flip", event_a_flip); + Log::printLine(cell_name + "->Event_A_Flip=" + (String) event_a_flip); + */ + + // -------------------------------------------------------------------- + // Get Node Capacitances + // -------------------------------------------------------------------- + double a_cap = getNet("A")->getTotalDownstreamCap(); + double y_cap = getNet("Y")->getTotalDownstreamCap(); + + cache->set(cell_name + "->Cap->A", a_cap); + cache->set(cell_name + "->Cap->Y", y_cap); + Log::printLine(cell_name + "->Cap->A=" + (String) a_cap); + Log::printLine(cell_name + "->Cap->Y=" + (String) y_cap); + // -------------------------------------------------------------------- + + // -------------------------------------------------------------------- + // Build Internal Delay Model + // -------------------------------------------------------------------- + double y_ron = getDriver("INV_RonZN")->getOutputRes(); + double a_to_y_delay = getDriver("INV_RonZN")->calculateDelay(); + cache->set(cell_name + "->DriveRes->Y", y_ron); + cache->set(cell_name + "->Delay->A_to_Y", a_to_y_delay); + Log::printLine(cell_name + "->DriveRes->Y=" + (String) y_ron); + Log::printLine(cell_name + "->Delay->A_to_Y=" + (String) a_to_y_delay); + // -------------------------------------------------------------------- + + return; + + } + +} // namespace DSENT + diff --git a/ext/dsent/model/std_cells/INV.h b/ext/dsent/model/std_cells/INV.h new file mode 100644 index 000000000..d81d207c6 --- /dev/null +++ b/ext/dsent/model/std_cells/INV.h @@ -0,0 +1,34 @@ +#ifndef __DSENT_MODEL_STD_CELLS_INV_H__ +#define __DSENT_MODEL_STD_CELLS_INV_H__ + +#include "util/CommonType.h" +#include "model/std_cells/StdCell.h" + +namespace DSENT +{ + class INV : public StdCell + { + public: + INV(const String& instance_name_, const TechModel* tech_model_); + virtual ~INV(); + + public: + // Set a list of properties' name needed to construct model + void initProperties(); + + // Cache the standard cell + void cacheStdCell(StdCellLib* cell_lib_, double drive_strength_); + + protected: + // Build the model + virtual void constructModel(); + virtual void updateModel(); + virtual void evaluateModel(); + virtual void useModel(); + virtual void propagateTransitionInfo(); + + }; // class INV +} // namespace DSENT + +#endif // __DSENT_MODEL_STD_CELLS_INV_H__ + diff --git a/ext/dsent/model/std_cells/LATQ.cc b/ext/dsent/model/std_cells/LATQ.cc new file mode 100644 index 000000000..b2548d07b --- /dev/null +++ b/ext/dsent/model/std_cells/LATQ.cc @@ -0,0 +1,380 @@ +#include "model/std_cells/LATQ.h" + +#include <cmath> + +#include "model/PortInfo.h" +#include "model/TransitionInfo.h" +#include "model/EventInfo.h" +#include "model/std_cells/StdCellLib.h" +#include "model/std_cells/CellMacros.h" +#include "model/timing_graph/ElectricalNet.h" +#include "model/timing_graph/ElectricalDriver.h" +#include "model/timing_graph/ElectricalLoad.h" +#include "model/timing_graph/ElectricalDelay.h" + +namespace DSENT +{ + using std::ceil; + using std::max; + using std::min; + + LATQ::LATQ(const String& instance_name_, const TechModel* tech_model_) + : StdCell(instance_name_, tech_model_) + { + initProperties(); + } + + LATQ::~LATQ() + {} + + void LATQ::initProperties() + { + return; + } + + void LATQ::constructModel() + { + // All constructModel should do is create Area/NDDPower/Energy Results as + // well as instantiate any sub-instances using only the hard parameters + + createInputPort("D"); + createInputPort("G"); + createOutputPort("Q"); + + createLoad("D_Cap"); + createLoad("G_Cap"); + createDelay("D_to_Q_delay"); + createDelay("G_to_Q_delay"); + createDriver("Q_Ron", true); + + ElectricalLoad* d_cap = getLoad("D_Cap"); + ElectricalLoad* g_cap = getLoad("G_Cap"); + ElectricalDelay* d_to_q_delay = getDelay("D_to_Q_delay"); + ElectricalDelay* g_to_q_delay = getDelay("G_to_Q_delay"); + ElectricalDriver* q_ron = getDriver("Q_Ron"); + + getNet("D")->addDownstreamNode(d_cap); + getNet("G")->addDownstreamNode(g_cap); + d_cap->addDownstreamNode(d_to_q_delay); + g_cap->addDownstreamNode(g_to_q_delay); + g_to_q_delay->addDownstreamNode(q_ron); + q_ron->addDownstreamNode(getNet("Q")); + + // Create Area result + // Create NDD Power result + createElectricalAtomicResults(); + // Create G Event Energy Result + createElectricalEventAtomicResult("G"); + // Create DFF Event Energy Result + createElectricalEventAtomicResult("LATD"); + createElectricalEventAtomicResult("LATQ"); + // Create Idle event for leakage + // G pin is assumed to be on all the time + //createElectricalEventAtomicResult("Idle"); + getEventInfo("Idle")->setStaticTransitionInfos(); + return; + } + + void LATQ::updateModel() + { + // Get parameters + double drive_strength = getDrivingStrength(); + Map<double>* cache = getTechModel()->getStdCellLib()->getStdCellCache(); + + // Standard cell cache string + String cell_name = "LATQ_X" + (String) drive_strength; + + // Get timing parameters + getLoad("D_Cap")->setLoadCap(cache->get(cell_name + "->Cap->D")); + getLoad("G_Cap")->setLoadCap(cache->get(cell_name + "->Cap->G")); + getDriver("Q_Ron")->setOutputRes(cache->get(cell_name + "->DriveRes->Q")); + getDelay("G_to_Q_delay")->setDelay(cache->get(cell_name + "->Delay->G_to_Q")); + getDelay("D_to_Q_delay")->setDelay(cache->get(cell_name + "->Delay->D_to_Q")); + + // Set the cell area + getAreaResult("Active")->setValue(cache->get(cell_name + "->Area->Active")); + getAreaResult("Metal1Wire")->setValue(cache->get(cell_name + "->Area->Metal1Wire")); + + return; + } + + void LATQ::evaluateModel() + { + return; + } + + void LATQ::useModel() + { + // Get parameters + double drive_strength = getDrivingStrength(); + Map<double>* cache = getTechModel()->getStdCellLib()->getStdCellCache(); + + // Standard cell cache string + String cell_name = "LATQ_X" + (String) drive_strength; + + // Propagate the transition info and get P_D, P_M, and P_Q + propagateTransitionInfo(); + double P_D = getInputPort("D")->getTransitionInfo().getProbability1(); + double P_G = getInputPort("G")->getTransitionInfo().getProbability1(); + double P_Q = getOutputPort("Q")->getTransitionInfo().getProbability1(); + double G_num_trans_01 = getInputPort("G")->getTransitionInfo().getNumberTransitions01(); + double D_num_trans_01 = getInputPort("D")->getTransitionInfo().getNumberTransitions01(); + double Q_num_trans_01 = getOutputPort("Q")->getTransitionInfo().getNumberTransitions01(); + + // Calculate leakage + double leakage = 0; + leakage += cache->get(cell_name + "->Leakage->!D!G!Q") * (1 - P_D) * (1 - P_G) * (1 - P_Q); + leakage += cache->get(cell_name + "->Leakage->!D!GQ") * (1 - P_D) * (1 - P_G) * P_Q; + leakage += cache->get(cell_name + "->Leakage->!DG!Q") * (1 - P_D) * P_G * (1 - P_Q); + leakage += cache->get(cell_name + "->Leakage->D!G!Q") * P_D * (1 - P_G) * (1 - P_Q); + leakage += cache->get(cell_name + "->Leakage->D!GQ") * P_D * (1 - P_G) * P_Q; + leakage += cache->get(cell_name + "->Leakage->DGQ") * P_D * P_G * P_Q; + getNddPowerResult("Leakage")->setValue(leakage); + + // Get VDD + double vdd = getTechModel()->get("Vdd"); + + // Get capacitances + double g_b_cap = cache->get(cell_name + "->Cap->G_b"); + double d_b_cap = cache->get(cell_name + "->Cap->D_b"); + double q_i_cap = cache->get(cell_name + "->Cap->Q_i"); + double q_b_cap = cache->get(cell_name + "->Cap->Q_b"); + double q_cap = cache->get(cell_name + "->Cap->Q"); + double q_load_cap = getNet("Q")->getTotalDownstreamCap(); + + // Calculate G Event energy + double g_event_energy = 0.0; + g_event_energy += (g_b_cap) * G_num_trans_01; + g_event_energy *= vdd * vdd; + getEventResult("G")->setValue(g_event_energy); + // Calculate LATD Event energy + double latd_event_energy = 0.0; + latd_event_energy += (d_b_cap) * D_num_trans_01; + latd_event_energy *= vdd * vdd; + getEventResult("LATD")->setValue(latd_event_energy); + // Calculate LATQ Event energy + double latq_event_energy = 0.0; + latq_event_energy += (q_i_cap + q_b_cap + q_cap + q_load_cap) * Q_num_trans_01; + latq_event_energy *= vdd * vdd; + getEventResult("LATQ")->setValue(latq_event_energy); + + return; + } + + void LATQ::propagateTransitionInfo() + { + const TransitionInfo& trans_G = getInputPort("G")->getTransitionInfo(); + const TransitionInfo& trans_D = getInputPort("D")->getTransitionInfo(); + + double G_num_trans_01 = trans_G.getNumberTransitions01(); + double G_num_trans_10 = G_num_trans_01; + double G_num_trans_00 = trans_G.getNumberTransitions00(); + double D_freq_mult = trans_D.getFrequencyMultiplier(); + + // If the latch is sampling just as fast or faster than input data signal + // Then it can capture all transitions (though it should be normalized to clock) + if((G_num_trans_10 + G_num_trans_00) >= D_freq_mult) + { + const TransitionInfo& trans_Q = trans_D.scaleFrequencyMultiplier(G_num_trans_10 + G_num_trans_00); + getOutputPort("Q")->setTransitionInfo(trans_Q); + } + // If the latch is sampling slower than the input data signal, then input + // will look like they transition more + else + { + // Calculate scale ratio + double scale_ratio = (G_num_trans_10 + G_num_trans_00) / D_freq_mult; + // 00 and 11 transitions become fewer + double D_scaled_diff = 0.5 * (1 - scale_ratio) * (trans_D.getNumberTransitions00() + trans_D.getNumberTransitions11()); + double D_scaled_num_trans_00 = trans_D.getNumberTransitions00() * scale_ratio; + double D_scaled_num_trans_11 = trans_D.getNumberTransitions11() * scale_ratio; + // 01 and 10 transitions become more frequent + double D_scaled_num_trans_10 = trans_D.getNumberTransitions01() + D_scaled_diff; + + // Create final transition info, remembering to apply scaling ratio to normalize to G + const TransitionInfo trans_Q( D_scaled_num_trans_00 * scale_ratio, + D_scaled_num_trans_10 * scale_ratio, + D_scaled_num_trans_11 * scale_ratio); + getOutputPort("Q")->setTransitionInfo(trans_Q); + } + + return; + } + + // Creates the standard cell, characterizes and abstracts away the details + void LATQ::cacheStdCell(StdCellLib* cell_lib_, double drive_strength_) + { + // Get parameters + double gate_pitch = cell_lib_->getTechModel()->get("Gate->PitchContacted"); + Map<double>* cache = cell_lib_->getStdCellCache(); + + // Standard cell cache string + String cell_name = "LATQ_X" + (String) drive_strength_; + + Log::printLine("=== " + cell_name + " ==="); + + + // Now actually build the full standard cell model + createInputPort("D"); + createInputPort("G"); + createOutputPort("Q"); + + createNet("D_b"); + createNet("Q_i"); + createNet("Q_b"); + createNet("G_b"); + + // Adds macros + CellMacros::addInverter(this, "INV1", false, true, "D", "D_b"); + CellMacros::addInverter(this, "INV2", false, true, "Q_i", "Q_b"); + CellMacros::addInverter(this, "INV3", false, true, "Q_b", "Q"); + CellMacros::addInverter(this, "INV4", false, true, "G", "G_b"); + CellMacros::addTristate(this, "INVZ1", false, true, false, false, "D_b", "G", "G_b", "Q_i"); //trace timing through A->ZN path only + CellMacros::addTristate(this, "INVZ2", false, false, false, false, "Q_b", "G_b", "G", "Q_i"); //don't trace timing through the feedback path + + // Update macros + CellMacros::updateInverter(this, "INV1", drive_strength_ * 0.125); + CellMacros::updateInverter(this, "INV2", drive_strength_ * 0.5); + CellMacros::updateInverter(this, "INV3", drive_strength_ * 1.0); + CellMacros::updateInverter(this, "INV4", drive_strength_ * 0.125); + CellMacros::updateTristate(this, "INVZ1", drive_strength_ * 0.5); + CellMacros::updateTristate(this, "INVZ2", drive_strength_ * 0.0625); + + // Cache area result + double area = 0.0; + area += gate_pitch * getTotalHeight() * 1; + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INV1_GatePitches").toDouble(); + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INV2_GatePitches").toDouble(); + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INV3_GatePitches").toDouble(); + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INV4_GatePitches").toDouble(); + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INVZ1_GatePitches").toDouble(); + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INVZ2_GatePitches").toDouble(); + cache->set(cell_name + "->Area->Active", area); + cache->set(cell_name + "->Area->Metal1Wire", area); //Cover-block m1 area + Log::printLine(cell_name + "->Area->Active=" + (String) area); + Log::printLine(cell_name + "->Area->Metal1Wire=" + (String) area); + + // -------------------------------------------------------------------- + // Leakage Model Calculation + // -------------------------------------------------------------------- + // Cache leakage power results (for every single signal combination) + double leakage_000 = 0; //!D, !G, !Q + double leakage_001 = 0; //!D, !G, Q + double leakage_010 = 0; //!D, G, !Q + double leakage_100 = 0; //D, !G, !Q + double leakage_101 = 0; //D, !G, Q + double leakage_111 = 0; //D, G, Q + + //This is so painful... + leakage_000 += getGenProperties()->get("INV1_LeakagePower_0").toDouble(); + leakage_000 += getGenProperties()->get("INV2_LeakagePower_0").toDouble(); + leakage_000 += getGenProperties()->get("INV3_LeakagePower_1").toDouble(); + leakage_000 += getGenProperties()->get("INV4_LeakagePower_0").toDouble(); + leakage_000 += getGenProperties()->get("INVZ1_LeakagePower_011_0").toDouble(); + leakage_000 += getGenProperties()->get("INVZ2_LeakagePower_101_0").toDouble(); + + leakage_001 += getGenProperties()->get("INV1_LeakagePower_0").toDouble(); + leakage_001 += getGenProperties()->get("INV2_LeakagePower_0").toDouble(); + leakage_001 += getGenProperties()->get("INV3_LeakagePower_0").toDouble(); + leakage_001 += getGenProperties()->get("INV4_LeakagePower_0").toDouble(); + leakage_001 += getGenProperties()->get("INVZ1_LeakagePower_011_1").toDouble(); + leakage_001 += getGenProperties()->get("INVZ2_LeakagePower_100_1").toDouble(); + + leakage_010 += getGenProperties()->get("INV1_LeakagePower_0").toDouble(); + leakage_010 += getGenProperties()->get("INV2_LeakagePower_0").toDouble(); + leakage_010 += getGenProperties()->get("INV3_LeakagePower_1").toDouble(); + leakage_010 += getGenProperties()->get("INV4_LeakagePower_1").toDouble(); + leakage_010 += getGenProperties()->get("INVZ1_LeakagePower_101_0").toDouble(); + leakage_010 += getGenProperties()->get("INVZ2_LeakagePower_011_0").toDouble(); + + leakage_100 += getGenProperties()->get("INV1_LeakagePower_1").toDouble(); + leakage_100 += getGenProperties()->get("INV2_LeakagePower_1").toDouble(); + leakage_100 += getGenProperties()->get("INV3_LeakagePower_1").toDouble(); + leakage_100 += getGenProperties()->get("INV4_LeakagePower_0").toDouble(); + leakage_100 += getGenProperties()->get("INVZ1_LeakagePower_010_0").toDouble(); + leakage_100 += getGenProperties()->get("INVZ2_LeakagePower_101_0").toDouble(); + + leakage_101 += getGenProperties()->get("INV1_LeakagePower_1").toDouble(); + leakage_101 += getGenProperties()->get("INV2_LeakagePower_1").toDouble(); + leakage_101 += getGenProperties()->get("INV3_LeakagePower_0").toDouble(); + leakage_101 += getGenProperties()->get("INV4_LeakagePower_0").toDouble(); + leakage_101 += getGenProperties()->get("INVZ1_LeakagePower_010_1").toDouble(); + leakage_101 += getGenProperties()->get("INVZ2_LeakagePower_100_1").toDouble(); + + leakage_111 += getGenProperties()->get("INV1_LeakagePower_1").toDouble(); + leakage_111 += getGenProperties()->get("INV2_LeakagePower_1").toDouble(); + leakage_111 += getGenProperties()->get("INV3_LeakagePower_0").toDouble(); + leakage_111 += getGenProperties()->get("INV4_LeakagePower_1").toDouble(); + leakage_111 += getGenProperties()->get("INVZ1_LeakagePower_100_1").toDouble(); + leakage_111 += getGenProperties()->get("INVZ2_LeakagePower_010_1").toDouble(); + + cache->set(cell_name + "->Leakage->!D!G!Q", leakage_000); + cache->set(cell_name + "->Leakage->!D!GQ", leakage_001); + cache->set(cell_name + "->Leakage->!DG!Q", leakage_010); + cache->set(cell_name + "->Leakage->D!G!Q", leakage_100); + cache->set(cell_name + "->Leakage->D!GQ", leakage_101); + cache->set(cell_name + "->Leakage->DGQ", leakage_111); + Log::printLine(cell_name + "->Leakage->!D!G!Q=" + (String) leakage_000); + Log::printLine(cell_name + "->Leakage->!D!GQ=" + (String) leakage_001); + Log::printLine(cell_name + "->Leakage->!DG!Q=" + (String) leakage_010); + Log::printLine(cell_name + "->Leakage->D!G!Q=" + (String) leakage_100); + Log::printLine(cell_name + "->Leakage->D!GQ=" + (String) leakage_101); + Log::printLine(cell_name + "->Leakage->DGQ=" + (String) leakage_111); + // -------------------------------------------------------------------- + + // -------------------------------------------------------------------- + // Get Node Capacitances + // -------------------------------------------------------------------- + double d_cap = getNet("D")->getTotalDownstreamCap(); + double d_b_cap = getNet("D_b")->getTotalDownstreamCap(); + double q_i_cap = getNet("Q_i")->getTotalDownstreamCap(); + double q_b_cap = getNet("Q_b")->getTotalDownstreamCap(); + double q_cap = getNet("Q")->getTotalDownstreamCap(); + double g_cap = getNet("G")->getTotalDownstreamCap(); + double g_b_cap = getNet("G_b")->getTotalDownstreamCap(); + + cache->set(cell_name + "->Cap->D", d_cap); + cache->set(cell_name + "->Cap->D_b", d_b_cap); + cache->set(cell_name + "->Cap->Q_i", q_i_cap); + cache->set(cell_name + "->Cap->Q_b", q_b_cap); + cache->set(cell_name + "->Cap->Q", q_cap); + cache->set(cell_name + "->Cap->G", g_cap); + cache->set(cell_name + "->Cap->G_b", g_b_cap); + + Log::printLine(cell_name + "->Cap->D=" + (String) d_cap); + Log::printLine(cell_name + "->Cap->D_b=" + (String) d_b_cap); + Log::printLine(cell_name + "->Cap->Q_i=" + (String) q_i_cap); + Log::printLine(cell_name + "->Cap->Q_b=" + (String) q_b_cap); + Log::printLine(cell_name + "->Cap->Q=" + (String) q_cap); + Log::printLine(cell_name + "->Cap->G=" + (String) g_cap); + Log::printLine(cell_name + "->Cap->G_b=" + (String) g_b_cap); + // -------------------------------------------------------------------- + + // -------------------------------------------------------------------- + // Build Internal Delay Model + // -------------------------------------------------------------------- + double q_ron = getDriver("INV3_RonZN")->getOutputRes(); + + double d_to_q_delay = getDriver("INV1_RonZN")->calculateDelay() + + getDriver("INVZ1_RonZN")->calculateDelay() + + getDriver("INV2_RonZN")->calculateDelay() + + getDriver("INV3_RonZN")->calculateDelay(); + double g_to_q_delay = getDriver("INV4_RonZN")->calculateDelay() + + getDriver("INVZ1_RonZN")->calculateDelay() + + getDriver("INV2_RonZN")->calculateDelay() + + getDriver("INV3_RonZN")->calculateDelay(); + + cache->set(cell_name + "->DriveRes->Q", q_ron); + cache->set(cell_name + "->Delay->D_to_Q", d_to_q_delay); + cache->set(cell_name + "->Delay->G_to_Q", g_to_q_delay); + Log::printLine(cell_name + "->DriveRes->Q=" + (String) q_ron); + Log::printLine(cell_name + "->Delay->D_to_Q=" + (String) d_to_q_delay); + Log::printLine(cell_name + "->Delay->G_to_Q=" + (String) g_to_q_delay); + + return; + // -------------------------------------------------------------------- + + } + +} // namespace DSENT + diff --git a/ext/dsent/model/std_cells/LATQ.h b/ext/dsent/model/std_cells/LATQ.h new file mode 100644 index 000000000..7dcb26fd5 --- /dev/null +++ b/ext/dsent/model/std_cells/LATQ.h @@ -0,0 +1,34 @@ +#ifndef __DSENT_MODEL_STD_CELLS_LATQ_H__ +#define __DSENT_MODEL_STD_CELLS_LATQ_H__ + +#include "util/CommonType.h" +#include "model/std_cells/StdCell.h" + +namespace DSENT +{ + class LATQ : public StdCell + { + // A DQ flip-flop + public: + LATQ(const String& instance_name_, const TechModel* tech_model_); + virtual ~LATQ(); + + public: + // Set a list of properties' name needed to construct model + void initProperties(); + // Cache the standard cell + void cacheStdCell(StdCellLib* cell_lib_, double drive_strength_); + + protected: + // Build the model + virtual void constructModel(); + virtual void updateModel(); + virtual void evaluateModel(); + virtual void useModel(); + virtual void propagateTransitionInfo(); + + }; // class LATQ +} // namespace DSENT + +#endif // __DSENT_MODEL_STD_CELLS_LATQ_H__ + diff --git a/ext/dsent/model/std_cells/MUX2.cc b/ext/dsent/model/std_cells/MUX2.cc new file mode 100644 index 000000000..73f18f7b6 --- /dev/null +++ b/ext/dsent/model/std_cells/MUX2.cc @@ -0,0 +1,420 @@ +#include "model/std_cells/MUX2.h" + +#include <cmath> + +#include "model/PortInfo.h" +#include "model/TransitionInfo.h" +#include "model/EventInfo.h" +#include "model/std_cells/StdCellLib.h" +#include "model/std_cells/CellMacros.h" +#include "model/timing_graph/ElectricalNet.h" +#include "model/timing_graph/ElectricalDriver.h" +#include "model/timing_graph/ElectricalLoad.h" +#include "model/timing_graph/ElectricalDelay.h" + +namespace DSENT +{ + using std::ceil; + using std::max; + + MUX2::MUX2(const String& instance_name_, const TechModel* tech_model_) + : StdCell(instance_name_, tech_model_) + { + initProperties(); + } + + MUX2::~MUX2() + {} + + void MUX2::initProperties() + { + return; + } + + void MUX2::constructModel() + { + // All constructModel should do is create Area/NDDPower/Energy Results as + // well as instantiate any sub-instances using only the hard parameters + + createInputPort("A"); + createInputPort("B"); + createInputPort("S0"); + createOutputPort("Y"); + + createLoad("A_Cap"); + createLoad("B_Cap"); + createLoad("S0_Cap"); + createDelay("A_to_Y_delay"); + createDelay("B_to_Y_delay"); + createDelay("S0_to_Y_delay"); + createDriver("Y_Ron", true); + + ElectricalLoad* a_cap = getLoad("A_Cap"); + ElectricalLoad* b_cap = getLoad("B_Cap"); + ElectricalLoad* s0_cap = getLoad("S0_Cap"); + ElectricalDelay* a_to_y_delay = getDelay("A_to_Y_delay"); + ElectricalDelay* b_to_y_delay = getDelay("B_to_Y_delay"); + ElectricalDelay* s0_to_y_delay = getDelay("S0_to_Y_delay"); + ElectricalDriver* y_ron = getDriver("Y_Ron"); + + getNet("A")->addDownstreamNode(a_cap); + getNet("B")->addDownstreamNode(b_cap); + getNet("S0")->addDownstreamNode(s0_cap); + a_cap->addDownstreamNode(a_to_y_delay); + b_cap->addDownstreamNode(b_to_y_delay); + s0_cap->addDownstreamNode(s0_to_y_delay); + a_to_y_delay->addDownstreamNode(y_ron); + b_to_y_delay->addDownstreamNode(y_ron); + s0_to_y_delay->addDownstreamNode(y_ron); + y_ron->addDownstreamNode(getNet("Y")); + + // Create Area result + createElectricalAtomicResults(); + getEventInfo("Idle")->setStaticTransitionInfos(); + // Create MUX2 Event Energy Result + createElectricalEventAtomicResult("MUX2"); + + + return; + } + + void MUX2::updateModel() + { + // Get parameters + double drive_strength = getDrivingStrength(); + Map<double>* cache = getTechModel()->getStdCellLib()->getStdCellCache(); + + // Standard cell cache string + String cell_name = "MUX2_X" + (String) drive_strength; + + // Get timing parameters + getLoad("A_Cap")->setLoadCap(cache->get(cell_name + "->Cap->A")); + getLoad("B_Cap")->setLoadCap(cache->get(cell_name + "->Cap->B")); + getLoad("S0_Cap")->setLoadCap(cache->get(cell_name + "->Cap->S0")); + + getDelay("A_to_Y_delay")->setDelay(cache->get(cell_name + "->Delay->A_to_Y")); + getDelay("B_to_Y_delay")->setDelay(cache->get(cell_name + "->Delay->B_to_Y")); + getDelay("S0_to_Y_delay")->setDelay(cache->get(cell_name + "->Delay->S0_to_Y")); + + getDriver("Y_Ron")->setOutputRes(cache->get(cell_name + "->DriveRes->Y")); + + // Set the cell area + getAreaResult("Active")->setValue(cache->get(cell_name + "->ActiveArea")); + getAreaResult("Metal1Wire")->setValue(cache->get(cell_name + "->ActiveArea")); + + return; + } + + void MUX2::evaluateModel() + { + return; + } + + void MUX2::useModel() + { + // Get parameters + double drive_strength = getDrivingStrength(); + Map<double>* cache = getTechModel()->getStdCellLib()->getStdCellCache(); + + // Standard cell cache string + String cell_name = "MUX2_X" + (String) drive_strength; + + // Propagate the transition and get the 0->1 transition count + propagateTransitionInfo(); + double P_A = getInputPort("A")->getTransitionInfo().getProbability1(); + double P_B = getInputPort("B")->getTransitionInfo().getProbability1(); + double P_S0 = getInputPort("S0")->getTransitionInfo().getProbability1(); + double S0_num_trans_01 = getInputPort("S0")->getTransitionInfo().getNumberTransitions01(); + double Y_num_trans_01 = getOutputPort("Y")->getTransitionInfo().getNumberTransitions01(); + + // Calculate leakage + double leakage = 0; + leakage += cache->get(cell_name + "->Leakage->!A!B!S0") * (1 - P_A) * (1 - P_B) * (1 - P_S0); + leakage += cache->get(cell_name + "->Leakage->!A!BS0") * (1 - P_A) * (1 - P_B) * P_S0; + leakage += cache->get(cell_name + "->Leakage->!AB!S0") * (1 - P_A) * P_B * (1 - P_S0); + leakage += cache->get(cell_name + "->Leakage->!ABS0") * (1 - P_A) * P_B * P_S0; + leakage += cache->get(cell_name + "->Leakage->A!B!S0") * P_A * (1 - P_B) * (1 - P_S0); + leakage += cache->get(cell_name + "->Leakage->A!BS0") * P_A * (1 - P_B) * P_S0; + leakage += cache->get(cell_name + "->Leakage->AB!S0") * P_A * P_B * (1 - P_S0); + leakage += cache->get(cell_name + "->Leakage->ABS0") * P_A * P_B * P_S0; + getNddPowerResult("Leakage")->setValue(leakage); + + // Get VDD + double vdd = getTechModel()->get("Vdd"); + + // Get capacitances + double s0_b_cap = cache->get(cell_name + "->Cap->S0_b"); + double y_bar_cap = cache->get(cell_name + "->Cap->Y_b"); + double y_cap = cache->get(cell_name + "->Cap->Y"); + double y_load_cap = getNet("Y")->getTotalDownstreamCap(); + // Create mux2 event energy + double mux2_event_energy = 0.0; + mux2_event_energy += (s0_b_cap) * S0_num_trans_01; + mux2_event_energy += (y_bar_cap + y_cap + y_load_cap) * Y_num_trans_01; + mux2_event_energy *= vdd * vdd; + getEventResult("MUX2")->setValue(mux2_event_energy); + + return; + } + + void MUX2::propagateTransitionInfo() + { + // Get input signal transition info + const TransitionInfo& trans_A = getInputPort("A")->getTransitionInfo(); + const TransitionInfo& trans_B = getInputPort("B")->getTransitionInfo(); + const TransitionInfo& trans_S0 = getInputPort("S0")->getTransitionInfo(); + + // Scale all transition information to the highest freq multiplier + double max_freq_mult = max(max(trans_A.getFrequencyMultiplier(), trans_B.getFrequencyMultiplier()), trans_S0.getFrequencyMultiplier()); + const TransitionInfo& scaled_trans_A = trans_A.scaleFrequencyMultiplier(max_freq_mult); + const TransitionInfo& scaled_trans_B = trans_B.scaleFrequencyMultiplier(max_freq_mult); + const TransitionInfo& scaled_trans_S0 = trans_S0.scaleFrequencyMultiplier(max_freq_mult); + + // Compute the probability of each transition on a given cycle + double A_prob_00 = scaled_trans_A.getNumberTransitions00() / max_freq_mult; + double A_prob_01 = scaled_trans_A.getNumberTransitions01() / max_freq_mult; + double A_prob_10 = A_prob_01; + double A_prob_11 = scaled_trans_A.getNumberTransitions11() / max_freq_mult; + double B_prob_00 = scaled_trans_B.getNumberTransitions00() / max_freq_mult; + double B_prob_01 = scaled_trans_B.getNumberTransitions01() / max_freq_mult; + double B_prob_10 = B_prob_01; + double B_prob_11 = scaled_trans_B.getNumberTransitions11() / max_freq_mult; + double S0_prob_00 = scaled_trans_S0.getNumberTransitions00() / max_freq_mult; + double S0_prob_01 = scaled_trans_S0.getNumberTransitions01() / max_freq_mult; + double S0_prob_10 = S0_prob_01; + double S0_prob_11 = scaled_trans_S0.getNumberTransitions11() / max_freq_mult; + + // Compute output probabilities + double Y_prob_00 = S0_prob_00 * A_prob_00 + + S0_prob_01 * (A_prob_00 + A_prob_01) * (B_prob_00 + B_prob_10) + + S0_prob_10 * (A_prob_00 + A_prob_10) * (B_prob_00 + B_prob_01) + + S0_prob_11 * B_prob_00; + double Y_prob_01 = S0_prob_00 * A_prob_01 + + S0_prob_01 * (A_prob_00 + A_prob_01) * (B_prob_01 + B_prob_11) + + S0_prob_10 * (A_prob_01 + A_prob_11) * (B_prob_00 + B_prob_01) + + S0_prob_11 * B_prob_01; + double Y_prob_11 = S0_prob_00 * A_prob_11 + + S0_prob_01 * (A_prob_10 + A_prob_11) * (B_prob_01 + B_prob_11) + + S0_prob_10 * (A_prob_01 + A_prob_11) * (B_prob_10 + B_prob_11) + + S0_prob_11 * B_prob_11; + + // Check that probabilities add up to 1.0 with some finite tolerance + ASSERT(LibUtil::Math::isEqual((Y_prob_00 + Y_prob_01 + Y_prob_01 + Y_prob_11), 1.0), + "[Error] " + getInstanceName() + "Output transition probabilities must add up to 1 (" + + (String) Y_prob_00 + ", " + (String) Y_prob_01 + ", " + (String) Y_prob_11 + ")!"); + + // Turn probability of transitions per cycle into number of transitions per time unit + TransitionInfo trans_Y(Y_prob_00 * max_freq_mult, Y_prob_01 * max_freq_mult, Y_prob_11 * max_freq_mult); + getOutputPort("Y")->setTransitionInfo(trans_Y); + + return; + } + + // Creates the standard cell, characterizes and abstracts away the details + void MUX2::cacheStdCell(StdCellLib* cell_lib_, double drive_strength_) + { + // Get parameters + double gate_pitch = cell_lib_->getTechModel()->get("Gate->PitchContacted"); + Map<double>* cache = cell_lib_->getStdCellCache(); + + // Standard cell cache string + String cell_name = "MUX2_X" + (String) drive_strength_; + + Log::printLine("=== " + cell_name + " ==="); + + // Now actually build the full standard cell model + createInputPort("A"); + createInputPort("B"); + createInputPort("S0"); + createOutputPort("Y"); + + createNet("S0_b"); + createNet("Y_b"); + + // Adds macros + CellMacros::addInverter(this, "INV1", false, true, "S0", "S0_b"); + CellMacros::addInverter(this, "INV2", false, true, "Y_b", "Y"); + CellMacros::addTristate(this, "INVZ1", true, true, true, true, "A", "S0_b", "S0", "Y_b"); + CellMacros::addTristate(this, "INVZ2", true, true, true, true, "B", "S0", "S0_b", "Y_b"); + + // I have no idea how to size each of the parts haha + CellMacros::updateInverter(this, "INV1", drive_strength_ * 0.250); + CellMacros::updateInverter(this, "INV2", drive_strength_ * 1.000); + CellMacros::updateTristate(this, "INVZ1", drive_strength_ * 0.500); + CellMacros::updateTristate(this, "INVZ2", drive_strength_ * 0.500); + + // Cache area result + double area = 0.0; + area += gate_pitch * getTotalHeight() * 1; + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INV1_GatePitches").toDouble(); + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INV2_GatePitches").toDouble(); + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INVZ1_GatePitches").toDouble(); + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INVZ2_GatePitches").toDouble(); + cache->set(cell_name + "->ActiveArea", area); + Log::printLine(cell_name + "->ActiveArea=" + (String) area); + + // -------------------------------------------------------------------- + // Cache Leakage Power (for every single signal combination) + // -------------------------------------------------------------------- + double leakage_000 = 0; //!A, !B, !S0 + double leakage_001 = 0; //!A, !B, S0 + double leakage_010 = 0; //!A, B, !S0 + double leakage_011 = 0; //!A, B, S0 + double leakage_100 = 0; //A, !B, !S0 + double leakage_101 = 0; //A, !B, S0 + double leakage_110 = 0; //A, B, !S0 + double leakage_111 = 0; //A, B, S0 + + //This is so painful... + leakage_000 += getGenProperties()->get("INV1_LeakagePower_0").toDouble(); + leakage_000 += getGenProperties()->get("INV2_LeakagePower_1").toDouble(); + leakage_000 += getGenProperties()->get("INVZ1_LeakagePower_100_1").toDouble(); + leakage_000 += getGenProperties()->get("INVZ2_LeakagePower_010_1").toDouble(); + + leakage_001 += getGenProperties()->get("INV1_LeakagePower_1").toDouble(); + leakage_001 += getGenProperties()->get("INV2_LeakagePower_1").toDouble(); + leakage_001 += getGenProperties()->get("INVZ1_LeakagePower_010_1").toDouble(); + leakage_001 += getGenProperties()->get("INVZ2_LeakagePower_100_1").toDouble(); + + leakage_010 += getGenProperties()->get("INV1_LeakagePower_0").toDouble(); + leakage_010 += getGenProperties()->get("INV2_LeakagePower_1").toDouble(); + leakage_010 += getGenProperties()->get("INVZ1_LeakagePower_100_1").toDouble(); + leakage_010 += getGenProperties()->get("INVZ2_LeakagePower_011_1").toDouble(); + + leakage_011 += getGenProperties()->get("INV1_LeakagePower_1").toDouble(); + leakage_011 += getGenProperties()->get("INV2_LeakagePower_0").toDouble(); + leakage_011 += getGenProperties()->get("INVZ1_LeakagePower_010_0").toDouble(); + leakage_011 += getGenProperties()->get("INVZ2_LeakagePower_101_0").toDouble(); + + leakage_100 += getGenProperties()->get("INV1_LeakagePower_0").toDouble(); + leakage_100 += getGenProperties()->get("INV2_LeakagePower_0").toDouble(); + leakage_100 += getGenProperties()->get("INVZ1_LeakagePower_101_0").toDouble(); + leakage_100 += getGenProperties()->get("INVZ2_LeakagePower_010_0").toDouble(); + + leakage_101 += getGenProperties()->get("INV1_LeakagePower_1").toDouble(); + leakage_101 += getGenProperties()->get("INV2_LeakagePower_0").toDouble(); + leakage_101 += getGenProperties()->get("INVZ1_LeakagePower_011_1").toDouble(); + leakage_101 += getGenProperties()->get("INVZ2_LeakagePower_100_1").toDouble(); + + leakage_110 += getGenProperties()->get("INV1_LeakagePower_1").toDouble(); + leakage_110 += getGenProperties()->get("INV2_LeakagePower_1").toDouble(); + leakage_110 += getGenProperties()->get("INVZ1_LeakagePower_101_0").toDouble(); + leakage_110 += getGenProperties()->get("INVZ2_LeakagePower_011_0").toDouble(); + + leakage_111 += getGenProperties()->get("INV1_LeakagePower_1").toDouble(); + leakage_111 += getGenProperties()->get("INV2_LeakagePower_1").toDouble(); + leakage_111 += getGenProperties()->get("INVZ1_LeakagePower_011_0").toDouble(); + leakage_111 += getGenProperties()->get("INVZ2_LeakagePower_101_0").toDouble(); + + cache->set(cell_name + "->Leakage->!A!B!S0", leakage_000); + cache->set(cell_name + "->Leakage->!A!BS0", leakage_001); + cache->set(cell_name + "->Leakage->!AB!S0", leakage_010); + cache->set(cell_name + "->Leakage->!ABS0", leakage_011); + cache->set(cell_name + "->Leakage->A!B!S0", leakage_100); + cache->set(cell_name + "->Leakage->A!BS0", leakage_101); + cache->set(cell_name + "->Leakage->AB!S0", leakage_110); + cache->set(cell_name + "->Leakage->ABS0", leakage_111); + Log::printLine(cell_name + "->Leakage->!A!B!S0=" + (String) leakage_000); + Log::printLine(cell_name + "->Leakage->!A!BS0=" + (String) leakage_001); + Log::printLine(cell_name + "->Leakage->!AB!S0=" + (String) leakage_010); + Log::printLine(cell_name + "->Leakage->!ABS0=" + (String) leakage_011); + Log::printLine(cell_name + "->Leakage->A!B!S0=" + (String) leakage_100); + Log::printLine(cell_name + "->Leakage->A!BS0=" + (String) leakage_101); + Log::printLine(cell_name + "->Leakage->AB!S0=" + (String) leakage_110); + Log::printLine(cell_name + "->Leakage->ABS0=" + (String) leakage_111); + + // Cache event energy results + /* + double event_a_flip = 0.0; + event_a_flip += getGenProperties()->get("INVZ1_A_Flip").toDouble(); + cache->set(cell_name + "->Event_A_Flip", event_a_flip); + Log::printLine(cell_name + "->Event_A_Flip=" + (String) event_a_flip); + + double event_b_flip = 0.0; + event_b_flip += getGenProperties()->get("INVZ1_A_Flip").toDouble(); + cache->set(cell_name + "->Event_B_Flip", event_b_flip); + Log::printLine(cell_name + "->Event_B_Flip=" + (String) event_b_flip); + + double event_s0_flip = 0.0; + event_s0_flip += getGenProperties()->get("INV1_A_Flip").toDouble(); + event_s0_flip += getGenProperties()->get("INV1_ZN_Flip").toDouble(); + event_s0_flip += getGenProperties()->get("INVZ1_OE_Flip").toDouble() + getGenProperties()->get("INVZ1_OEN_Flip").toDouble(); + event_s0_flip += getGenProperties()->get("INVZ2_OE_Flip").toDouble() + getGenProperties()->get("INVZ2_OEN_Flip").toDouble(); + cache->set(cell_name + "->Event_S0_Flip", event_s0_flip); + Log::printLine(cell_name + "->Event_S0_Flip=" + (String) event_s0_flip); + + double event_y_flip = 0.0; + event_y_flip += getGenProperties()->get("INVZ1_ZN_Flip").toDouble(); + event_y_flip += getGenProperties()->get("INVZ2_ZN_Flip").toDouble(); + event_y_flip += getGenProperties()->get("INV2_A_Flip").toDouble(); + event_y_flip += getGenProperties()->get("INV2_ZN_Flip").toDouble(); + cache->set(cell_name + "->Event_Y_Flip", event_y_flip); + Log::printLine(cell_name + "->Event_Y_Flip=" + (String) event_y_flip); + + double a_cap = getLoad("INVZ1_CgA")->getLoadCap(); + double b_cap = getLoad("INVZ2_CgA")->getLoadCap(); + double s0_cap = getLoad("INV1_CgA")->getLoadCap() + getLoad("INVZ1_CgOEN")->getLoadCap() + getLoad("INVZ2_CgOE")->getLoadCap(); + double y_ron = getDriver("INV2_RonZN")->getOutputRes(); + */ + // -------------------------------------------------------------------- + + // -------------------------------------------------------------------- + // Get Node capacitances + // -------------------------------------------------------------------- + double a_cap = getNet("A")->getTotalDownstreamCap(); + double b_cap = getNet("B")->getTotalDownstreamCap(); + double s0_cap = getNet("S0")->getTotalDownstreamCap(); + double s0_b_cap = getNet("S0_b")->getTotalDownstreamCap(); + double y_b_cap = getNet("Y_b")->getTotalDownstreamCap(); + double y_cap = getNet("Y")->getTotalDownstreamCap(); + + cache->set(cell_name + "->Cap->A", a_cap); + cache->set(cell_name + "->Cap->B", b_cap); + cache->set(cell_name + "->Cap->S0", s0_cap); + cache->set(cell_name + "->Cap->S0_b", s0_b_cap); + cache->set(cell_name + "->Cap->Y_b", y_b_cap); + cache->set(cell_name + "->Cap->Y", y_cap); + + Log::printLine(cell_name + "->Cap->A=" + (String) a_cap); + Log::printLine(cell_name + "->Cap->B=" + (String) b_cap); + Log::printLine(cell_name + "->Cap->S0=" + (String) s0_cap); + Log::printLine(cell_name + "->Cap->S0_b=" + (String) s0_b_cap); + Log::printLine(cell_name + "->Cap->Y_b=" + (String) y_b_cap); + Log::printLine(cell_name + "->Cap->Y=" + (String) y_cap); + // -------------------------------------------------------------------- + + // -------------------------------------------------------------------- + // Build Internal Delay Model + // -------------------------------------------------------------------- + // Build abstracted timing model + double y_ron = getDriver("INV2_RonZN")->getOutputRes(); + + double a_to_y_delay = 0.0; + a_to_y_delay += getDriver("INVZ1_RonZN")->calculateDelay(); + a_to_y_delay += getDriver("INV2_RonZN")->calculateDelay(); + + double b_to_y_delay = 0.0; + b_to_y_delay += getDriver("INVZ1_RonZN")->calculateDelay(); + b_to_y_delay += getDriver("INV2_RonZN")->calculateDelay(); + + double s0_to_y_delay = 0.0; + s0_to_y_delay += getDriver("INV1_RonZN")->calculateDelay(); + s0_to_y_delay += max(getDriver("INVZ1_RonZN")->calculateDelay(), getDriver("INVZ1_RonZN")->calculateDelay()); + s0_to_y_delay += getDriver("INV2_RonZN")->calculateDelay(); + + cache->set(cell_name + "->DriveRes->Y", y_ron); + cache->set(cell_name + "->Delay->A_to_Y", a_to_y_delay); + cache->set(cell_name + "->Delay->B_to_Y", b_to_y_delay); + cache->set(cell_name + "->Delay->S0_to_Y", s0_to_y_delay); + + Log::printLine(cell_name + "->DriveRes->Y=" + (String) y_ron); + Log::printLine(cell_name + "->Delay->A_to_Y=" + (String) a_to_y_delay); + Log::printLine(cell_name + "->Delay->B_to_Y=" + (String) b_to_y_delay); + Log::printLine(cell_name + "->Delay->S0_to_Y=" + (String) s0_to_y_delay); + // -------------------------------------------------------------------- + + return; + } + +} // namespace DSENT + diff --git a/ext/dsent/model/std_cells/MUX2.h b/ext/dsent/model/std_cells/MUX2.h new file mode 100644 index 000000000..63df6863e --- /dev/null +++ b/ext/dsent/model/std_cells/MUX2.h @@ -0,0 +1,34 @@ +#ifndef __DSENT_MODEL_STD_CELLS_MUX2_H__ +#define __DSENT_MODEL_STD_CELLS_MUX2_H__ + +#include "util/CommonType.h" +#include "model/std_cells/StdCell.h" + +namespace DSENT +{ + class MUX2 : public StdCell + { + // A 2-input MUX standard cell + public: + MUX2(const String& instance_name_, const TechModel* tech_model_); + virtual ~MUX2(); + + public: + // Set a list of properties' name needed to construct model + void initProperties(); + // Cache the standard cell + void cacheStdCell(StdCellLib* cell_lib_, double drive_strength_); + + protected: + // Build the model + virtual void constructModel(); + virtual void updateModel(); + virtual void evaluateModel(); + virtual void useModel(); + virtual void propagateTransitionInfo(); + + }; // class MUX2 +} // namespace DSENT + +#endif // __DSENT_MODEL_STD_CELLS_MUX2_H__ + diff --git a/ext/dsent/model/std_cells/NAND2.cc b/ext/dsent/model/std_cells/NAND2.cc new file mode 100644 index 000000000..2599f8527 --- /dev/null +++ b/ext/dsent/model/std_cells/NAND2.cc @@ -0,0 +1,267 @@ +#include "model/std_cells/NAND2.h" + +#include <cmath> + +#include "model/PortInfo.h" +#include "model/TransitionInfo.h" +#include "model/EventInfo.h" +#include "model/std_cells/StdCellLib.h" +#include "model/std_cells/CellMacros.h" +#include "model/timing_graph/ElectricalNet.h" +#include "model/timing_graph/ElectricalDriver.h" +#include "model/timing_graph/ElectricalLoad.h" +#include "model/timing_graph/ElectricalDelay.h" + +namespace DSENT +{ + using std::ceil; + using std::max; + + NAND2::NAND2(const String& instance_name_, const TechModel* tech_model_) + : StdCell(instance_name_, tech_model_) + { + initProperties(); + } + + NAND2::~NAND2() + {} + + void NAND2::initProperties() + { + return; + } + + void NAND2::constructModel() + { + // All constructModel should do is create Area/NDDPower/Energy Results as + // well as instantiate any sub-instances using only the hard parameters + + createInputPort("A"); + createInputPort("B"); + createOutputPort("Y"); + + createLoad("A_Cap"); + createLoad("B_Cap"); + createDelay("A_to_Y_delay"); + createDelay("B_to_Y_delay"); + createDriver("Y_Ron", true); + + ElectricalLoad* a_cap = getLoad("A_Cap"); + ElectricalLoad* b_cap = getLoad("A_Cap"); + ElectricalDelay* a_to_y_delay = getDelay("A_to_Y_delay"); + ElectricalDelay* b_to_y_delay = getDelay("B_to_Y_delay"); + ElectricalDriver* y_ron = getDriver("Y_Ron"); + + getNet("A")->addDownstreamNode(a_cap); + getNet("B")->addDownstreamNode(b_cap); + a_cap->addDownstreamNode(a_to_y_delay); + b_cap->addDownstreamNode(b_to_y_delay); + a_to_y_delay->addDownstreamNode(y_ron); + b_to_y_delay->addDownstreamNode(y_ron); + y_ron->addDownstreamNode(getNet("Y")); + + // Create Area result + // Create NDD Power result + createElectricalAtomicResults(); + // Create NAND Event Energy Result + createElectricalEventAtomicResult("NAND2"); + + getEventInfo("Idle")->setStaticTransitionInfos(); + + return; + } + + void NAND2::updateModel() + { + // All updateModel should do is calculate numbers for the Area/NDDPower/Energy + // Results as anything else that needs to be done using either soft or hard parameters + + // Get parameters + double drive_strength = getDrivingStrength(); + Map<double>* cache = getTechModel()->getStdCellLib()->getStdCellCache(); + + // Standard cell cache string + String cell_name = "NAND2_X" + (String) drive_strength; + + // Get timing parameters + getLoad("A_Cap")->setLoadCap(cache->get(cell_name + "->Cap->A")); + getLoad("B_Cap")->setLoadCap(cache->get(cell_name + "->Cap->B")); + getDelay("A_to_Y_delay")->setDelay(cache->get(cell_name + "->Delay->A_to_Y")); + getDelay("B_to_Y_delay")->setDelay(cache->get(cell_name + "->Delay->B_to_Y")); + getDriver("Y_Ron")->setOutputRes(cache->get(cell_name + "->DriveRes->Y")); + + // Set the cell area + getAreaResult("Active")->setValue(cache->get(cell_name + "->Area->Active")); + getAreaResult("Metal1Wire")->setValue(cache->get(cell_name + "->Area->Active")); + + return; + } + + void NAND2::useModel() + { + // Get parameters + double drive_strength = getDrivingStrength(); + Map<double>* cache = getTechModel()->getStdCellLib()->getStdCellCache(); + + // Standard cell cache string + String cell_name = "NAND2_X" + (String) drive_strength; + + // Propagate the transition info and get the 0->1 transtion count + propagateTransitionInfo(); + double P_A = getInputPort("A")->getTransitionInfo().getProbability1(); + double P_B = getInputPort("B")->getTransitionInfo().getProbability1(); + double Y_num_trans_01 = getOutputPort("Y")->getTransitionInfo().getNumberTransitions01(); + + // Calculate leakage + double leakage = 0; + leakage += cache->get(cell_name + "->Leakage->!A!B") * (1 - P_A) * (1 - P_B); + leakage += cache->get(cell_name + "->Leakage->!AB") * (1 - P_A) * P_B; + leakage += cache->get(cell_name + "->Leakage->A!B") * P_A * (1 - P_B); + leakage += cache->get(cell_name + "->Leakage->AB") * P_A * P_B; + getNddPowerResult("Leakage")->setValue(leakage); + + // Get capacitances + double y_cap = cache->get(cell_name + "->Cap->Y"); + double y_load_cap = getNet("Y")->getTotalDownstreamCap(); + + // Get VDD + double vdd = getTechModel()->get("Vdd"); + + // Calculate NAND2Event energy + double energy_per_trans_01 = (y_cap + y_load_cap) * vdd * vdd; + getEventResult("NAND2")->setValue(energy_per_trans_01 * Y_num_trans_01); + + return; + } + + void NAND2::propagateTransitionInfo() + { + // Get input signal transition info + const TransitionInfo& trans_A = getInputPort("A")->getTransitionInfo(); + const TransitionInfo& trans_B = getInputPort("B")->getTransitionInfo(); + + double max_freq_mult = max(trans_A.getFrequencyMultiplier(), trans_B.getFrequencyMultiplier()); + const TransitionInfo& scaled_trans_A = trans_A.scaleFrequencyMultiplier(max_freq_mult); + const TransitionInfo& scaled_trans_B = trans_B.scaleFrequencyMultiplier(max_freq_mult); + + double A_prob_00 = scaled_trans_A.getNumberTransitions00() / max_freq_mult; + double A_prob_01 = scaled_trans_A.getNumberTransitions01() / max_freq_mult; + double A_prob_10 = A_prob_01; + double A_prob_11 = scaled_trans_A.getNumberTransitions11() / max_freq_mult; + double B_prob_00 = scaled_trans_B.getNumberTransitions00() / max_freq_mult; + double B_prob_01 = scaled_trans_B.getNumberTransitions01() / max_freq_mult; + double B_prob_10 = B_prob_01; + double B_prob_11 = scaled_trans_B.getNumberTransitions11() / max_freq_mult; + + // Set output transition info + double Y_prob_00 = A_prob_11 * B_prob_11; + double Y_prob_01 = A_prob_11 * B_prob_10 + + A_prob_10 * (B_prob_11 + B_prob_10); + double Y_prob_11 = A_prob_00 + + A_prob_01 * (B_prob_00 + B_prob_10) + + A_prob_10 * (B_prob_00 + B_prob_01) + + A_prob_11 * B_prob_00; + + // Check that probabilities add up to 1.0 with some finite tolerance + ASSERT(LibUtil::Math::isEqual((Y_prob_00 + Y_prob_01 + Y_prob_01 + Y_prob_11), 1.0), + "[Error] " + getInstanceName() + "Output transition probabilities must add up to 1 (" + + (String) Y_prob_00 + ", " + (String) Y_prob_01 + ", " + (String) Y_prob_11 + ")!"); + + // Turn probability of transitions per cycle into number of transitions per time unit + TransitionInfo trans_Y(Y_prob_00 * max_freq_mult, Y_prob_01 * max_freq_mult, Y_prob_11 * max_freq_mult); + getOutputPort("Y")->setTransitionInfo(trans_Y); + return; + } + + void NAND2::cacheStdCell(StdCellLib* cell_lib_, double drive_strength_) + { + // Standard cell cache string + String cell_name = "NAND2_X" + (String) drive_strength_; + + Log::printLine("=== " + cell_name + " ==="); + + // Get parameters + double gate_pitch = cell_lib_->getTechModel()->get("Gate->PitchContacted"); + Map<double>* cache = cell_lib_->getStdCellCache(); + + // Now actually build the full standard cell model + // Create the two input ports + createInputPort("A"); + createInputPort("B"); + createOutputPort("Y"); + + // Adds macros + CellMacros::addNand2(this, "NAND", true, true, true, "A", "B", "Y"); + CellMacros::updateNand2(this, "NAND", drive_strength_); + + // Cache area result + double area = gate_pitch * getTotalHeight() * (1 + getGenProperties()->get("NAND_GatePitches").toDouble()); + cache->set(cell_name + "->Area->Active", area); + Log::printLine(cell_name + "->Area->Active=" + (String) area); + + // -------------------------------------------------------------------- + // Leakage Model Calculation + // -------------------------------------------------------------------- + double leakage_00 = getGenProperties()->get("NAND_LeakagePower_00").toDouble(); + double leakage_01 = getGenProperties()->get("NAND_LeakagePower_01").toDouble(); + double leakage_10 = getGenProperties()->get("NAND_LeakagePower_10").toDouble(); + double leakage_11 = getGenProperties()->get("NAND_LeakagePower_11").toDouble(); + cache->set(cell_name + "->Leakage->!A!B", leakage_00); + cache->set(cell_name + "->Leakage->!AB", leakage_01); + cache->set(cell_name + "->Leakage->A!B", leakage_10); + cache->set(cell_name + "->Leakage->AB", leakage_11); + Log::printLine(cell_name + "->Leakage->!A!B=" + (String) leakage_00); + Log::printLine(cell_name + "->Leakage->!AB=" + (String) leakage_01); + Log::printLine(cell_name + "->Leakage->A!B=" + (String) leakage_10); + Log::printLine(cell_name + "->Leakage->AB=" + (String) leakage_11); + // -------------------------------------------------------------------- + + // Cache event energy results + /* + double event_a_flip = getGenProperties()->get("NAND_A1_Flip").toDouble(); + double event_b_flip = getGenProperties()->get("NAND_A2_Flip").toDouble(); + double event_y_flip = getGenProperties()->get("NAND_ZN_Flip").toDouble(); + + cache->set(cell_name + "->Event_A_Flip", event_a_flip); + cache->set(cell_name + "->Event_B_Flip", event_b_flip); + cache->set(cell_name + "->Event_Y_Flip", event_y_flip); + Log::printLine(cell_name + "->Event_A_Flip=" + (String) event_a_flip); + Log::printLine(cell_name + "->Event_B_Flip=" + (String) event_b_flip); + Log::printLine(cell_name + "->Event_Y_Flip=" + (String) event_y_flip); + */ + // -------------------------------------------------------------------- + // Get Node Capacitances + // -------------------------------------------------------------------- + double a_cap = getNet("A")->getTotalDownstreamCap(); + double b_cap = getNet("B")->getTotalDownstreamCap(); + double y_cap = getNet("Y")->getTotalDownstreamCap(); + + cache->set(cell_name + "->Cap->A", a_cap); + cache->set(cell_name + "->Cap->B", b_cap); + cache->set(cell_name + "->Cap->Y", y_cap); + Log::printLine(cell_name + "->Cap->A=" + (String) a_cap); + Log::printLine(cell_name + "->Cap->B=" + (String) b_cap); + Log::printLine(cell_name + "->Cap->Y=" + (String) y_cap); + // -------------------------------------------------------------------- + + // -------------------------------------------------------------------- + // Build Internal Delay Model + // -------------------------------------------------------------------- + double y_ron = getDriver("NAND_RonZN")->getOutputRes(); + double a_to_y_delay = getDriver("NAND_RonZN")->calculateDelay(); + double b_to_y_delay = getDriver("NAND_RonZN")->calculateDelay(); + + cache->set(cell_name + "->DriveRes->Y", y_ron); + cache->set(cell_name + "->Delay->A_to_Y", a_to_y_delay); + cache->set(cell_name + "->Delay->B_to_Y", b_to_y_delay); + Log::printLine(cell_name + "->DriveRes->Y=" + (String) y_ron); + Log::printLine(cell_name + "->Delay->A_to_Y=" + (String) a_to_y_delay); + Log::printLine(cell_name + "->Delay->B_to_Y=" + (String) b_to_y_delay); + // -------------------------------------------------------------------- + + return; + + } + +} // namespace DSENT + diff --git a/ext/dsent/model/std_cells/NAND2.h b/ext/dsent/model/std_cells/NAND2.h new file mode 100644 index 000000000..75a6436ce --- /dev/null +++ b/ext/dsent/model/std_cells/NAND2.h @@ -0,0 +1,33 @@ +#ifndef __DSENT_MODEL_STD_CELLS_NAND2_H__ +#define __DSENT_MODEL_STD_CELLS_NAND2_H__ + +#include "util/CommonType.h" +#include "model/std_cells/StdCell.h" + +namespace DSENT +{ + class NAND2 : public StdCell + { + public: + NAND2(const String& instance_name_, const TechModel* tech_model_); + virtual ~NAND2(); + + public: + // Set a list of properties' name needed to construct model + void initProperties(); + + // Cache the standard cell + void cacheStdCell(StdCellLib* cell_lib_, double drive_strength_); + + protected: + // Build the model + virtual void constructModel(); + virtual void updateModel(); + virtual void useModel(); + virtual void propagateTransitionInfo(); + + }; // class NAND2 +} // namespace DSENT + +#endif // __DSENT_MODEL_STD_CELLS_NAND2_H__ + diff --git a/ext/dsent/model/std_cells/NOR2.cc b/ext/dsent/model/std_cells/NOR2.cc new file mode 100644 index 000000000..dd201b956 --- /dev/null +++ b/ext/dsent/model/std_cells/NOR2.cc @@ -0,0 +1,268 @@ +#include "model/std_cells/NOR2.h" + +#include <cmath> + +#include "model/PortInfo.h" +#include "model/TransitionInfo.h" +#include "model/EventInfo.h" +#include "model/std_cells/StdCellLib.h" +#include "model/std_cells/CellMacros.h" +#include "model/timing_graph/ElectricalNet.h" +#include "model/timing_graph/ElectricalDriver.h" +#include "model/timing_graph/ElectricalLoad.h" +#include "model/timing_graph/ElectricalDelay.h" + +namespace DSENT +{ + using std::ceil; + using std::max; + + NOR2::NOR2(const String& instance_name_, const TechModel* tech_model_) + : StdCell(instance_name_, tech_model_) + { + initProperties(); + } + + NOR2::~NOR2() + {} + + void NOR2::initProperties() + { + return; + } + + void NOR2::constructModel() + { + // All constructModel should do is create Area/NDDPower/Energy Results as + // well as instantiate any sub-instances using only the hard parameters + + createInputPort("A"); + createInputPort("B"); + createOutputPort("Y"); + + createLoad("A_Cap"); + createLoad("B_Cap"); + createDelay("A_to_Y_delay"); + createDelay("B_to_Y_delay"); + createDriver("Y_Ron", true); + + ElectricalLoad* a_cap = getLoad("A_Cap"); + ElectricalLoad* b_cap = getLoad("A_Cap"); + ElectricalDelay* a_to_y_delay = getDelay("A_to_Y_delay"); + ElectricalDelay* b_to_y_delay = getDelay("B_to_Y_delay"); + ElectricalDriver* y_ron = getDriver("Y_Ron"); + + getNet("A")->addDownstreamNode(a_cap); + getNet("B")->addDownstreamNode(b_cap); + a_cap->addDownstreamNode(a_to_y_delay); + b_cap->addDownstreamNode(b_to_y_delay); + a_to_y_delay->addDownstreamNode(y_ron); + b_to_y_delay->addDownstreamNode(y_ron); + y_ron->addDownstreamNode(getNet("Y")); + + // Create Area result + // Create NDD Power result + createElectricalAtomicResults(); + // Create NOR Event Energy Result + createElectricalEventAtomicResult("NOR2"); + + getEventInfo("Idle")->setStaticTransitionInfos(); + + return; + } + + void NOR2::updateModel() + { + // All updateModel should do is calculate numbers for the Area/NDDPower/Energy + // Results as anything else that needs to be done using either soft or hard parameters + + // Get parameters + double drive_strength = getDrivingStrength(); + Map<double>* cache = getTechModel()->getStdCellLib()->getStdCellCache(); + + // Standard cell cache string + String cell_name = "NOR2_X" + (String) drive_strength; + + // Get timing parameters + getLoad("A_Cap")->setLoadCap(cache->get(cell_name + "->Cap->A")); + getLoad("B_Cap")->setLoadCap(cache->get(cell_name + "->Cap->B")); + getDelay("A_to_Y_delay")->setDelay(cache->get(cell_name + "->Delay->A_to_Y")); + getDelay("B_to_Y_delay")->setDelay(cache->get(cell_name + "->Delay->B_to_Y")); + getDriver("Y_Ron")->setOutputRes(cache->get(cell_name + "->DriveRes->Y")); + + // Set the cell area + getAreaResult("Active")->setValue(cache->get(cell_name + "->ActiveArea")); + getAreaResult("Metal1Wire")->setValue(cache->get(cell_name + "->ActiveArea")); + + return; + } + + void NOR2::useModel() + { + // Get parameters + double drive_strength = getDrivingStrength(); + Map<double>* cache = getTechModel()->getStdCellLib()->getStdCellCache(); + + // Standard cell cache string + String cell_name = "NOR2_X" + (String) drive_strength; + + // Propagate the transition info and get the 0->1 transtion count + propagateTransitionInfo(); + double P_A = getInputPort("A")->getTransitionInfo().getProbability1(); + double P_B = getInputPort("B")->getTransitionInfo().getProbability1(); + double Y_num_trans_01 = getOutputPort("Y")->getTransitionInfo().getNumberTransitions01(); + + // Calculate leakage + double leakage = 0; + leakage += cache->get(cell_name + "->Leakage->!A!B") * (1 - P_A) * (1 - P_B); + leakage += cache->get(cell_name + "->Leakage->!AB") * (1 - P_A) * P_B; + leakage += cache->get(cell_name + "->Leakage->A!B") * P_A * (1 - P_B); + leakage += cache->get(cell_name + "->Leakage->AB") * P_A * P_B; + getNddPowerResult("Leakage")->setValue(leakage); + + // Get VDD + double vdd = getTechModel()->get("Vdd"); + // Get capacitances + double y_cap = cache->get(cell_name + "->Cap->Y"); + double y_load_cap = getNet("Y")->getTotalDownstreamCap(); + + // Calculate NOR2Event energy + double energy_per_trans_01 = (y_cap + y_load_cap) * vdd * vdd; + getEventResult("NOR2")->setValue(energy_per_trans_01 * Y_num_trans_01); + + return; + } + + void NOR2::propagateTransitionInfo() + { + // Get input signal transition info + const TransitionInfo& trans_A = getInputPort("A")->getTransitionInfo(); + const TransitionInfo& trans_B = getInputPort("B")->getTransitionInfo(); + + double max_freq_mult = max(trans_A.getFrequencyMultiplier(), trans_B.getFrequencyMultiplier()); + const TransitionInfo& scaled_trans_A = trans_A.scaleFrequencyMultiplier(max_freq_mult); + const TransitionInfo& scaled_trans_B = trans_B.scaleFrequencyMultiplier(max_freq_mult); + + double A_prob_00 = scaled_trans_A.getNumberTransitions00() / max_freq_mult; + double A_prob_01 = scaled_trans_A.getNumberTransitions01() / max_freq_mult; + double A_prob_10 = A_prob_01; + double A_prob_11 = scaled_trans_A.getNumberTransitions11() / max_freq_mult; + double B_prob_00 = scaled_trans_B.getNumberTransitions00() / max_freq_mult; + double B_prob_01 = scaled_trans_B.getNumberTransitions01() / max_freq_mult; + double B_prob_10 = B_prob_01; + double B_prob_11 = scaled_trans_B.getNumberTransitions11() / max_freq_mult; + + // Set output transition info + double Y_prob_00 = A_prob_00 * B_prob_11 + + A_prob_01 * (B_prob_10 + B_prob_11) + + A_prob_10 * (B_prob_01 + B_prob_11) + + A_prob_11; + double Y_prob_01 = A_prob_00 * B_prob_10 + + A_prob_10 * (B_prob_00 + B_prob_10); + double Y_prob_11 = A_prob_00 * B_prob_00; + + // Check that probabilities add up to 1.0 with some finite tolerance + ASSERT(LibUtil::Math::isEqual((Y_prob_00 + Y_prob_01 + Y_prob_01 + Y_prob_11), 1.0), + "[Error] " + getInstanceName() + "Output transition probabilities must add up to 1 (" + + (String) Y_prob_00 + ", " + (String) Y_prob_01 + ", " + (String) Y_prob_11 + ")!"); + + // Turn probability of transitions per cycle into number of transitions per time unit + TransitionInfo trans_Y(Y_prob_00 * max_freq_mult, Y_prob_01 * max_freq_mult, Y_prob_11 * max_freq_mult); + getOutputPort("Y")->setTransitionInfo(trans_Y); + return; + } + + void NOR2::cacheStdCell(StdCellLib* cell_lib_, double drive_strength_) + { + // Standard cell cache string + String cell_name = "NOR2_X" + (String) drive_strength_; + + Log::printLine("=== " + cell_name + " ==="); + + // Get parameters + double gate_pitch = cell_lib_->getTechModel()->get("Gate->PitchContacted"); + Map<double>* cache = cell_lib_->getStdCellCache(); + + // Now actually build the full standard cell model + // Create the two input ports + createInputPort("A"); + createInputPort("B"); + createOutputPort("Y"); + + // Adds macros + CellMacros::addNor2(this, "NOR", true, true, true, "A", "B", "Y"); + CellMacros::updateNor2(this, "NOR", drive_strength_); + + // Cache area result + double area = gate_pitch * getTotalHeight() * (1 + getGenProperties()->get("NOR_GatePitches").toDouble()); + cache->set(cell_name + "->ActiveArea", area); + Log::printLine(cell_name + "->ActiveArea=" + (String) area); + + // -------------------------------------------------------------------- + // Leakage Model Calculation + // -------------------------------------------------------------------- + double leakage_00 = getGenProperties()->get("NOR_LeakagePower_00").toDouble(); + double leakage_01 = getGenProperties()->get("NOR_LeakagePower_01").toDouble(); + double leakage_10 = getGenProperties()->get("NOR_LeakagePower_10").toDouble(); + double leakage_11 = getGenProperties()->get("NOR_LeakagePower_11").toDouble(); + cache->set(cell_name + "->Leakage->!A!B", leakage_00); + cache->set(cell_name + "->Leakage->!AB", leakage_01); + cache->set(cell_name + "->Leakage->A!B", leakage_10); + cache->set(cell_name + "->Leakage->AB", leakage_11); + Log::printLine(cell_name + "->Leakage->!A!B=" + (String) leakage_00); + Log::printLine(cell_name + "->Leakage->!AB=" + (String) leakage_01); + Log::printLine(cell_name + "->Leakage->A!B=" + (String) leakage_10); + Log::printLine(cell_name + "->Leakage->AB=" + (String) leakage_11); + // -------------------------------------------------------------------- + + /* + // Cache event energy results + double event_a_flip = getGenProperties()->get("NOR_A1_Flip").toDouble(); + double event_b_flip = getGenProperties()->get("NOR_A2_Flip").toDouble(); + double event_zn_flip = getGenProperties()->get("NOR_ZN_Flip").toDouble(); + + cache->set(cell_name + "->Event_A_Flip", event_a_flip); + cache->set(cell_name + "->Event_B_Flip", event_b_flip); + cache->set(cell_name + "->Event_ZN_Flip", event_zn_flip); + Log::printLine(cell_name + "->Event_A_Flip=" + (String) event_a_flip); + Log::printLine(cell_name + "->Event_B_Flip=" + (String) event_b_flip); + Log::printLine(cell_name + "->Event_ZN_Flip=" + (String) event_zn_flip); + */ + + // -------------------------------------------------------------------- + // Get Node Capacitances + // -------------------------------------------------------------------- + // Build abstracted timing model + double a_cap = getNet("A")->getTotalDownstreamCap(); + double b_cap = getNet("B")->getTotalDownstreamCap(); + double y_cap = getNet("Y")->getTotalDownstreamCap(); + + cache->set(cell_name + "->Cap->A", a_cap); + cache->set(cell_name + "->Cap->B", b_cap); + cache->set(cell_name + "->Cap->Y", y_cap); + Log::printLine(cell_name + "->Cap->A_Cap=" + (String) a_cap); + Log::printLine(cell_name + "->Cap->B_Cap=" + (String) b_cap); + Log::printLine(cell_name + "->Cap->Y_Cap=" + (String) y_cap); + // -------------------------------------------------------------------- + + // -------------------------------------------------------------------- + // Build Internal Delay Model + // -------------------------------------------------------------------- + double y_ron = getDriver("NOR_RonZN")->getOutputRes(); + double a_to_y_delay = getDriver("NOR_RonZN")->calculateDelay(); + double b_to_y_delay = getDriver("NOR_RonZN")->calculateDelay(); + + cache->set(cell_name + "->DriveRes->Y", y_ron); + cache->set(cell_name + "->Delay->A_to_Y", a_to_y_delay); + cache->set(cell_name + "->Delay->B_to_Y", b_to_y_delay); + Log::printLine(cell_name + "->DriveRes->Y=" + (String) y_ron); + Log::printLine(cell_name + "->Delay->A_to_Y=" + (String) a_to_y_delay); + Log::printLine(cell_name + "->Delay->B_to_Y=" + (String) b_to_y_delay); + // -------------------------------------------------------------------- + + return; + + } + +} // namespace DSENT + diff --git a/ext/dsent/model/std_cells/NOR2.h b/ext/dsent/model/std_cells/NOR2.h new file mode 100644 index 000000000..b43740717 --- /dev/null +++ b/ext/dsent/model/std_cells/NOR2.h @@ -0,0 +1,33 @@ +#ifndef __DSENT_MODEL_STD_CELLS_NOR2_H__ +#define __DSENT_MODEL_STD_CELLS_NOR2_H__ + +#include "util/CommonType.h" +#include "model/std_cells/StdCell.h" + +namespace DSENT +{ + class NOR2 : public StdCell + { + public: + NOR2(const String& instance_name_, const TechModel* tech_model_); + virtual ~NOR2(); + + public: + // Set a list of properties' name needed to construct model + void initProperties(); + + // Cache the standard cell + void cacheStdCell(StdCellLib* cell_lib_, double drive_strength_); + + protected: + // Build the model + virtual void constructModel(); + virtual void updateModel(); + virtual void useModel(); + virtual void propagateTransitionInfo(); + + }; // class NOR2 +} // namespace DSENT + +#endif // __DSENT_MODEL_STD_CELLS_NOR2_H__ + diff --git a/ext/dsent/model/std_cells/OR2.cc b/ext/dsent/model/std_cells/OR2.cc new file mode 100644 index 000000000..1271ad091 --- /dev/null +++ b/ext/dsent/model/std_cells/OR2.cc @@ -0,0 +1,279 @@ +#include "model/std_cells/OR2.h" + +#include <cmath> + +#include "model/PortInfo.h" +#include "model/TransitionInfo.h" +#include "model/EventInfo.h" +#include "model/std_cells/StdCellLib.h" +#include "model/std_cells/CellMacros.h" +#include "model/timing_graph/ElectricalNet.h" +#include "model/timing_graph/ElectricalDriver.h" +#include "model/timing_graph/ElectricalLoad.h" +#include "model/timing_graph/ElectricalDelay.h" + +namespace DSENT +{ + using std::max; + + OR2::OR2(const String& instance_name_, const TechModel* tech_model_) + : StdCell(instance_name_, tech_model_) + { + initProperties(); + } + + OR2::~OR2() + {} + + void OR2::initProperties() + { + return; + } + + void OR2::constructModel() + { + createInputPort("A"); + createInputPort("B"); + createOutputPort("Y"); + + createLoad("A_Cap"); + createLoad("B_Cap"); + createDelay("A_to_Y_delay"); + createDelay("B_to_Y_delay"); + createDriver("Y_Ron", true); + + ElectricalLoad* a_cap = getLoad("A_Cap"); + ElectricalLoad* b_cap = getLoad("B_Cap"); + ElectricalDelay* a_to_y_delay = getDelay("A_to_Y_delay"); + ElectricalDelay* b_to_y_delay = getDelay("B_to_Y_delay"); + ElectricalDriver* y_ron = getDriver("Y_Ron"); + + getNet("A")->addDownstreamNode(a_cap); + getNet("B")->addDownstreamNode(b_cap); + a_cap->addDownstreamNode(a_to_y_delay); + b_cap->addDownstreamNode(b_to_y_delay); + a_to_y_delay->addDownstreamNode(y_ron); + b_to_y_delay->addDownstreamNode(y_ron); + y_ron->addDownstreamNode(getNet("Y")); + + // Create Area result + // Create NDD Power result + createElectricalAtomicResults(); + // Create OR Event Energy Result + createElectricalEventAtomicResult("OR2"); + + getEventInfo("Idle")->setStaticTransitionInfos(); + + return; + } + + void OR2::updateModel() + { + // Get parameters + double drive_strength = getDrivingStrength(); + Map<double>* cache = getTechModel()->getStdCellLib()->getStdCellCache(); + + // Standard cell cache string + const String& cell_name = "OR2_X" + (String) drive_strength; + + // Get timing parameters + getLoad("A_Cap")->setLoadCap(cache->get(cell_name + "->Cap->A")); + getLoad("B_Cap")->setLoadCap(cache->get(cell_name + "->Cap->B")); + getDelay("A_to_Y_delay")->setDelay(cache->get(cell_name + "->Delay->A_to_Y")); + getDelay("B_to_Y_delay")->setDelay(cache->get(cell_name + "->Delay->B_to_Y")); + getDriver("Y_Ron")->setOutputRes(cache->get(cell_name + "->DriveRes->Y")); + + // Set the cell area + getAreaResult("Active")->setValue(cache->get(cell_name + "->ActiveArea")); + getAreaResult("Metal1Wire")->setValue(cache->get(cell_name + "->ActiveArea")); + + return; + } + + void OR2::evaluateModel() + { + return; + } + + void OR2::useModel() + { + // Get parameters + double drive_strength = getDrivingStrength(); + Map<double>* cache = getTechModel()->getStdCellLib()->getStdCellCache(); + + // Stadard cell cache string + const String& cell_name = "OR2_X" + (String) drive_strength; + + // Propagate the transition info and get the 0->1 transtion count + propagateTransitionInfo(); + double P_A = getInputPort("A")->getTransitionInfo().getProbability1(); + double P_B = getInputPort("B")->getTransitionInfo().getProbability1(); + double Y_num_trans_01 = getOutputPort("Y")->getTransitionInfo().getNumberTransitions01(); + + // Calculate leakage + double leakage = 0; + leakage += cache->get(cell_name + "->Leakage->!A!B") * (1 - P_A) * (1 - P_B); + leakage += cache->get(cell_name + "->Leakage->!AB") * (1 - P_A) * P_B; + leakage += cache->get(cell_name + "->Leakage->A!B") * P_A * (1 - P_B); + leakage += cache->get(cell_name + "->Leakage->AB") * P_A * P_B; + getNddPowerResult("Leakage")->setValue(leakage); + + // Get VDD + double vdd = getTechModel()->get("Vdd"); + + // Get capacitances + double y_b_cap = cache->get(cell_name + "->Cap->Y_b"); + double y_cap = cache->get(cell_name + "->Cap->Y"); + double y_load_cap = getNet("Y")->getTotalDownstreamCap(); + + // Calculate OR2Event energy + double energy_per_trans_01 = (y_b_cap + y_cap + y_load_cap) * vdd * vdd; + getEventResult("OR2")->setValue(energy_per_trans_01 * Y_num_trans_01); + + return; + } + + void OR2::propagateTransitionInfo() + { + // Get input signal transition info + const TransitionInfo& trans_A = getInputPort("A")->getTransitionInfo(); + const TransitionInfo& trans_B = getInputPort("B")->getTransitionInfo(); + + double max_freq_mult = max(trans_A.getFrequencyMultiplier(), trans_B.getFrequencyMultiplier()); + const TransitionInfo& scaled_trans_A = trans_A.scaleFrequencyMultiplier(max_freq_mult); + const TransitionInfo& scaled_trans_B = trans_B.scaleFrequencyMultiplier(max_freq_mult); + + double A_prob_00 = scaled_trans_A.getNumberTransitions00() / max_freq_mult; + double A_prob_01 = scaled_trans_A.getNumberTransitions01() / max_freq_mult; + double A_prob_10 = A_prob_01; + double A_prob_11 = scaled_trans_A.getNumberTransitions11() / max_freq_mult; + double B_prob_00 = scaled_trans_B.getNumberTransitions00() / max_freq_mult; + double B_prob_01 = scaled_trans_B.getNumberTransitions01() / max_freq_mult; + double B_prob_10 = B_prob_01; + double B_prob_11 = scaled_trans_B.getNumberTransitions11() / max_freq_mult; + + // Set output transition info + double Y_prob_00 = A_prob_00 * B_prob_00; + double Y_prob_01 = A_prob_00 * B_prob_01 + + A_prob_01 * (B_prob_00 + B_prob_01); + double Y_prob_11 = A_prob_00 * B_prob_11 + + A_prob_01 * (B_prob_10 + B_prob_11) + + A_prob_10 * (B_prob_01 + B_prob_11) + + A_prob_11; + + // Check that probabilities add up to 1.0 with some finite tolerance + ASSERT(LibUtil::Math::isEqual((Y_prob_00 + Y_prob_01 + Y_prob_01 + Y_prob_11), 1.0), "[Error] " + getInstanceName() + + "Output transition probabilities must add up to 1 (" + (String) Y_prob_00 + ", " + + (String) Y_prob_01 + ", " + (String) Y_prob_11 + ")!"); + + // Turn probability of transitions per cycle into number of transitions per time unit + TransitionInfo trans_Y(Y_prob_00 * max_freq_mult, Y_prob_01 * max_freq_mult, Y_prob_11 * max_freq_mult); + getOutputPort("Y")->setTransitionInfo(trans_Y); + return; + } + + // Creates the standard cell, characterizes and abstracts away the details + void OR2::cacheStdCell(StdCellLib* cell_lib_, double drive_strength_) + { + // Get parameters + double gate_pitch = cell_lib_->getTechModel()->get("Gate->PitchContacted"); + Map<double>* cache = cell_lib_->getStdCellCache(); + + // Stadard cell cache string + const String& cell_name = "OR2_X" + (String) drive_strength_; + + Log::printLine("=== " + cell_name + " ==="); + + // Now actually build the full standard cell model + createInputPort("A"); + createInputPort("B"); + createOutputPort("Y"); + + createNet("Y_b"); + + // Adds macros + CellMacros::addNor2(this, "NOR2", false, true, true, "A", "B", "Y_b"); + CellMacros::addInverter(this, "INV", false, true, "Y_b", "Y"); + + // Update macros + CellMacros::updateNor2(this, "NOR2", drive_strength_ * 0.66); + CellMacros::updateInverter(this, "INV", drive_strength_ * 1.0); + + // Cache area result + double area = 0.0; + area += gate_pitch * getTotalHeight() * 1; + area += gate_pitch * getTotalHeight() * getGenProperties()->get("NOR2_GatePitches").toDouble(); + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INV_GatePitches").toDouble(); + cache->set(cell_name + "->ActiveArea", area); + Log::printLine(cell_name + "->ActiveArea=" + (String)area); + + // -------------------------------------------------------------------- + // Leakage Model Calculation + // -------------------------------------------------------------------- + // Cache leakage power results (for every single signal combination) + double leakage_00 = 0.0; // !A, !B + double leakage_01 = 0.0; // !A, B + double leakage_10 = 0.0; // A, !B + double leakage_11 = 0.0; // A, B + + leakage_00 += getGenProperties()->get("NOR2_LeakagePower_00").toDouble(); + leakage_00 += getGenProperties()->get("INV_LeakagePower_1").toDouble(); + + leakage_01 += getGenProperties()->get("NOR2_LeakagePower_01").toDouble(); + leakage_01 += getGenProperties()->get("INV_LeakagePower_0").toDouble(); + + leakage_10 += getGenProperties()->get("NOR2_LeakagePower_10").toDouble(); + leakage_10 += getGenProperties()->get("INV_LeakagePower_0").toDouble(); + + leakage_11 += getGenProperties()->get("NOR2_LeakagePower_11").toDouble(); + leakage_11 += getGenProperties()->get("INV_LeakagePower_0").toDouble(); + + cache->set(cell_name + "->Leakage->!A!B", leakage_00); + cache->set(cell_name + "->Leakage->!AB", leakage_01); + cache->set(cell_name + "->Leakage->A!B", leakage_10); + cache->set(cell_name + "->Leakage->AB", leakage_11); + Log::printLine(cell_name + "->Leakage->!A!B=" + (String) leakage_00); + Log::printLine(cell_name + "->Leakage->!AB=" + (String) leakage_01); + Log::printLine(cell_name + "->Leakage->A!B=" + (String) leakage_10); + Log::printLine(cell_name + "->Leakage->AB=" + (String) leakage_11); + // -------------------------------------------------------------------- + + // -------------------------------------------------------------------- + // Get Node Capacitances + // -------------------------------------------------------------------- + double a_cap = getNet("A")->getTotalDownstreamCap(); + double b_cap = getNet("B")->getTotalDownstreamCap(); + double y_b_cap = getNet("Y_b")->getTotalDownstreamCap(); + double y_cap = getNet("Y")->getTotalDownstreamCap(); + + cache->set(cell_name + "->Cap->A", a_cap); + cache->set(cell_name + "->Cap->B", b_cap); + cache->set(cell_name + "->Cap->Y_b", y_b_cap); + cache->set(cell_name + "->Cap->Y", y_cap); + Log::printLine(cell_name + "->Cap->A_Cap=" + (String) a_cap); + Log::printLine(cell_name + "->Cap->B_Cap=" + (String) b_cap); + Log::printLine(cell_name + "->Cap->Y_b_Cap=" + (String) y_b_cap); + Log::printLine(cell_name + "->Cap->Y_Cap=" + (String) y_cap); + // -------------------------------------------------------------------- + + // -------------------------------------------------------------------- + // Build Internal Delay Model + // -------------------------------------------------------------------- + double y_ron = getDriver("INV_RonZN")->getOutputRes(); + double a_to_y_delay = getDriver("NOR2_RonZN")->calculateDelay() + + getDriver("INV_RonZN")->calculateDelay(); + double b_to_y_delay = getDriver("NOR2_RonZN")->calculateDelay() + + getDriver("INV_RonZN")->calculateDelay(); + + cache->set(cell_name + "->DriveRes->Y", y_ron); + cache->set(cell_name + "->Delay->A_to_Y", a_to_y_delay); + cache->set(cell_name + "->Delay->B_to_Y", b_to_y_delay); + Log::printLine(cell_name + "->DriveRes->Y=" + (String) y_ron); + Log::printLine(cell_name + "->Delay->A_to_Y=" + (String) a_to_y_delay); + Log::printLine(cell_name + "->Delay->B_to_Y=" + (String) b_to_y_delay); + // -------------------------------------------------------------------- + + return; + } +} // namespace DSENT + diff --git a/ext/dsent/model/std_cells/OR2.h b/ext/dsent/model/std_cells/OR2.h new file mode 100644 index 000000000..8e08131f1 --- /dev/null +++ b/ext/dsent/model/std_cells/OR2.h @@ -0,0 +1,33 @@ +#ifndef __DSENT_MODEL_STD_CELLS_OR2_H__ +#define __DSENT_MODEL_STD_CELLS_OR2_H__ + +#include "util/CommonType.h" +#include "model/std_cells/StdCell.h" + +namespace DSENT +{ + class OR2 : public StdCell + { + public: + OR2(const String& instance_name_, const TechModel* tech_model_); + virtual ~OR2(); + + public: + // Set a list of properties' name needed to construct model + void initProperties(); + // Cache the standard cell + void cacheStdCell(StdCellLib* cell_lib_, double drive_strength_); + + protected: + // Build the model + virtual void constructModel(); + virtual void updateModel(); + virtual void evaluateModel(); + virtual void useModel(); + virtual void propagateTransitionInfo(); + + }; // class OR2 +} // namespace DSENT + +#endif // __DSENT_MODEL_STD_CELLS_OR2_H__ + diff --git a/ext/dsent/model/std_cells/StdCell.cc b/ext/dsent/model/std_cells/StdCell.cc new file mode 100644 index 000000000..bc95f97c3 --- /dev/null +++ b/ext/dsent/model/std_cells/StdCell.cc @@ -0,0 +1,71 @@ +#include "model/std_cells/StdCell.h" + +#include "model/timing_graph/ElectricalNet.h" +#include "model/timing_graph/ElectricalDriver.h" +#include "model/timing_graph/ElectricalLoad.h" + +#include <cmath> +#include <algorithm> + +namespace DSENT +{ + StdCell::StdCell(const String& instance_name_, const TechModel* tech_model_) + : ElectricalModel(instance_name_, tech_model_) + { + initParameters(); + initProperties(); + } + + StdCell::~StdCell() + { + + } + + + void StdCell::initParameters() + { + addParameterName("AvailableDrivingStrengths"); + return; + } + + void StdCell::initProperties() + { + addPropertyName("DrivingStrength"); + return; + } + + // Get PMOS to NMOS ratio + double StdCell::getPToNRatio() const + { + return m_p_to_n_ratio_; + } + + void StdCell::setPToNRatio(double p_to_n_ratio_) + { + m_p_to_n_ratio_ = p_to_n_ratio_; + } + + // Get height of the standard cell taken by active transistors + double StdCell::getActiveHeight() const + { + return m_active_height_; + } + + void StdCell::setActiveHeight(double active_height_) + { + m_active_height_ = active_height_; + } + + // Get total height of the standard cell including overheads + double StdCell::getTotalHeight() const + { + return m_total_height_; + } + + void StdCell::setTotalHeight(double total_height_) + { + m_total_height_ = total_height_; + } + +} // namespace DSENT + diff --git a/ext/dsent/model/std_cells/StdCell.h b/ext/dsent/model/std_cells/StdCell.h new file mode 100644 index 000000000..25a65768a --- /dev/null +++ b/ext/dsent/model/std_cells/StdCell.h @@ -0,0 +1,53 @@ +#ifndef __DSENT_MODEL_STD_CELLS_STDCELL_H__ +#define __DSENT_MODEL_STD_CELLS_STDCELL_H__ + +#include "util/CommonType.h" +#include "model/ElectricalModel.h" + +namespace DSENT +{ + class StdCell : public ElectricalModel + { + public: + StdCell(const String& instance_name_, const TechModel* tech_model_); + virtual ~StdCell(); + + public: + // Set a list of parameters needed to construct model + virtual void initParameters(); + // Set a list of properties needed to update model + virtual void initProperties(); + + // Get PMOS to NMOS ratio + double getPToNRatio() const; + void setPToNRatio(double p_to_n_ratio_); + // Get height of the standard cell taken by active transistors + double getActiveHeight() const; + void setActiveHeight(double active_height_); + // Get total height of the standard cell including overheads + double getTotalHeight() const; + void setTotalHeight(double total_height_); + + // Construct the full model of the standard cell and cache + // its contents to use for future copies of the standard cell + virtual void cacheStdCell(StdCellLib* cell_lib_, double drive_strength_) = 0; + + protected: + // Build the model, note that this is only available if the + // standard cell has been cached (via cacheStdCellModel) + virtual void constructModel() = 0; + virtual void updateModel() = 0; + + private: + // The PMOS to NMOS ratio + double m_p_to_n_ratio_; + // The height of the standard cell taken by active transitors + double m_active_height_; + // The total height of the standard cell including overheads + double m_total_height_; + + }; // class StdCell +} // namespace DSENT + +#endif // __DSENT_MODEL_STD_CELLS_STDCELL_H__ + diff --git a/ext/dsent/model/std_cells/StdCellLib.cc b/ext/dsent/model/std_cells/StdCellLib.cc new file mode 100644 index 000000000..dfe32012b --- /dev/null +++ b/ext/dsent/model/std_cells/StdCellLib.cc @@ -0,0 +1,180 @@ +#include "model/std_cells/StdCellLib.h" + +#include <cmath> + +#include "model/std_cells/StdCell.h" +#include "model/std_cells/INV.h" +#include "model/ModelGen.h" + +namespace DSENT +{ + using std::pow; + + StdCellLib::StdCellLib(TechModel* tech_model_) + : m_tech_model_(tech_model_) + { + m_std_cell_cache_ = new Map<double>(); + ASSERT((m_tech_model_ != NULL), "[Error] StdCellLib -> tech_model is NULL"); + createLib(); + } + + StdCellLib::~StdCellLib() + { + delete m_std_cell_cache_; + } + + const TechModel* StdCellLib::getTechModel() const + { + return m_tech_model_; + } + + StdCell* StdCellLib::createStdCell(const String& std_cell_name_, const String& instance_name_) const + { + // Create the standard cell + StdCell* created_cell = ModelGen::createStdCell(std_cell_name_, instance_name_, getTechModel()); + // Grab the variants of each standard cell + String driving_strength_str = getTechModel()->get("StdCell->AvailableSizes"); + // Set library properties for the standard cell + created_cell->setPToNRatio(getPToNRatio()); + created_cell->setActiveHeight(getActiveHeight()); + created_cell->setTotalHeight(getTotalHeight()); + created_cell->setAvailableDrivingStrengths(driving_strength_str); + return created_cell; + } + + // Get PMOS to NMOS ratio + double StdCellLib::getPToNRatio() const + { + return m_p_to_n_ratio_; + } + + void StdCellLib::setPToNRatio(double p_to_n_ratio_) + { + m_p_to_n_ratio_ = p_to_n_ratio_; + } + + // Get height of the standard cell taken by active transistors + double StdCellLib::getActiveHeight() const + { + return m_active_height_; + } + + void StdCellLib::setActiveHeight(double active_height_) + { + m_active_height_ = active_height_; + } + + // Get total height of the standard cell including overheads + double StdCellLib::getTotalHeight() const + { + return m_total_height_; + } + + void StdCellLib::setTotalHeight(double total_height_) + { + m_total_height_ = total_height_; + } + + void StdCellLib::createLib() + { + Log::printLine("Standard cell library creation for tech model " + getTechModel()->get("Name")); + + // Get technology parameters + double nmos_eff_res = getTechModel()->get("Nmos->EffResWidth"); + double pmos_eff_res = getTechModel()->get("Pmos->EffResWidth"); + double gate_min_width = getTechModel()->get("Gate->MinWidth"); + + // Create standard cell common parameters + double pn_ratio = pmos_eff_res / nmos_eff_res; + double nmos_unit_width = gate_min_width; + double pmos_unit_width = gate_min_width * pn_ratio; + + // Derive the height of each cell in the standard cell library, as well as the max Nmos and Pmos widths + double std_cell_total_height = getTechModel()->get("StdCell->Tracks").toDouble() * + (getTechModel()->get("Wire->Metal1->MinWidth").toDouble() + getTechModel()->get("Wire->Metal1->MinSpacing").toDouble()); + double std_cell_active_height = std_cell_total_height / getTechModel()->get("StdCell->HeightOverheadFactor").toDouble(); + + Log::printLine("Standard cell P-to-N ratio (Beta) = " + (String) pn_ratio); + Log::printLine("Standard cell NMOS unit width = " + (String) nmos_unit_width); + Log::printLine("Standard cell PMOS unit width = " + (String) pmos_unit_width); + Log::printLine("Standard cell active height = " + (String) std_cell_active_height); + Log::printLine("Standard cell total height = " + (String) std_cell_total_height); + + setPToNRatio(pn_ratio); + setActiveHeight(std_cell_active_height); + setTotalHeight(std_cell_total_height); + + const vector<String>& cell_sizes = getTechModel()->get("StdCell->AvailableSizes").split("[,]"); + // Create cached standard cells + for (unsigned int i = 0; i < cell_sizes.size(); ++i) + { + StdCell* inv = createStdCell("INV", "CachedINV"); + inv->cacheStdCell(this, cell_sizes[i].toDouble()); + delete inv; + + StdCell* nand2 = createStdCell("NAND2", "CachedNAND2"); + nand2->cacheStdCell(this, cell_sizes[i].toDouble()); + delete nand2; + + StdCell* nor2 = createStdCell("NOR2", "CachedNOR2"); + nor2->cacheStdCell(this, cell_sizes[i].toDouble()); + delete nor2; + + StdCell* mux2 = createStdCell("MUX2", "CachedMUX2"); + mux2->cacheStdCell(this, cell_sizes[i].toDouble()); + delete mux2; + + StdCell* xor2 = createStdCell("XOR2", "CachedXOR2"); + xor2->cacheStdCell(this, cell_sizes[i].toDouble()); + delete xor2; + + StdCell* addf = createStdCell("ADDF", "CachedADDF"); + addf->cacheStdCell(this, cell_sizes[i].toDouble()); + delete addf; + + StdCell* dffq = createStdCell("DFFQ", "CachedDFFQ"); + dffq->cacheStdCell(this, cell_sizes[i].toDouble()); + delete dffq; + + StdCell* latq = createStdCell("LATQ", "CachedLATQ"); + latq->cacheStdCell(this, cell_sizes[i].toDouble()); + delete latq; + + StdCell* or2 = createStdCell("OR2", "CachedOR2"); + or2->cacheStdCell(this, cell_sizes[i].toDouble()); + delete or2; + + StdCell* and2 = createStdCell("AND2", "CachedAND2"); + and2->cacheStdCell(this, cell_sizes[i].toDouble()); + delete and2; + } + + Log::printLine("Standard cell library creation - End"); + return; + } + + StdCellLib* StdCellLib::clone() const + { + StdCellLib* new_lib = new StdCellLib(m_tech_model_); + return new_lib; + } + + const String StdCellLib::genDrivingStrengthString(const vector<double>& driving_strength_) const + { + String ret_str = "["; + for(int i = 0; i < (int)driving_strength_.size() - 1; ++i) + { + ret_str += String(driving_strength_[i]) + ", "; + } + ret_str += String(driving_strength_[driving_strength_.size() - 1]); + ret_str += "]"; + return ret_str; + } + + Map<double>* StdCellLib::getStdCellCache() const + { + return m_std_cell_cache_; + } + +} // namespace DSENT + diff --git a/ext/dsent/model/std_cells/StdCellLib.h b/ext/dsent/model/std_cells/StdCellLib.h new file mode 100644 index 000000000..74c09149e --- /dev/null +++ b/ext/dsent/model/std_cells/StdCellLib.h @@ -0,0 +1,63 @@ +#ifndef __DSENT_MODEL_STD_CELLS_STDCELLLIBS_H__ +#define __DSENT_MODEL_STD_CELLS_STDCELLLIBS_H__ + +#include "util/CommonType.h" + +namespace DSENT +{ + class TechModel; + class StdCell; + class LibertyFile; + + class StdCellLib + { + public: + StdCellLib(TechModel* tech_model_); + ~StdCellLib(); + + public: + // Get the technology model pointer + const TechModel* getTechModel() const; + // Create a standard cell by name and instance name + StdCell* createStdCell(const String& std_cell_name_, const String& instance_name_) const; + + // Get PMOS to NMOS ratio + double getPToNRatio() const; + void setPToNRatio(double p_to_n_ratio_); + // Get height of the standard cell taken by active transistors + double getActiveHeight() const; + void setActiveHeight(double active_height_); + // Get total height of the standard cell including overheads + double getTotalHeight() const; + void setTotalHeight(double total_height_); + // Get the standard cell library cache of values + Map<double>* getStdCellCache() const; + // Create a list of standard cells + void createLib(); + + // Return a copy of this instance + StdCellLib* clone() const; + + private: + // Disabled copy constructor. Use clone to perform copy operation + StdCellLib(const StdCellLib& std_cell_lib_); + // Generate driving strength string + const String genDrivingStrengthString(const vector<double>& driving_strength_) const; + + private: + // Technology model pointer + TechModel* m_tech_model_; + // The PMOS to NMOS ratio + double m_p_to_n_ratio_; + // The height of the standard cell taken by active transitors + double m_active_height_; + // The total height of the standard cell including overheads + double m_total_height_; + // Std cell values cache + Map<double>* m_std_cell_cache_; + + }; // class StdCellLib +} // namespace DSENT + +#endif // __DSENT_MODEL_STD_CELLS_STDCELLLIBS_H__ + diff --git a/ext/dsent/model/std_cells/XOR2.cc b/ext/dsent/model/std_cells/XOR2.cc new file mode 100644 index 000000000..5b57b55e5 --- /dev/null +++ b/ext/dsent/model/std_cells/XOR2.cc @@ -0,0 +1,345 @@ +#include "model/std_cells/XOR2.h" + +#include <cmath> + +#include "model/PortInfo.h" +#include "model/EventInfo.h" +#include "model/TransitionInfo.h" +#include "model/std_cells/StdCellLib.h" +#include "model/std_cells/CellMacros.h" +#include "model/timing_graph/ElectricalNet.h" +#include "model/timing_graph/ElectricalDriver.h" +#include "model/timing_graph/ElectricalLoad.h" +#include "model/timing_graph/ElectricalDelay.h" + +namespace DSENT +{ + using std::ceil; + using std::max; + + XOR2::XOR2(const String& instance_name_, const TechModel* tech_model_) + : StdCell(instance_name_, tech_model_) + { + initProperties(); + } + + XOR2::~XOR2() + {} + + void XOR2::initProperties() + { + return; + } + + void XOR2::constructModel() + { + // All constructModel should do is create Area/NDDPower/Energy Results as + // well as instantiate any sub-instances using only the hard parameters + + createInputPort("A"); + createInputPort("B"); + createOutputPort("Y"); + + createLoad("A_Cap"); + createLoad("B_Cap"); + createDelay("A_to_Y_delay"); + createDelay("B_to_Y_delay"); + createDriver("Y_Ron", true); + + ElectricalLoad* a_cap = getLoad("A_Cap"); + ElectricalLoad* b_cap = getLoad("B_Cap"); + ElectricalDelay* a_to_y_delay = getDelay("A_to_Y_delay"); + ElectricalDelay* b_to_y_delay = getDelay("B_to_Y_delay"); + ElectricalDriver* y_ron = getDriver("Y_Ron"); + + getNet("A")->addDownstreamNode(a_cap); + getNet("B")->addDownstreamNode(b_cap); + a_cap->addDownstreamNode(a_to_y_delay); + b_cap->addDownstreamNode(b_to_y_delay); + a_to_y_delay->addDownstreamNode(y_ron); + b_to_y_delay->addDownstreamNode(y_ron); + y_ron->addDownstreamNode(getNet("Y")); + + // Create Area result + // Create NDD Power result + createElectricalAtomicResults(); + // Create XOR2 Event Energy Result + createElectricalEventAtomicResult("XOR2"); + + getEventInfo("Idle")->setStaticTransitionInfos(); + + return; + } + + void XOR2::updateModel() + { + // Get parameters + double drive_strength = getDrivingStrength(); + Map<double>* cache = getTechModel()->getStdCellLib()->getStdCellCache(); + + // Standard cell cache string + String cell_name = "XOR2_X" + (String) drive_strength; + + // Get timing parameters + getLoad("A_Cap")->setLoadCap(cache->get(cell_name + "->Cap->A")); + getLoad("B_Cap")->setLoadCap(cache->get(cell_name + "->Cap->B")); + + getDelay("A_to_Y_delay")->setDelay(cache->get(cell_name + "->Delay->A_to_Y")); + getDelay("B_to_Y_delay")->setDelay(cache->get(cell_name + "->Delay->B_to_Y")); + + getDriver("Y_Ron")->setOutputRes(cache->get(cell_name + "->DriveRes->Y")); + + // Set the cell area + getAreaResult("Active")->setValue(cache->get(cell_name + "->ActiveArea")); + getAreaResult("Metal1Wire")->setValue(cache->get(cell_name + "->ActiveArea")); + + return; + } + + void XOR2::evaluateModel() + { + return; + } + + void XOR2::useModel() + { + // Get parameters + double drive_strength = getDrivingStrength(); + Map<double>* cache = getTechModel()->getStdCellLib()->getStdCellCache(); + + // Standard cell cache string + String cell_name = "XOR2_X" + (String) drive_strength; + + // Propagate the transition info and get the 0->1 transtion count + propagateTransitionInfo(); + double P_A = getInputPort("A")->getTransitionInfo().getProbability1(); + double P_B = getInputPort("B")->getTransitionInfo().getProbability1(); + double A_num_trans_01 = getInputPort("A")->getTransitionInfo().getNumberTransitions01(); + double B_num_trans_01 = getInputPort("B")->getTransitionInfo().getNumberTransitions01(); + double Y_num_trans_01 = getOutputPort("Y")->getTransitionInfo().getNumberTransitions01(); + + // Calculate leakage + double leakage = 0; + leakage += cache->get(cell_name + "->Leakage->!A!B") * (1 - P_A) * (1 - P_B); + leakage += cache->get(cell_name + "->Leakage->!AB") * (1 - P_A) * P_B; + leakage += cache->get(cell_name + "->Leakage->A!B") * P_A * (1 - P_B); + leakage += cache->get(cell_name + "->Leakage->AB") * P_A * P_B; + getNddPowerResult("Leakage")->setValue(leakage); + + // Get VDD + double vdd = getTechModel()->get("Vdd"); + + // Get capacitances + double a_b_cap = cache->get(cell_name + "->Cap->A_b"); + double b_b_cap = cache->get(cell_name + "->Cap->B_b"); + double y_cap = cache->get(cell_name + "->Cap->Y"); + double y_load_cap = getNet("Y")->getTotalDownstreamCap(); + + // Calculate XOR Event energy + double xor2_event_result = 0.0; + xor2_event_result += a_b_cap * A_num_trans_01; + xor2_event_result += b_b_cap * B_num_trans_01; + xor2_event_result += (y_cap + y_load_cap) * Y_num_trans_01; + xor2_event_result *= vdd * vdd; + getEventResult("XOR2")->setValue(xor2_event_result); + + return; + } + + void XOR2::propagateTransitionInfo() + { + // Get input signal transition info + const TransitionInfo& trans_A = getInputPort("A")->getTransitionInfo(); + const TransitionInfo& trans_B = getInputPort("B")->getTransitionInfo(); + + double max_freq_mult = max(trans_A.getFrequencyMultiplier(), trans_B.getFrequencyMultiplier()); + const TransitionInfo& scaled_trans_A = trans_A.scaleFrequencyMultiplier(max_freq_mult); + const TransitionInfo& scaled_trans_B = trans_B.scaleFrequencyMultiplier(max_freq_mult); + + + double A_prob_00 = scaled_trans_A.getNumberTransitions00() / max_freq_mult; + double A_prob_01 = scaled_trans_A.getNumberTransitions01() / max_freq_mult; + double A_prob_10 = A_prob_01; + double A_prob_11 = scaled_trans_A.getNumberTransitions11() / max_freq_mult; + double B_prob_00 = scaled_trans_B.getNumberTransitions00() / max_freq_mult; + double B_prob_01 = scaled_trans_B.getNumberTransitions01() / max_freq_mult; + double B_prob_10 = B_prob_01; + double B_prob_11 = scaled_trans_B.getNumberTransitions11() / max_freq_mult; + + // Set output transition info + double Y_prob_00 = A_prob_00 * B_prob_00 + + A_prob_01 * B_prob_01 + + A_prob_10 * B_prob_10 + + A_prob_11 * B_prob_11; + double Y_prob_01 = A_prob_00 * B_prob_01 + + A_prob_01 * B_prob_00 + + A_prob_10 * B_prob_11 + + A_prob_11 * B_prob_10; + double Y_prob_11 = A_prob_00 * B_prob_11 + + A_prob_01 * B_prob_10 + + A_prob_10 * B_prob_01 + + A_prob_11 * B_prob_00; + + // Check that probabilities add up to 1.0 with some finite tolerance + ASSERT(LibUtil::Math::isEqual((Y_prob_00 + Y_prob_01 + Y_prob_01 + Y_prob_11), 1.0), + "[Error] " + getInstanceName() + "Output transition probabilities must add up to 1 (" + + (String) Y_prob_00 + ", " + (String) Y_prob_01 + ", " + (String) Y_prob_11 + ")!"); + + // Turn probability of transitions per cycle into number of transitions per time unit + TransitionInfo trans_Y(Y_prob_00 * max_freq_mult, Y_prob_01 * max_freq_mult, Y_prob_11 * max_freq_mult); + getOutputPort("Y")->setTransitionInfo(trans_Y); + return; + } + + // Creates the standard cell, characterizes and abstracts away the details + void XOR2::cacheStdCell(StdCellLib* cell_lib_, double drive_strength_) + { + // Get parameters + double gate_pitch = cell_lib_->getTechModel()->get("Gate->PitchContacted"); + Map<double>* cache = cell_lib_->getStdCellCache(); + + // Standard cell cache string + String cell_name = "XOR2_X" + (String) drive_strength_; + + Log::printLine("=== " + cell_name + " ==="); + + // Now actually build the full standard cell model + createInputPort("A"); + createInputPort("B"); + createOutputPort("Y"); + + createNet("A_b"); + createNet("B_b"); + + // Adds macros + CellMacros::addInverter(this, "INV1", false, true, "A", "A_b"); + CellMacros::addInverter(this, "INV2", false, true, "B", "B_b"); + CellMacros::addTristate(this, "INVZ1", true, true, true, true, "B", "A", "A_b", "Y"); + CellMacros::addTristate(this, "INVZ2", true, true, true, true, "B_b", "A_b", "A", "Y"); + + // I have no idea how to size each of the parts haha + CellMacros::updateInverter(this, "INV1", drive_strength_ * 0.500); + CellMacros::updateInverter(this, "INV2", drive_strength_ * 0.500); + CellMacros::updateTristate(this, "INVZ1", drive_strength_ * 1.000); + CellMacros::updateTristate(this, "INVZ2", drive_strength_ * 1.000); + + // Cache area result + double area = 0.0; + area += gate_pitch * getTotalHeight() * 1; + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INV1_GatePitches").toDouble(); + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INV2_GatePitches").toDouble(); + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INVZ1_GatePitches").toDouble(); + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INVZ2_GatePitches").toDouble(); + cache->set(cell_name + "->ActiveArea", area); + Log::printLine(cell_name + "->ActiveArea=" + (String) area); + + // -------------------------------------------------------------------- + // Leakage Model Calculation + // -------------------------------------------------------------------- + // Cache leakage power results (for every single signal combination) + double leakage_00 = 0; //!A, !B + double leakage_01 = 0; //!A, B + double leakage_10 = 0; //A, !B + double leakage_11 = 0; //A, B + + //This is so painful... + leakage_00 += getGenProperties()->get("INV1_LeakagePower_0").toDouble(); + leakage_00 += getGenProperties()->get("INV2_LeakagePower_0").toDouble(); + leakage_00 += getGenProperties()->get("INVZ1_LeakagePower_010_0").toDouble(); + leakage_00 += getGenProperties()->get("INVZ2_LeakagePower_101_0").toDouble(); + + leakage_01 += getGenProperties()->get("INV1_LeakagePower_0").toDouble(); + leakage_01 += getGenProperties()->get("INV2_LeakagePower_1").toDouble(); + leakage_01 += getGenProperties()->get("INVZ1_LeakagePower_011_1").toDouble(); + leakage_01 += getGenProperties()->get("INVZ2_LeakagePower_100_1").toDouble(); + + leakage_10 += getGenProperties()->get("INV1_LeakagePower_1").toDouble(); + leakage_10 += getGenProperties()->get("INV2_LeakagePower_0").toDouble(); + leakage_10 += getGenProperties()->get("INVZ1_LeakagePower_100_1").toDouble(); + leakage_10 += getGenProperties()->get("INVZ2_LeakagePower_011_1").toDouble(); + + leakage_11 += getGenProperties()->get("INV1_LeakagePower_1").toDouble(); + leakage_11 += getGenProperties()->get("INV2_LeakagePower_1").toDouble(); + leakage_11 += getGenProperties()->get("INVZ1_LeakagePower_101_0").toDouble(); + leakage_11 += getGenProperties()->get("INVZ2_LeakagePower_010_0").toDouble(); + + cache->set(cell_name + "->Leakage->!A!B", leakage_00); + cache->set(cell_name + "->Leakage->!AB", leakage_01); + cache->set(cell_name + "->Leakage->A!B", leakage_10); + cache->set(cell_name + "->Leakage->AB", leakage_11); + Log::printLine(cell_name + "->Leakage->!A!B=" + (String) leakage_00); + Log::printLine(cell_name + "->Leakage->!AB=" + (String) leakage_01); + Log::printLine(cell_name + "->Leakage->A!B=" + (String) leakage_10); + Log::printLine(cell_name + "->Leakage->AB=" + (String) leakage_11); + // -------------------------------------------------------------------- + + // Cache event energy results + /* + double event_a_flip = 0.0; + event_a_flip += getGenProperties()->get("INV1_A_Flip").toDouble() + getGenProperties()->get("INV1_ZN_Flip").toDouble(); + event_a_flip += getGenProperties()->get("INVZ1_OE_Flip").toDouble() + getGenProperties()->get("INVZ1_OEN_Flip").toDouble(); + event_a_flip += getGenProperties()->get("INVZ2_OE_Flip").toDouble() + getGenProperties()->get("INVZ2_OEN_Flip").toDouble(); + cache->set(cell_name + "->Event_A_Flip", event_a_flip); + Log::printLine(cell_name + "->Event_A_Flip=" + (String) event_a_flip); + + double event_b_flip = 0.0; + event_b_flip += getGenProperties()->get("INV2_A_Flip").toDouble() + getGenProperties()->get("INV2_ZN_Flip").toDouble(); + event_b_flip += getGenProperties()->get("INVZ1_A_Flip").toDouble(); + event_b_flip += getGenProperties()->get("INVZ2_A_Flip").toDouble(); + cache->set(cell_name + "->Event_B_Flip", event_b_flip); + Log::printLine(cell_name + "->Event_B_Flip=" + (String) event_b_flip); + + double event_y_flip = 0.0; + event_y_flip += getGenProperties()->get("INVZ1_ZN_Flip").toDouble(); + event_y_flip += getGenProperties()->get("INVZ2_ZN_Flip").toDouble(); + cache->set(cell_name + "->Event_Y_Flip", event_y_flip); + Log::printLine(cell_name + "->Event_Y_Flip=" + (String) event_y_flip); + */ + + // -------------------------------------------------------------------- + // Get Node Capacitances + // -------------------------------------------------------------------- + // Build abstracted timing model + double a_cap = getNet("A")->getTotalDownstreamCap(); + double b_cap = getNet("B")->getTotalDownstreamCap(); + double a_b_cap = getNet("A_b")->getTotalDownstreamCap(); + double b_b_cap = getNet("B_b")->getTotalDownstreamCap(); + double y_cap = getNet("Y")->getTotalDownstreamCap(); + + cache->set(cell_name + "->Cap->A", a_cap); + cache->set(cell_name + "->Cap->B", b_cap); + cache->set(cell_name + "->Cap->A_b", a_b_cap); + cache->set(cell_name + "->Cap->B_b", b_b_cap); + cache->set(cell_name + "->Cap->Y", y_cap); + Log::printLine(cell_name + "->Cap->A=" + (String) a_cap); + Log::printLine(cell_name + "->Cap->B=" + (String) b_cap); + Log::printLine(cell_name + "->Cap->A=" + (String) a_b_cap); + Log::printLine(cell_name + "->Cap->B=" + (String) b_b_cap); + Log::printLine(cell_name + "->Cap->Y=" + (String) y_cap); + // -------------------------------------------------------------------- + + // -------------------------------------------------------------------- + // Build Internal Delay Model + // -------------------------------------------------------------------- + double y_ron = (getDriver("INVZ1_RonZN")->getOutputRes() + getDriver("INVZ2_RonZN")->getOutputRes()) / 2; + + double a_to_y_delay = 0.0; + a_to_y_delay += getDriver("INV1_RonZN")->calculateDelay(); + a_to_y_delay += max(getDriver("INVZ1_RonZN")->calculateDelay(), getDriver("INVZ2_RonZN")->calculateDelay()); + + double b_to_y_delay = 0.0; + b_to_y_delay += max(getDriver("INVZ1_RonZN")->calculateDelay(), getDriver("INV2_RonZN")->calculateDelay() + getDriver("INVZ2_RonZN")->calculateDelay()); + + cache->set(cell_name + "->DriveRes->Y", y_ron); + cache->set(cell_name + "->Delay->A_to_Y", a_to_y_delay); + cache->set(cell_name + "->Delay->B_to_Y", b_to_y_delay); + Log::printLine(cell_name + "->DriveRes->Y=" + (String) y_ron); + Log::printLine(cell_name + "->Delay->A_to_Y=" + (String) a_to_y_delay); + Log::printLine(cell_name + "->Delay->B_to_Y=" + (String) b_to_y_delay); + // -------------------------------------------------------------------- + + return; + } + +} // namespace DSENT + diff --git a/ext/dsent/model/std_cells/XOR2.h b/ext/dsent/model/std_cells/XOR2.h new file mode 100644 index 000000000..95f9a54b3 --- /dev/null +++ b/ext/dsent/model/std_cells/XOR2.h @@ -0,0 +1,34 @@ +#ifndef __DSENT_MODEL_STD_CELLS_XOR2_H__ +#define __DSENT_MODEL_STD_CELLS_XOR2_H__ + +#include "util/CommonType.h" +#include "model/std_cells/StdCell.h" + +namespace DSENT +{ + class XOR2 : public StdCell + { + public: + XOR2(const String& instance_name_, const TechModel* tech_model_); + virtual ~XOR2(); + + public: + // Set a list of properties' name needed to construct model + void initProperties(); + + // Cache the standard cell + void cacheStdCell(StdCellLib* cell_lib_, double drive_strength_); + + protected: + // Build the model + virtual void constructModel(); + virtual void updateModel(); + virtual void evaluateModel(); + virtual void useModel(); + virtual void propagateTransitionInfo(); + + }; // class XOR2 +} // namespace DSENT + +#endif // __DSENT_MODEL_STD_CELLS_XOR2_H__ + |