summaryrefslogtreecommitdiff
path: root/ext/dsent/model/std_cells
diff options
context:
space:
mode:
Diffstat (limited to 'ext/dsent/model/std_cells')
-rw-r--r--ext/dsent/model/std_cells/ADDF.cc671
-rw-r--r--ext/dsent/model/std_cells/ADDF.h39
-rw-r--r--ext/dsent/model/std_cells/AND2.cc272
-rw-r--r--ext/dsent/model/std_cells/AND2.h32
-rw-r--r--ext/dsent/model/std_cells/BUF.cc216
-rw-r--r--ext/dsent/model/std_cells/BUF.h33
-rw-r--r--ext/dsent/model/std_cells/CellMacros.cc477
-rw-r--r--ext/dsent/model/std_cells/CellMacros.h57
-rw-r--r--ext/dsent/model/std_cells/DFFQ.cc536
-rw-r--r--ext/dsent/model/std_cells/DFFQ.h38
-rw-r--r--ext/dsent/model/std_cells/INV.cc219
-rw-r--r--ext/dsent/model/std_cells/INV.h34
-rw-r--r--ext/dsent/model/std_cells/LATQ.cc380
-rw-r--r--ext/dsent/model/std_cells/LATQ.h34
-rw-r--r--ext/dsent/model/std_cells/MUX2.cc420
-rw-r--r--ext/dsent/model/std_cells/MUX2.h34
-rw-r--r--ext/dsent/model/std_cells/NAND2.cc267
-rw-r--r--ext/dsent/model/std_cells/NAND2.h33
-rw-r--r--ext/dsent/model/std_cells/NOR2.cc268
-rw-r--r--ext/dsent/model/std_cells/NOR2.h33
-rw-r--r--ext/dsent/model/std_cells/OR2.cc279
-rw-r--r--ext/dsent/model/std_cells/OR2.h33
-rw-r--r--ext/dsent/model/std_cells/StdCell.cc71
-rw-r--r--ext/dsent/model/std_cells/StdCell.h53
-rw-r--r--ext/dsent/model/std_cells/StdCellLib.cc180
-rw-r--r--ext/dsent/model/std_cells/StdCellLib.h63
-rw-r--r--ext/dsent/model/std_cells/XOR2.cc345
-rw-r--r--ext/dsent/model/std_cells/XOR2.h34
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__
+