ext: add the source code for DSENT
authorNilay Vaish <nilay@cs.wisc.edu>
Sat, 11 Oct 2014 20:02:23 +0000 (15:02 -0500)
committerNilay Vaish <nilay@cs.wisc.edu>
Sat, 11 Oct 2014 20:02:23 +0000 (15:02 -0500)
This patch adds a tool called DSENT to the ext/ directory.  DSENT
is a tool that models power and area for on-chip networks.  The next
patch adds a script for using the tool.

183 files changed:
ext/dsent/DSENT.cc [new file with mode: 0644]
ext/dsent/DSENT.h [new file with mode: 0644]
ext/dsent/LICENSE [new file with mode: 0644]
ext/dsent/Makefile [new file with mode: 0644]
ext/dsent/README [new file with mode: 0644]
ext/dsent/configs/electrical-clos.cfg [new file with mode: 0644]
ext/dsent/configs/electrical-link.cfg [new file with mode: 0644]
ext/dsent/configs/electrical-mesh.cfg [new file with mode: 0644]
ext/dsent/configs/example.cfg [new file with mode: 0644]
ext/dsent/configs/photonic-clos.cfg [new file with mode: 0644]
ext/dsent/configs/photonic-link.cfg [new file with mode: 0644]
ext/dsent/configs/router.cfg [new file with mode: 0644]
ext/dsent/libutil/Assert.h [new file with mode: 0644]
ext/dsent/libutil/Calculator.cc [new file with mode: 0644]
ext/dsent/libutil/Calculator.h [new file with mode: 0644]
ext/dsent/libutil/Config.cc [new file with mode: 0644]
ext/dsent/libutil/Config.h [new file with mode: 0644]
ext/dsent/libutil/Exception.cc [new file with mode: 0644]
ext/dsent/libutil/Exception.h [new file with mode: 0644]
ext/dsent/libutil/LibUtil.h [new file with mode: 0644]
ext/dsent/libutil/Log.cc [new file with mode: 0644]
ext/dsent/libutil/Log.h [new file with mode: 0644]
ext/dsent/libutil/Makefile [new file with mode: 0644]
ext/dsent/libutil/Map.h [new file with mode: 0644]
ext/dsent/libutil/MathUtil.cc [new file with mode: 0644]
ext/dsent/libutil/MathUtil.h [new file with mode: 0644]
ext/dsent/libutil/OptionParser.cc [new file with mode: 0644]
ext/dsent/libutil/OptionParser.h [new file with mode: 0644]
ext/dsent/libutil/String.cc [new file with mode: 0644]
ext/dsent/libutil/String.h [new file with mode: 0644]
ext/dsent/main.cc [new file with mode: 0644]
ext/dsent/model/ElectricalModel.cc [new file with mode: 0644]
ext/dsent/model/ElectricalModel.h [new file with mode: 0644]
ext/dsent/model/EventInfo.cc [new file with mode: 0644]
ext/dsent/model/EventInfo.h [new file with mode: 0644]
ext/dsent/model/Model.cc [new file with mode: 0644]
ext/dsent/model/Model.h [new file with mode: 0644]
ext/dsent/model/ModelGen.cc [new file with mode: 0644]
ext/dsent/model/ModelGen.h [new file with mode: 0644]
ext/dsent/model/OpticalModel.cc [new file with mode: 0644]
ext/dsent/model/OpticalModel.h [new file with mode: 0644]
ext/dsent/model/PortInfo.cc [new file with mode: 0644]
ext/dsent/model/PortInfo.h [new file with mode: 0644]
ext/dsent/model/TransitionInfo.cc [new file with mode: 0644]
ext/dsent/model/TransitionInfo.h [new file with mode: 0644]
ext/dsent/model/electrical/BarrelShifter.cc [new file with mode: 0644]
ext/dsent/model/electrical/BarrelShifter.h [new file with mode: 0644]
ext/dsent/model/electrical/BroadcastHTree.cc [new file with mode: 0644]
ext/dsent/model/electrical/BroadcastHTree.h [new file with mode: 0644]
ext/dsent/model/electrical/DFFRAM.cc [new file with mode: 0644]
ext/dsent/model/electrical/DFFRAM.h [new file with mode: 0644]
ext/dsent/model/electrical/Decoder.cc [new file with mode: 0644]
ext/dsent/model/electrical/Decoder.h [new file with mode: 0644]
ext/dsent/model/electrical/DemuxTreeDeserializer.cc [new file with mode: 0644]
ext/dsent/model/electrical/DemuxTreeDeserializer.h [new file with mode: 0644]
ext/dsent/model/electrical/MatrixArbiter.cc [new file with mode: 0644]
ext/dsent/model/electrical/MatrixArbiter.h [new file with mode: 0644]
ext/dsent/model/electrical/Multiplexer.cc [new file with mode: 0644]
ext/dsent/model/electrical/Multiplexer.h [new file with mode: 0644]
ext/dsent/model/electrical/MultiplexerCrossbar.cc [new file with mode: 0644]
ext/dsent/model/electrical/MultiplexerCrossbar.h [new file with mode: 0644]
ext/dsent/model/electrical/MuxTreeSerializer.cc [new file with mode: 0644]
ext/dsent/model/electrical/MuxTreeSerializer.h [new file with mode: 0644]
ext/dsent/model/electrical/OR.cc [new file with mode: 0644]
ext/dsent/model/electrical/OR.h [new file with mode: 0644]
ext/dsent/model/electrical/RepeatedLink.cc [new file with mode: 0644]
ext/dsent/model/electrical/RepeatedLink.h [new file with mode: 0644]
ext/dsent/model/electrical/RippleAdder.cc [new file with mode: 0644]
ext/dsent/model/electrical/RippleAdder.h [new file with mode: 0644]
ext/dsent/model/electrical/SeparableAllocator.cc [new file with mode: 0644]
ext/dsent/model/electrical/SeparableAllocator.h [new file with mode: 0644]
ext/dsent/model/electrical/TestModel.cc [new file with mode: 0644]
ext/dsent/model/electrical/TestModel.h [new file with mode: 0644]
ext/dsent/model/electrical/router/Router.cc [new file with mode: 0644]
ext/dsent/model/electrical/router/Router.h [new file with mode: 0644]
ext/dsent/model/electrical/router/RouterInputPort.cc [new file with mode: 0644]
ext/dsent/model/electrical/router/RouterInputPort.h [new file with mode: 0644]
ext/dsent/model/electrical/router/RouterSwitchAllocator.cc [new file with mode: 0644]
ext/dsent/model/electrical/router/RouterSwitchAllocator.h [new file with mode: 0644]
ext/dsent/model/network/ElectricalClos.cc [new file with mode: 0644]
ext/dsent/model/network/ElectricalClos.h [new file with mode: 0644]
ext/dsent/model/network/ElectricalMesh.cc [new file with mode: 0644]
ext/dsent/model/network/ElectricalMesh.h [new file with mode: 0644]
ext/dsent/model/network/PhotonicClos.cc [new file with mode: 0644]
ext/dsent/model/network/PhotonicClos.h [new file with mode: 0644]
ext/dsent/model/optical/GatedLaserSource.cc [new file with mode: 0644]
ext/dsent/model/optical/GatedLaserSource.h [new file with mode: 0644]
ext/dsent/model/optical/LaserSource.cc [new file with mode: 0644]
ext/dsent/model/optical/LaserSource.h [new file with mode: 0644]
ext/dsent/model/optical/OpticalLinkBackendRx.cc [new file with mode: 0644]
ext/dsent/model/optical/OpticalLinkBackendRx.h [new file with mode: 0644]
ext/dsent/model/optical/OpticalLinkBackendTx.cc [new file with mode: 0644]
ext/dsent/model/optical/OpticalLinkBackendTx.h [new file with mode: 0644]
ext/dsent/model/optical/OpticalTestModel.cc [new file with mode: 0644]
ext/dsent/model/optical/OpticalTestModel.h [new file with mode: 0644]
ext/dsent/model/optical/RingDetector.cc [new file with mode: 0644]
ext/dsent/model/optical/RingDetector.h [new file with mode: 0644]
ext/dsent/model/optical/RingFilter.cc [new file with mode: 0644]
ext/dsent/model/optical/RingFilter.h [new file with mode: 0644]
ext/dsent/model/optical/RingModulator.cc [new file with mode: 0644]
ext/dsent/model/optical/RingModulator.h [new file with mode: 0644]
ext/dsent/model/optical/SWMRLink.cc [new file with mode: 0644]
ext/dsent/model/optical/SWMRLink.h [new file with mode: 0644]
ext/dsent/model/optical/SWSRLink.cc [new file with mode: 0644]
ext/dsent/model/optical/SWSRLink.h [new file with mode: 0644]
ext/dsent/model/optical/ThrottledLaserSource.cc [new file with mode: 0644]
ext/dsent/model/optical/ThrottledLaserSource.h [new file with mode: 0644]
ext/dsent/model/optical_graph/OpticalDetector.cc [new file with mode: 0644]
ext/dsent/model/optical_graph/OpticalDetector.h [new file with mode: 0644]
ext/dsent/model/optical_graph/OpticalFilter.cc [new file with mode: 0644]
ext/dsent/model/optical_graph/OpticalFilter.h [new file with mode: 0644]
ext/dsent/model/optical_graph/OpticalGraph.cc [new file with mode: 0644]
ext/dsent/model/optical_graph/OpticalGraph.h [new file with mode: 0644]
ext/dsent/model/optical_graph/OpticalLaser.cc [new file with mode: 0644]
ext/dsent/model/optical_graph/OpticalLaser.h [new file with mode: 0644]
ext/dsent/model/optical_graph/OpticalModulator.cc [new file with mode: 0644]
ext/dsent/model/optical_graph/OpticalModulator.h [new file with mode: 0644]
ext/dsent/model/optical_graph/OpticalNode.cc [new file with mode: 0644]
ext/dsent/model/optical_graph/OpticalNode.h [new file with mode: 0644]
ext/dsent/model/optical_graph/OpticalReceiver.h [new file with mode: 0644]
ext/dsent/model/optical_graph/OpticalTransmitter.h [new file with mode: 0644]
ext/dsent/model/optical_graph/OpticalWaveguide.cc [new file with mode: 0644]
ext/dsent/model/optical_graph/OpticalWaveguide.h [new file with mode: 0644]
ext/dsent/model/optical_graph/OpticalWavelength.cc [new file with mode: 0644]
ext/dsent/model/optical_graph/OpticalWavelength.h [new file with mode: 0644]
ext/dsent/model/std_cells/ADDF.cc [new file with mode: 0644]
ext/dsent/model/std_cells/ADDF.h [new file with mode: 0644]
ext/dsent/model/std_cells/AND2.cc [new file with mode: 0644]
ext/dsent/model/std_cells/AND2.h [new file with mode: 0644]
ext/dsent/model/std_cells/BUF.cc [new file with mode: 0644]
ext/dsent/model/std_cells/BUF.h [new file with mode: 0644]
ext/dsent/model/std_cells/CellMacros.cc [new file with mode: 0644]
ext/dsent/model/std_cells/CellMacros.h [new file with mode: 0644]
ext/dsent/model/std_cells/DFFQ.cc [new file with mode: 0644]
ext/dsent/model/std_cells/DFFQ.h [new file with mode: 0644]
ext/dsent/model/std_cells/INV.cc [new file with mode: 0644]
ext/dsent/model/std_cells/INV.h [new file with mode: 0644]
ext/dsent/model/std_cells/LATQ.cc [new file with mode: 0644]
ext/dsent/model/std_cells/LATQ.h [new file with mode: 0644]
ext/dsent/model/std_cells/MUX2.cc [new file with mode: 0644]
ext/dsent/model/std_cells/MUX2.h [new file with mode: 0644]
ext/dsent/model/std_cells/NAND2.cc [new file with mode: 0644]
ext/dsent/model/std_cells/NAND2.h [new file with mode: 0644]
ext/dsent/model/std_cells/NOR2.cc [new file with mode: 0644]
ext/dsent/model/std_cells/NOR2.h [new file with mode: 0644]
ext/dsent/model/std_cells/OR2.cc [new file with mode: 0644]
ext/dsent/model/std_cells/OR2.h [new file with mode: 0644]
ext/dsent/model/std_cells/StdCell.cc [new file with mode: 0644]
ext/dsent/model/std_cells/StdCell.h [new file with mode: 0644]
ext/dsent/model/std_cells/StdCellLib.cc [new file with mode: 0644]
ext/dsent/model/std_cells/StdCellLib.h [new file with mode: 0644]
ext/dsent/model/std_cells/XOR2.cc [new file with mode: 0644]
ext/dsent/model/std_cells/XOR2.h [new file with mode: 0644]
ext/dsent/model/timing_graph/ElectricalDelay.cc [new file with mode: 0644]
ext/dsent/model/timing_graph/ElectricalDelay.h [new file with mode: 0644]
ext/dsent/model/timing_graph/ElectricalDriver.cc [new file with mode: 0644]
ext/dsent/model/timing_graph/ElectricalDriver.h [new file with mode: 0644]
ext/dsent/model/timing_graph/ElectricalDriverMultiplier.cc [new file with mode: 0644]
ext/dsent/model/timing_graph/ElectricalDriverMultiplier.h [new file with mode: 0644]
ext/dsent/model/timing_graph/ElectricalLoad.cc [new file with mode: 0644]
ext/dsent/model/timing_graph/ElectricalLoad.h [new file with mode: 0644]
ext/dsent/model/timing_graph/ElectricalNet.cc [new file with mode: 0644]
ext/dsent/model/timing_graph/ElectricalNet.h [new file with mode: 0644]
ext/dsent/model/timing_graph/ElectricalTimingNode.cc [new file with mode: 0644]
ext/dsent/model/timing_graph/ElectricalTimingNode.h [new file with mode: 0644]
ext/dsent/model/timing_graph/ElectricalTimingOptimizer.cc [new file with mode: 0644]
ext/dsent/model/timing_graph/ElectricalTimingOptimizer.h [new file with mode: 0644]
ext/dsent/model/timing_graph/ElectricalTimingTree.cc [new file with mode: 0644]
ext/dsent/model/timing_graph/ElectricalTimingTree.h [new file with mode: 0644]
ext/dsent/tech/TechModel.cc [new file with mode: 0644]
ext/dsent/tech/TechModel.h [new file with mode: 0644]
ext/dsent/tech/tech_models/Bulk22LVT.model [new file with mode: 0644]
ext/dsent/tech/tech_models/Bulk32LVT.model [new file with mode: 0644]
ext/dsent/tech/tech_models/Bulk45LVT.model [new file with mode: 0644]
ext/dsent/tech/tech_models/Photonics.model [new file with mode: 0644]
ext/dsent/tech/tech_models/TG11LVT.model [new file with mode: 0644]
ext/dsent/util/CommonType.h [new file with mode: 0644]
ext/dsent/util/Config.cc [new file with mode: 0644]
ext/dsent/util/Config.h [new file with mode: 0644]
ext/dsent/util/Constants.cc [new file with mode: 0644]
ext/dsent/util/Constants.h [new file with mode: 0644]
ext/dsent/util/Result.cc [new file with mode: 0644]
ext/dsent/util/Result.h [new file with mode: 0644]

diff --git a/ext/dsent/DSENT.cc b/ext/dsent/DSENT.cc
new file mode 100644 (file)
index 0000000..576cbbe
--- /dev/null
@@ -0,0 +1,423 @@
+#include "DSENT.h"
+
+#include <cstdlib>
+#include <iostream>
+
+namespace DSENT
+{
+    Model* DSENT::ms_model_ = NULL;
+    bool DSENT::ms_is_verbose_ = false;
+
+    void DSENT::run(int argc_, char** argv_)
+    {
+        // Initialize DSENT framework (setup log file, config file, ...)
+        initialize(argc_, argv_);
+
+        // Build the specified model in the config file
+        buildModel();
+
+        // Process the specified queries
+        processQuery();
+        // Process the specified evaluation
+        processEvaluate();
+
+        // Finalize DSENT framework (close log file, ...)
+        finalize();
+        return;
+    }
+
+    void DSENT::setRuntimeOptions(OptionParser* option_parser_)
+    {
+        option_parser_->addOption("-cfg", "ConfigFilename", true, "filename", false, "",
+                "Specify the config filename.");
+
+        option_parser_->addOption("-available_models", "IsListModels", false, "", true, "false",
+                "List available DSENT models.");
+
+        option_parser_->addOption("-log", "LogFilename", true, "filename", true, "./dsent.log", 
+                "Specify the log filename.");
+
+        option_parser_->addOption("-overwrite", "OverwriteString", true, "options", true, "",
+                "Overwrite dynamically the options set in the config file. Options are separated by a comma (;).");
+
+        option_parser_->addOption("-overwrite_tech", "OverwriteTechString", true, "options", true, "",
+                "Overwrite dynamically the options set in the technology file. Options are separated by a comma (;).");
+
+        option_parser_->addOption("-print_config", "IsPrintConfig", false, "", true, "false", 
+                "Print the config used at DSENT runtime.");
+
+        option_parser_->addOption("-query", "QueryString", true, "query string", true, "",
+                "Specify the list of items to query. This command is the same as owerwriting the 'QueryString'.");
+
+        option_parser_->addOption("-eval", "EvaluateString", true, "evaluate string", true, "",
+                "Specify the list of statements to evaluate. This command is the same as owerwriting the 'EvaluateString'.");
+
+        option_parser_->addOption("-verbose", "IsVerbose", false, "", true, "false", 
+                "Enable verbose mode which prints out more detailed messages.");
+        return;
+    }
+
+    void DSENT::initialize(int argc_, char** argv_)
+    {
+        OptionParser* option_parser = new OptionParser();
+
+        // Init the option parser and setup available options
+        setRuntimeOptions(option_parser);
+
+        // Parse the options
+        option_parser->parseArguments(argc_, argv_);
+
+        // If -available_models is specified, print out a list of available 
+        // models and exit DSENT.
+        if(option_parser->get("IsListModels").toBool())
+        {
+            ModelGen::printAvailableModels();
+            exit(0);
+        }
+
+        // Init the log file
+        Log::allocate(option_parser->get("LogFilename"));
+
+        // Init the config file
+        Config::allocate(option_parser->get("ConfigFilename"));
+        Config* dsent_config = Config::getSingleton();
+
+        // Overwrite the existing options
+        dsent_config->readString(option_parser->get("OverwriteString"));
+
+        // Overwrite the technology file
+        dsent_config->constructTechModel(option_parser->get("OverwriteTechString"));
+
+        ms_is_verbose_ = option_parser->get("IsVerbose").toBool();
+
+        // Overwrite the query string if it is specified from command line
+        if(option_parser->get("QueryString").size() != 0)
+        {
+            dsent_config->set("QueryString", option_parser->get("QueryString"));
+        }
+        // Overwrite the evaluation string if it is specified from command line
+        if(option_parser->get("EvaluateString").size() != 0)
+        {
+            dsent_config->set("EvaluateString", option_parser->get("EvaluateString"));
+        }
+
+        // Print the config used for this run
+        if(option_parser->get("IsPrintConfig").toBool())
+        {
+            if(ms_is_verbose_)
+            {
+                cout << "Configuration:" << endl;
+                cout << "==============" << endl;
+            }
+            cout << *dsent_config;
+
+            if(ms_is_verbose_)
+            {
+                cout << "==============" << endl;
+            }
+        }
+
+        delete option_parser;
+        return;
+    }
+
+    void DSENT::buildModel()
+    {
+        Config* dsent_config = Config::getSingleton();
+
+        // Create the model specified
+        const String& model_name = dsent_config->get("ModelName");
+        ms_model_ = ModelGen::createModel(model_name, model_name, dsent_config->getTechModel());
+
+        // Construct the model
+        // Read all parameters the model requires
+        const vector<String>* parameter_names = ms_model_->getParameterNames();
+        // For all parameters, grab values from the config file
+        for(vector<String>::const_iterator it = parameter_names->begin(); it != parameter_names->end(); ++it)
+        {
+            const String& parameter_name = *it;
+            // If it exists in the config file, set the parameter
+            if(dsent_config->keyExist(parameter_name))
+            {
+                ms_model_->setParameter(parameter_name, dsent_config->get(parameter_name));
+            }
+        }
+        ms_model_->construct();
+
+        // Update the model
+        // Read all properties the model requires
+        const vector<String>* property_names = ms_model_->getPropertyNames();
+        // For all properties, grab values from the config file
+        for(vector<String>::const_iterator it = property_names->begin(); it != property_names->end(); ++it)
+        {
+            const String& property_name = *it;
+            // If it exists in the config file, set the parameter
+            if(dsent_config->keyExist(property_name))
+            {
+                ms_model_->setProperty(property_name, dsent_config->get(property_name));
+            }
+        }
+        ms_model_->update();
+
+        // Evaluate the model
+        // Perform timing optimization if needed
+        if(dsent_config->getIfKeyExist("IsPerformTimingOptimization", "false").toBool())
+        {
+            performTimingOpt();
+        }
+        ms_model_->evaluate();
+
+        // Report timing if needed
+        if(dsent_config->getIfKeyExist("IsReportTiming", "false").toBool())
+        {
+            reportTiming();
+        }
+
+        return;
+    }
+
+    void DSENT::processQuery()
+    {
+        Config* dsent_config = Config::getSingleton();
+        vector<String> queries = dsent_config->get("QueryString").split(" ;\r\n");
+
+        if(ms_is_verbose_)
+        {
+            cout << "Query results:" << endl;
+            cout << "==============" << endl;
+        }
+
+        for(unsigned int i = 0; i < queries.size(); ++i)
+        {
+            const String& curr_query = queries[i];
+
+            if(ms_is_verbose_)
+            {
+                String str = "Process query: '" + curr_query + "'";
+                cout << str << endl;
+                cout << String(str.size(), '-') << endl;
+            }
+
+            processQuery(curr_query, true);
+
+            if(ms_is_verbose_)
+            {
+                cout << endl;
+            }
+        }
+        if(ms_is_verbose_)
+        {
+            cout << "==============" << endl;
+        }
+        return;
+    }
+
+    const void* DSENT::processQuery(const String& query_str_, bool is_print_)
+    {
+        vector<String> type_split = query_str_.splitByString(Model::TYPE_SEPARATOR);
+        ASSERT((type_split.size() == 2), "[Error] Invalid query format: " + query_str_);
+        String query_type = type_split[0];
+
+        vector<String> detail_split = type_split[1].splitByString(Model::DETAIL_SEPARATOR);
+        ASSERT((detail_split.size() == 2), "[Error] Invalid query format: " + query_str_);
+        String query_detail = detail_split[1];
+
+        vector<String> subfield_split = detail_split[0].splitByString(Model::SUBFIELD_SEPARATOR);
+        ASSERT(((subfield_split.size() == 2) || (subfield_split.size() == 1)), "[Error] Invalid query format: " + query_str_);
+        String query_hier = subfield_split[0];
+        String query_subfield = "";
+        if(subfield_split.size() == 2)
+        {
+            query_subfield = subfield_split[1];
+        }
+
+        const void* query_result = ms_model_->parseQuery(query_type, query_hier, query_subfield);
+        if(query_type == "Property")
+        {
+            const PropertyMap* property = (const PropertyMap*)query_result;
+            if(is_print_)
+            {
+                cout << *property;
+            }
+        }
+        else if(query_type == "Parameter")
+        {
+            const ParameterMap* parameter = (const ParameterMap*)query_result;
+            if(is_print_)
+            {
+                cout << *parameter;
+            }
+        }
+        else if(query_type.contain("Hier"))
+        {
+            const Model* model = (const Model*)query_result;
+            if(is_print_)
+            {
+                model->printHierarchy(query_type, query_subfield, "", query_detail, cout);
+            }
+        }
+        else
+        {
+            const Result* result = (const Result*)query_result;
+            if(is_print_)
+            {
+                result->print(query_type + Model::TYPE_SEPARATOR + query_hier + 
+                        Model::SUBFIELD_SEPARATOR + query_subfield, query_detail, cout);
+            }
+        }
+        return query_result;
+    }
+
+    void DSENT::finalize()
+    {
+        // Release the constructed model
+        delete ms_model_;
+        ms_model_ = NULL;
+
+        // Release the config file
+        Config::release();
+
+        // Release the log file
+        Log::release();
+
+        return;
+    }
+
+    void DSENT::performTimingOpt()
+    {
+        Config* dsent_config = Config::getSingleton();
+
+        // Get the frequency it is optimizing to
+        double freq = dsent_config->get("Frequency").toDouble();
+
+        // Get all the starting net names
+        const vector<String>& start_net_names = dsent_config->get("TimingOptimization->StartNetNames").split("[,]");
+
+        ASSERT((start_net_names.size() > 0), "[Error] Expecting net names in TimingOptimization->StartNetNames");
+
+        if(start_net_names[0] == "*")
+        {
+            // Optimize from all input ports
+            ElectricalModel* electrical_model = (ElectricalModel*)ms_model_;
+
+            ElectricalTimingOptimizer timing_optimizer("Optimizer", electrical_model->getTechModel());
+            timing_optimizer.setModel(electrical_model);
+            timing_optimizer.construct();
+            timing_optimizer.update();
+
+            ElectricalTimingTree timing_tree(timing_optimizer.getInstanceName(), &timing_optimizer);
+
+            const Map<PortInfo*>* input_ports = timing_optimizer.getInputs();
+            Map<PortInfo*>::ConstIterator it_begin = input_ports->begin();
+            Map<PortInfo*>::ConstIterator it_end = input_ports->end();
+            Map<PortInfo*>::ConstIterator it;
+            for(it = it_begin; it != it_end; ++it)
+            {
+                const String& net_name = it->first;
+                Log::printLine("Optimizing net: " + net_name);
+                timing_tree.performTimingOpt(timing_optimizer.getNet(net_name, makeNetIndex(0)), 1.0 / freq);
+                //timing_tree.performTimingOpt(electrical_model->getNet(net_name, makeNetIndex(0)), 1.0 / freq);
+            }
+            // Loop the second times 
+            for(it = it_begin; it != it_end; ++it)
+            {
+                const String& net_name = it->first;
+                Log::printLine("Optimizing net: " + net_name);
+                //timing_tree.performTimingOpt(timing_optimizer.getNet(net_name, makeNetIndex(0)), 1.0 / freq);
+            }
+        }
+        else
+        {
+            // TODO : parse the net name so that we could do hierarchical optimization
+            // Currently we can only optimize timing at the top level
+            ElectricalModel* electrical_model = (ElectricalModel*)ms_model_;
+            ElectricalTimingTree timing_tree(electrical_model->getInstanceName(), electrical_model);
+            for(unsigned int i = 0; i < start_net_names.size(); ++i)
+            {
+                const String& net_name = start_net_names[i];
+                timing_tree.performTimingOpt(electrical_model->getNet(net_name), 1.0 / freq);
+            }
+        }
+        return;
+    }
+
+    void DSENT::reportTiming()
+    {
+        Config* dsent_config = Config::getSingleton();
+
+        // Get all the starting net names
+        const vector<String>& start_net_names = dsent_config->get("ReportTiming->StartNetNames").split("[,]");
+
+        ElectricalModel* electrical_model = (ElectricalModel*)ms_model_;
+        ElectricalTimingTree timing_tree(electrical_model->getInstanceName(), electrical_model);
+
+        cout << "Report timing:" << endl;
+        cout << "==============" << endl;
+        for(unsigned int i = 0; i < start_net_names.size(); ++i)
+        {
+            const String& net_name = start_net_names[i];
+            double timing = timing_tree.performCritPathExtract(electrical_model->getNet(net_name));
+            cout << net_name << " = " << timing << endl;
+        }
+        cout << "==============" << endl;
+        return;
+    }
+
+    void DSENT::processEvaluate()
+    {
+        Config* dsent_config = Config::getSingleton();
+
+        // Return if EvaluatString is empty or not exists
+        if(!dsent_config->keyExist("EvaluateString")) return;
+
+        String eval_str = dsent_config->get("EvaluateString");
+
+        if(eval_str == "") return;
+
+        if(ms_is_verbose_)
+        {
+            cout << "Eval results:" << endl;
+            cout << "==============" << endl;
+        }
+
+        //if(ms_is_verbose_)
+        //{
+        //    String str = "Process evaluation: '" + eval_str + "'";
+        //    cout << str << endl;
+        //    cout << String(str.size(), '-') << endl;
+        //}
+        DSENTCalculator calc;
+        calc.evaluateString(eval_str);
+
+        if(ms_is_verbose_)
+        {
+            cout << "==============" << endl;
+        }
+        return;
+        return;
+    }
+
+    DSENT::DSENTCalculator::DSENTCalculator()
+    {}
+
+    DSENT::DSENTCalculator::~DSENTCalculator()
+    {}
+
+    double DSENT::DSENTCalculator::getEnvVar(const String& var_name_) const
+    {
+        if(m_var_.keyExist(var_name_))
+        {
+            return m_var_.get(var_name_);
+        }
+        else if(Config::getSingleton()->keyExist(var_name_))
+        {
+            return Config::getSingleton()->get(var_name_);
+        }
+        else
+        {
+            const Result* result = (const Result*)DSENT::processQuery(var_name_ + "@0", false);
+            return result->calculateSum();
+        }
+    }
+} // namespace DSENT
+
diff --git a/ext/dsent/DSENT.h b/ext/dsent/DSENT.h
new file mode 100644 (file)
index 0000000..42abb98
--- /dev/null
@@ -0,0 +1,64 @@
+#ifndef __DSENT_DSENT_H__
+#define __DSENT_DSENT_H__
+
+// For DSENT operations
+#include "libutil/OptionParser.h"
+#include "libutil/Calculator.h"
+#include "util/CommonType.h"
+#include "util/Config.h"
+#include "util/Result.h"
+#include "model/Model.h"
+#include "model/ModelGen.h"
+
+// For timing optimization
+#include "model/ElectricalModel.h"
+#include "model/timing_graph/ElectricalNet.h"
+#include "model/timing_graph/ElectricalTimingTree.h"
+#include "model/timing_graph/ElectricalTimingOptimizer.h"
+#include "model/PortInfo.h"
+
+namespace DSENT
+{
+    using LibUtil::OptionParser;
+    using LibUtil::Calculator;
+
+    class DSENT
+    {
+        protected:
+            class DSENTCalculator : public Calculator
+            {
+                public:
+                    DSENTCalculator();
+                    virtual ~DSENTCalculator();
+        
+                protected:
+                    virtual double getEnvVar(const String& var_name_) const;
+            }; // class DSENTCalculator
+
+        public:
+            static void run(int argc_, char** argv_);
+
+        protected:
+            static void setRuntimeOptions(OptionParser* option_parser_);
+            static void initialize(int argc_, char** argv_);
+            static void buildModel();
+            static void processQuery();
+            static const void* processQuery(const String& query_str_, bool is_print_);
+            static void finalize();
+
+            static void performTimingOpt();
+            static void reportTiming();
+
+            static void processEvaluate();
+
+        protected:
+            static Model* ms_model_;
+
+            static bool ms_is_verbose_;
+
+    }; // class DSENT
+
+} // namespace DSENT
+
+#endif // __DSENT_DSENT_H__
+
diff --git a/ext/dsent/LICENSE b/ext/dsent/LICENSE
new file mode 100644 (file)
index 0000000..eef8c88
--- /dev/null
@@ -0,0 +1,19 @@
+Copyright (c) 2012 Massachusetts Institute of Technology
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
\ No newline at end of file
diff --git a/ext/dsent/Makefile b/ext/dsent/Makefile
new file mode 100644 (file)
index 0000000..1241883
--- /dev/null
@@ -0,0 +1,55 @@
+
+# Define the directories that will be compiled
+DIRS_TO_COMPILE := util tech io \
+                   model model/timing_graph \
+                   model/std_cells \
+                   model/electrical \
+                   model/electrical/router \
+                   model/optical \
+                   model/optical_graph \
+                   model/network \
+                   model/network/ATAC
+
+DIRS = $(patsubst %,$(CURDIR)/%,$(DIRS_TO_COMPILE))
+
+SRCS = $(foreach dir, $(DIRS), $(wildcard $(dir)/*.cc))
+
+OBJS = $(SRCS:%.cc=%.o)
+
+DEF_FLAGS = 
+INCLUDE_FLAGS = -I$(CURDIR)
+OPT_FLAGS = -O2 -g 
+WARN_FLAGS = -pedantic -Wall -W #-Wextra -Werror -Wno-write-strings
+CXXFLAGS = $(OPT_FLAGS) $(WARN_FLAGS) $(INCLUDE_FLAGS) $(DEF_FLAGS)
+
+LD_LIBS += -lutil
+LD_FLAGS += -Llibutil
+
+# Other libraries used 
+LIB_UTIL = libutil/libutil.a
+
+#TARGET = $(CURDIR)/libdsent.a
+TARGET = $(CURDIR)/dsent
+
+all: $(TARGET)
+
+#$(TARGET): $(OBJS)
+#      ar rcs $@ $^
+$(TARGET): main.o DSENT.o $(LIB_UTIL) $(OBJS) 
+       $(CXX) $(CXXFLAGS) $(LD_FLAGS) $(OBJS) main.o DSENT.o -o $(TARGET) $(LD_LIBS) 
+
+# For general c++ compilation
+%.o: %.cc
+       $(CXX) $(CXXFLAGS) -c $< -o $@
+
+$(LIB_UTIL):
+       $(MAKE) -C $(CURDIR)/libutil
+
+%/created:
+       mkdir -p $(dir $@)
+       touch $@
+
+.phony: clean
+clean:
+       $(RM) -rf main.o DSENT.o $(OBJS) $(TARGET)
+       $(MAKE) -C $(CURDIR)/libutil clean
diff --git a/ext/dsent/README b/ext/dsent/README
new file mode 100644 (file)
index 0000000..0143a43
--- /dev/null
@@ -0,0 +1,374 @@
+DSENT (Design Space Exploration of Networks Tool)
+
+===============================================================================
+Overview
+===============================================================================
+DSENT is a modeling tool designed for rapid design space exploration of both
+electronical and emerging opto-electrical networks-on-chip (NoC). It provides
+analytic and parameterized models for various network components and is
+portable across a range of technology assumptions. Given architectural-level
+parameters, DSENT builds the specified models hierarchically from electrical
+and optical building blocks and outputs detailed power and area estimates. 
+
+
+===============================================================================
+Version
+===============================================================================
+Current: 0.91 (26 June 2012)
+
+Latest version or additional information can be found at
+
+    https://sites.google.com/site/mitdsent
+
+===============================================================================
+System requirements
+===============================================================================
+We have tested DSENT on the following platforms:
+
+Linux GNU g++ 4.1.2 and glibc 2.5
+Linux GNU g++ 4.3.2 and glibc 2.7
+Linux GNU g++ 4.4.5 and glibc 2.11.3
+Cygwin g++ 4.5.3 and cygwin 1.7.14
+
+===============================================================================
+License
+===============================================================================
+Please refer to the LICENSE file for licensing and copyright information.
+
+If you use DSENT in your research, please acknowledge us by referencing our 
+NOCS 2012 paper:
+
+Chen Sun, Chia-Hsin Owen Chen, George Kurian, Lan Wei, Jason Miller, 
+Anant Agarwal, Li-Shiuan Peh, Vladimir Stojanovic, "DSENT - A Tool Connecting 
+Emerging Photonics with Electronics for Opto-Electronic Networks-on-Chip 
+Modeling." The 6th ACM/IEEE International Symposium on Networks-on-Chip 
+(NOCS), May 2012, Lyngby, Denmark.
+
+
+===============================================================================
+Contact information
+===============================================================================
+If you have any questions or comments, please contact us through our mailing
+list at: mitdsent@mit.edu 
+
+We will try to reply as soon as possible.
+
+
+===============================================================================
+Build (installation)
+===============================================================================
+To build DSENT:
+
+    % make 
+
+By default DSENT is built with logging disabled. Logging keeps track of what 
+happens while running DSENT. It is an option more for the DSENT framework and 
+DSNET models developers. If you want to enable this option, simply type the 
+following: 
+
+    % make LIBUTIL_IS_LOG=true
+
+To clean the build: 
+
+    % make clean
+
+
+===============================================================================
+Usage
+===============================================================================
+DSENT builds models and runs based on the specified configuration file. In the 
+configuration file, you specify a model name and necessary information 
+(parameters and properties) required to build the model.
+
+To run DSENT:
+
+    % ./dsent -cfg <config_filename>
+
+To check what models are available:
+
+    % ./dsent -available_models
+
+To overwrite the configuration file from command line:
+    Use ';' to separate different key/value pairs. 
+
+    % ./dsent -cfg <config_filename> -overwrite <new query string>
+    % ./dsent -cfg configs/example.cfg -overwrite "NumberInputs=5; NumberOutputs=6;"
+
+To print out in a more human-friendly fasion:
+
+    % ./dsent -cfg <config_filename> -verbose
+
+To check what options are available:
+
+    % ./dsent -help
+
+Please see configs/example.cfg for an example of a configuration file.
+
+Please see configs/router.cfg for the router configuration file. 
+
+Please see QueryString and EvaluateString specifications below to know more 
+about the usage.
+
+===============================================================================
+Advanced Usage
+===============================================================================
+Since DSENT is a generic modeling framework for electrical and optical 
+components, you can create your own models. We will release guidelines on how 
+to create custom models on top of DSENT framework. You can use the provided 
+models as references.
+
+
+===============================================================================
+Quick start for Orion users
+===============================================================================
+Instead of using the SIM_port.h file, DSENT uses a text-based configuration 
+file to specify the router/link configurations. You do not need to recompile
+if you change parameters. Even though we use different parameter names, the
+ones we use should be self-explanatory. In this package, we provide template
+configuration files for the router and link:
+
+    router  - configs/router.cfg
+    link    - configs/electrical-link.cfg
+
+    Technology
+    ----------
+        We currently support 45, 32, 22, 11nm. You can specify the desired 
+        frequency but not the nominal voltage level since it is normally 
+        fixed in different processes. 
+
+    Router specs
+    ------------
+        Currently we only support the model of a widely used 3-pipeline-stage 
+        input-buffered virtual channel router and does not have distinction 
+        from ports for different components (cache, memory controller, I/O). 
+
+    Input buffer specs
+    ------------------
+        The number of virtual channels used for different message classes 
+        might be different; hence, DSENT uses NumberVirtualNetworks to 
+        specify the number of message classes and use 
+        NumberVirtualChannelsPerVirtualNetwork and 
+        NumberBuffersPerVirtualChannel to define the buffers needed for a  
+        virtual network (message class). 
+
+        Currently only DFF-based RAM is supports. This is reasonable since 
+        normally the buffer space needed at input port is small enough and 
+        does not need to use SRAMs or RFs (register files). 
+
+    Crossbar specs
+    --------------
+        Currently DSENT only supports multiplexer-based crossbars 
+        (MULTREE_CROSSBAR). You no longer need to specify the degree of the
+        multiplexers. 
+
+    Switch allocator specs
+    ----------------------
+        DSENT models a two-stage switch allocator. The first stage is used to 
+        arbitrate between VCs in the same input port, and the second stage is 
+        used to arbitrate between input ports. If there is only one VC in 
+        the input port, then the energy/power/area cost for the first stage 
+        will be zero. 
+        
+        Currently, DSENT supports MatrixArbiter. 
+
+    VC allocator specs
+    ------------------
+        We assume that the router uses a VC select scheme where the VC 
+        allocation is done by just popping a FIFO. Currently DSENT ignores 
+        this module since the FIFO that needs to keep the free VC information 
+        should be small enough. 
+
+    Clock distribution specs
+    ------------------------
+        Currently DSENT provides a broadcast H-Tree model. You can specify 
+        the number of levels of the H-Tree (normally 4 or 5 levels should be 
+        enough). 
+
+DSENT replaces the original orion_router_power, orion_router_area and 
+orion_link with QueryString and EvaluateString (see below for more detailed 
+information on how to use them). 
+
+
+===============================================================================
+QueryString specifications
+===============================================================================
+DSENT is a query-based model evaluator. You use QueryString to specify what 
+information you want DSENT to output. The syntax of a query string is shown as 
+follows: 
+
+    [Query type]>>[Instance name (with hierarchy)]:[Sub query type]@[Detail level]
+
+    E.g., Area>>Router->Crossbar:Active@4
+        * Query type:       Area
+        * Instance name:    Router->Crossbar
+        * Sub query type:   Active
+        * Detail level:     4
+
+    Query type
+    ----------
+        There are 9 types of queries: Parameter, Property, Energy, NddPower, 
+        Area, InstHier, EventHier, NddPowerHier, AreaHier. 
+
+        Parameter       - Print the model parameters needed to be specified 
+        Property        - Print the design constraints or utilization 
+            Use these to check what needs to be specified in the configuration 
+            file for the model. No sub query type is needed for these two 
+            types. 
+
+        Energy          - Print the data-dependent energy cost of an event
+        NddPower        - Print the non-data-denepent power of an instance
+        Area            - Print the area cost of an instance
+            Use these to obtain the costs of the specified model.
+
+        InstHier        - Print the instance name hierarchy
+            Use this to know what sub-instances are built for this model
+
+        EventHier       - Print the available events for Energy queries
+        NddPowerHier    - Print the available non-data-dependent power types
+        AreaHier        - Print the available area types
+            Use this to know what to specify in the "sub query type" field. 
+
+    Instance name (with hierarchy)
+    ------------------------------
+        The (sub)instance that you want to perform query. The name should be 
+        hierarchical starting from the top level model. Hierarchies are 
+        separated by the symbol "->".
+
+    Sub query type
+    --------------
+        This field is not required for 'Parameter', 'Property' and 'InstHier'.
+
+        For 'Energy', this field stands for the event that cause this energy 
+        cost, such as 'WriteBuffer'. 
+
+        For 'NddPower' and 'Area', this field stands for the power and area 
+        cost of the model, such as 'Leakage' and 'Active'. 
+
+        For 'EventHier', if this field is not specified, all events of this 
+        instance will be printed; if this field is specified, then only 
+        the specified event will be printed. 'AreaHier' and 'NddPowerHier' 
+        also have the similar behavior. 
+        
+    Detail level
+    ------------
+        Defines the hierarchy depth to be printed. '0' means current level. 
+        This field is needed for all query types for syntax correctness, 
+        although it is not used for 'Parameter' and 'Property'. 
+
+    Multi-line queries
+    ------------------
+        Query strings specified across multiple lines in the config file
+        must have each line be terminated by a '\'. It is whitespace sensitive,
+        so make sure there are no spaces after '\'. Note that the parser
+        prunes everything after the comment '#' character, including '\'!
+        See configs/router.cfg as an example.
+
+    Examples of individual QueryString's:
+
+        Parameter>>Router@0
+        Property>>Router->Crossbar@0
+        InstHier>>Router->InputPort@2
+        Energy>>Router:WriteBuffer@2
+        NddPower>>Router->Crossbar:Leakage@3
+        Area>>Router->SwitchAllocator:Active@4
+
+        
+===============================================================================
+EvaluateString specifications
+===============================================================================
+DSENT provides a way to let users do custom calculations by specifying the 
+EvaluateString in the configuration file. EvaluateString constains a sequence 
+of statements separated by one ';'. DSENT reads through the sequence and 
+evaluates the statements one-by-one. 
+
+Currently, DSENT supports:
+    Four arithmetic operations
+    --------------------------
+        3 + 4 * (5 + 6) / 7;
+
+    Define local variables through assignments
+    ------------------------------------------
+        variable 'a' will be mapped to 7 for future referencing
+
+        a = 3 + 4;
+
+    Global variable referencing
+    ---------------------------
+        $(var_name) indicates either a key in the configuration file or a 
+        query string. If var_name exists in the configuration file, then the 
+        corresponding value will be returned; otherwise, DSENT will do a query 
+        using the string var_name@0 and return the query result. 
+
+        b = $(Energy>>Router:WriteBuffer) * $(Frequency);
+
+    Printing outputs
+    ----------------
+        DSENT prints the string following the keyword 'print'. 
+
+        print <expression>
+        print "<string_to_print>";
+        print "<string_to_print>" <expression>;
+
+        print 3 + 4;                # Output: 7
+        print "Hello World";        # Output: Hello World
+        print "Hello World " 3 + 4; # Output: Hello World 7
+        
+    Multi-line evaluate strings
+    ---------------------------
+        Evaluate strings specified across multiple lines in the config file
+        must have each line be terminated by a '\'. It is whitespace sensitive,
+        so make sure there are no spaces after '\'. Note that the parser
+        prunes everything after the comment '#' character, including '\'!
+        See configs/router.cfg as an example.
+
+        
+===============================================================================
+Units
+===============================================================================
+DSENT uses only SI units for all inputs and outputs. For example:
+    time        = s (second)
+    distance    = m (meter)
+    capacitance = F (Farad)
+    power       = W (Watt)
+    energy      = J (Joule)
+    resistance  = Ohm
+    loss        = dB (Decibels)
+
+    
+===============================================================================
+Known Bugs and Issues
+===============================================================================
+
+1. If timing is not met, the timing optimizer will put the model in a state
+where everything is the maximum size (huge power, area). Thus, model results
+can be considered a gross over-estimate when timing isn't met. This is just the
+nature of the greedy timing optimizer and it will be addressed in the future.
+
+2. The VC control and credit buffer component of the router is currently
+not modeled, as they have always been assumed to be lumped into the "negligible
+control cost" category in previous models and evaluations. Our recent
+experiments have shown that this is not true and we will be adding this in the
+next iteration.
+
+3. Some of the connectivity paths have not been checked thoroughly. Thus,
+timing optimizer may miss some of the paths. However, we tried to make sure
+that the critical paths are modeled properly.
+
+4. Local interconnect will have an ever-larger impact on power and timing as
+technology scales. So far we have not implemented a method for automatically
+estimating them but we will eventually address this. Evaluations for 22nm
+and below will tend to underestimate as a result.
+
+===============================================================================
+Revision log
+===============================================================================
+V0.91:
+    Bugs fix:
+        1. Leakage power calculation printout for router (configs/router.cfg).
+
+    New feature:
+        1. Area printout for router (configs/router.cfg).
+
+V0.9:
+    First release.
+
diff --git a/ext/dsent/configs/electrical-clos.cfg b/ext/dsent/configs/electrical-clos.cfg
new file mode 100644 (file)
index 0000000..29888f7
--- /dev/null
@@ -0,0 +1,84 @@
+
+# Instance
+ModelName = ElectricalClos
+
+# Query string used to choose what will be output by Orion
+QueryString = \
+    Energy>>ElectricalClos:AvgUnicast@1 \
+    NddPower>>ElectricalClos:Leakage@0 \
+    Area>>ElectricalClos:Active@0 \
+    Area>>ElectricalClos:GlobalWire@0 \
+
+# Injection rate (# flits per cycle per site), assuming that the network is not
+# saturated and uniform random traffic
+InjectionRate                           = 0.1
+# Evaluation string
+EvaluateString                          = \
+    dynamic         = $(InjectionRate) * $(NumberInputSites) * $(Frequency) * $(Energy>>ElectricalClos:AvgUnicast); \
+    leakage         = $(NddPower>>ElectricalClos:Leakage); \
+    total           = dynamic + leakage; \
+    energy_per_bit  = total / ($(InjectionRate) * $(Frequency) * $(NumberInputSites) * $(NumberBitsPerFlit)); \
+    active_area     = $(Area>>ElectricalClos:Active); \
+    global_area     = $(Area>>ElectricalClos:GlobalWire); \
+    print "Electrical Clos Network:"; \
+    print "    Dynamic power: " dynamic; \
+    print "    Leakage power: " leakage; \
+    print "    Total power: " total; \
+    print "    Energy per bit: " energy_per_bit; \
+    print "    Global Wire Area: " global_area; \
+    print "    Active Area: " active_area; \
+    
+# Technology file (see other models in tech/models)
+ElectricalTechModelFilename             = tech/tech_models/Bulk45LVT.model
+
+###############################################################################
+# Timing optimization
+###############################################################################
+
+# Individual network components already optimize for timing, no need to do it
+# at the top-level
+# Operating frequency (Hz)
+Frequency                                       = 1.0e9
+
+# Report timing
+IsReportTiming                                  = true
+# Report timing
+ReportTiming->StartNetNames                     = [CK]
+
+###############################################################################
+# Model specifications
+###############################################################################
+
+# Clos Parameters
+# Number of sites that can send
+NumberInputSites                                = 64
+# Number of sites that can receive
+NumberOutputSites                               = 64
+# Bits per flit
+NumberBitsPerFlit                               = 64
+# Number of routers at each stage
+NumberIngressRouters                            = 8
+NumberMiddleRouters                             = 8
+NumberEgressRouters                             = 8
+
+# Router-specific parameters (see dsent.cfg.router for descriptions)
+Router->NumberVirtualNetworks                   = 3
+Router->NumberVirtualChannelsPerVirtualNetwork  = [1,1,1]
+Router->NumberBuffersPerVirtualChannel          = [4,1,1]
+Router->InputPort->BufferModel                  = DFFRAM
+Router->CrossbarModel                           = MultiplexerCrossbar
+Router->SwitchAllocator->ArbiterModel           = MatrixArbiter
+Router->ClockTreeModel                          = BroadcastHTree
+Router->ClockTree->NumberLevels                 = 6
+Router->ClockTree->WireLayer                    = Intermediate
+Router->ClockTree->WireWidthMultiplier          = 1.0
+
+# Electrical Link-specific parameters
+Link->WireLayer                                 = Global
+Link->WireWidthMultiplier                       = 1.0
+Link->WireSpacingMultiplier                     = 1.0
+
+# Physical organization properties
+# Note: This model assumes a square network layout
+InputSitePitch                                  = 1e-3
+OutputSitePitch                                 = 1e-3
\ No newline at end of file
diff --git a/ext/dsent/configs/electrical-link.cfg b/ext/dsent/configs/electrical-link.cfg
new file mode 100644 (file)
index 0000000..8369b86
--- /dev/null
@@ -0,0 +1,57 @@
+
+# Name of model to be built and evaluated
+ModelName                               = RepeatedLink
+
+# Query string to choose what to evaluate (use '\' to enable multiline config)
+QueryString                             = \
+    Energy>>RepeatedLink:Send@0 \
+    NddPower>>RepeatedLink:Leakage@0 \
+    Area>>RepeatedLink:Active@0 \
+
+# Injection rate
+InjectionRate                           = 0.3
+# Evaluation string
+EvaluateString                          = \
+    link_dynamic    = $(Energy>>RepeatedLink:Send) * $(Frequency); \
+    link_static     = $(NddPower>>RepeatedLink:Leakage); \
+    print "Link:"; \
+    print "    Dynamic power: " link_dynamic * $(InjectionRate); \
+    print "    Leakage power: " link_static; \
+
+# Technology file (see models in tech/models)
+ElectricalTechModelFilename             = tech/tech_models/Bulk45LVT.model
+
+###############################################################################
+# Timing optimization
+###############################################################################
+
+# True if want to perform timing optimization; otherwise, false.
+# NOTE: for links it should never be turned on for timing optimization, the 
+# link model is already doing timing optimization to insert buffers based on 
+# the 'Delay' specified
+IsPerformTimingOptimization             = false
+# Nets that the timing optimizer starts from
+TimingOptimization->StartNetNames       = []
+# Operating frequency (Hz)
+# 'Frequency' has no effect to the RepeatedLink model. Use 'Delay' to 
+# constraint the links timing. 
+Frequency                               = 1e9
+
+###############################################################################
+# Model specifications
+###############################################################################
+
+# Data width of the repeated link/bus
+NumberBits                              = 64
+# Wire layer
+WireLayer                               = Global
+# Wire width multiplier
+WireWidthMultiplier                     = 1.0
+# Wire spacing multiplier
+WireSpacingMultiplier                   = 1.0
+
+# Wire length (m)
+WireLength                              = 1e-3
+# Delay of the wire (may not be 1.0 / Frequency)
+Delay                                   = 1e-9
+
diff --git a/ext/dsent/configs/electrical-mesh.cfg b/ext/dsent/configs/electrical-mesh.cfg
new file mode 100644 (file)
index 0000000..929e4f1
--- /dev/null
@@ -0,0 +1,81 @@
+
+# Instance
+ModelName = ElectricalMesh
+
+# Query string used to choose what will be output by Orion
+QueryString = \
+    Energy>>ElectricalMesh:AvgUnicast@0 \
+    NddPower>>ElectricalMesh:Leakage@0 \
+    Area>>ElectricalMesh:Active@0 \
+    Area>>ElectricalMesh:GlobalWire@0 \
+
+# Injection rate (# flits per cycle per site), assuming that the network is not
+# saturated and uniform random traffic
+InjectionRate                           = 0.1
+# Evaluation string
+EvaluateString                          = \
+    dynamic         = $(InjectionRate) * $(NumberSites) * $(Frequency) * $(Energy>>ElectricalMesh:AvgUnicast); \
+    leakage         = $(NddPower>>ElectricalMesh:Leakage); \
+    total           = dynamic + leakage; \
+    energy_per_bit  = total / ($(InjectionRate) * $(Frequency) * $(NumberSites) * $(NumberBitsPerFlit)); \
+    active_area     = $(Area>>ElectricalMesh:Active); \
+    global_area     = $(Area>>ElectricalMesh:GlobalWire); \
+    print "Electrical Mesh Network:"; \
+    print "    Dynamic power: " dynamic; \
+    print "    Leakage power: " leakage; \
+    print "    Total power: " total; \
+    print "    Energy per bit: " energy_per_bit; \
+    print "    Global Wire Area: " global_area; \
+    print "    Active Area: " active_area; \
+    
+# Technology file (see other models in tech/models)
+ElectricalTechModelFilename             = tech/tech_models/Bulk45LVT.model
+
+###############################################################################
+# Timing optimization
+###############################################################################
+
+# Individual network components already optimize for timing, no need to do it
+# at the top-level
+# Operating frequency (Hz)
+Frequency                                       = 1.0e9
+
+# NOTE: If you adjust Frequency, make sure you adjust SWSR->LinkDataRate
+# to make sure it is >= Frequency, since the model doesn't support serialization
+# ratios < 1.
+
+# Report timing
+IsReportTiming                                  = true
+# Report timing
+ReportTiming->StartNetNames                     = [CK]
+
+###############################################################################
+# Model specifications
+###############################################################################
+
+# Mesh Parameters
+ClockFrequency                                  = 1e9
+NumberSites                                     = 64
+NumberBitsPerFlit                               = 64
+NumberSitesPerRouter                            = 1
+
+# Router-specific parameters (see dsent.cfg.router for descriptions)
+Router->NumberVirtualNetworks                   = 3
+Router->NumberVirtualChannelsPerVirtualNetwork  = [1,1,1]
+Router->NumberBuffersPerVirtualChannel          = [4,1,1]
+Router->InputPort->BufferModel                  = DFFRAM
+Router->CrossbarModel                           = MultiplexerCrossbar
+Router->SwitchAllocator->ArbiterModel           = MatrixArbiter
+Router->ClockTreeModel                          = BroadcastHTree
+Router->ClockTree->NumberLevels                 = 6
+Router->ClockTree->WireLayer                    = Intermediate
+Router->ClockTree->WireWidthMultiplier          = 1.0
+
+# Electrical Link-specific parameters
+Link->WireLayer                                 = Global
+Link->WireWidthMultiplier                       = 1.0
+Link->WireSpacingMultiplier                     = 1.0
+
+# Physical organization properties
+# Note: This model assumes a square network layout
+SitePitch                                       = 1e-3
diff --git a/ext/dsent/configs/example.cfg b/ext/dsent/configs/example.cfg
new file mode 100644 (file)
index 0000000..9e147b2
--- /dev/null
@@ -0,0 +1,40 @@
+
+# Example using a crossbar
+# % ./dsent -cfg configs/example.example -verbose
+
+
+# Name of model to be built and evaluated
+ModelName                               = MultiplexerCrossbar
+
+# Query string to choose what to evaluate (use '\' to enable multiline config)
+QueryString                             = \
+    Energy>>MultiplexerCrossbar:Multicast1@0 \
+    Energy>>MultiplexerCrossbar:Multicast1@2 \
+    NddPower>>MultiplexerCrossbar:Leakage@1 \
+    Area>>MultiplexerCrossbar:Active@1
+
+# Technology file (see models in tech/tech_models)
+ElectricalTechModelFilename             = tech/tech_models/Bulk45LVT.model
+
+###############################################################################
+# Timing optimization
+###############################################################################
+
+# True if want to perform timing optimization; otherwise, false.
+IsPerformTimingOptimization             = true
+# Nets that the timing optimizer starts from
+TimingOptimization->StartNetNames       = [*]       # '*' means from all inputs
+# Operating frequency (Hz)
+Frequency                               = 2e9
+
+###############################################################################
+# Model specifications
+###############################################################################
+
+# Number of inputs
+NumberInputs                            = 4
+# Number of outputs
+NumberOutputs                           = 4
+# Number of bits per input/output
+NumberBits                              = 64
+
diff --git a/ext/dsent/configs/photonic-clos.cfg b/ext/dsent/configs/photonic-clos.cfg
new file mode 100644 (file)
index 0000000..252b49a
--- /dev/null
@@ -0,0 +1,112 @@
+
+# Name of model to be built and evaluated
+ModelName = PhotonicClos
+
+# Query string to choose what to evaluate (use '\' to enable multiline config)
+QueryString = \
+    Energy>>PhotonicClos:AvgUnicast@1 \
+    NddPower>>PhotonicClos:RingTuning@0 \
+    NddPower>>PhotonicClos:Laser@0 \
+    NddPower>>PhotonicClos:Leakage@0 \
+    Area>>PhotonicClos:Active@0 \
+    Area>>PhotonicClos:GlobalWire@0 \
+    Area>>PhotonicClos:Photonic@0 \
+    
+# Injection rate (# flits per cycle per site), assuming that the network is not
+# saturated and uniform random traffic
+InjectionRate                           = 0.1
+# Evaluation string
+EvaluateString                          = \
+    dynamic         = $(InjectionRate) * $(NumberInputSites) * $(Frequency) * $(Energy>>PhotonicClos:AvgUnicast); \
+    leakage         = $(NddPower>>PhotonicClos:Leakage); \
+    ring_heating    = $(NddPower>>PhotonicClos:RingTuning); \
+    laser           = $(NddPower>>PhotonicClos:Laser); \
+    total           = dynamic + leakage + ring_heating + laser; \
+    energy_per_bit  = total / ($(InjectionRate) * $(Frequency) * $(NumberInputSites) * $(NumberBitsPerFlit)); \
+    active_area     = $(Area>>PhotonicClos:Active); \
+    global_area     = $(Area>>PhotonicClos:GlobalWire); \
+    photonic_area   = $(Area>>PhotonicClos:Photonic); \
+    print "Photonic Clos Network:"; \
+    print "    Dynamic power: " dynamic; \
+    print "    Leakage power: " leakage; \
+    print "    Laser power: " laser; \
+    print "    Ring Heater Power: " ring_heating; \
+    print "    Total power: " total; \
+    print "    Energy per bit: " energy_per_bit; \
+    print "    Active Area: " active_area; \
+    print "    Global Wire Area: " global_area; \
+    print "    Photonic Area: " photonic_area; \
+    
+# Technology file (see other models in tech/models)
+ElectricalTechModelFilename             = tech/tech_models/Bulk45LVT.model
+PhotonicTechModelFilename               = tech/tech_models/Photonics.model
+
+###############################################################################
+# Timing optimization
+###############################################################################
+
+# Individual network components already optimize for timing, no need to do it
+# at the top-level
+# Operating frequency (Hz)
+Frequency                                       = 4e9
+
+# NOTE: If you adjust Frequency, make sure you adjust SWSR->LinkDataRate
+# to make sure it is >= Frequency, since the model doesn't support serialization
+# ratios < 1.
+
+# Report timing
+IsReportTiming                                  = true
+# Report timing
+ReportTiming->StartNetNames                     = [CK]
+
+###############################################################################
+# Model specifications
+###############################################################################
+
+# Clos Parameters
+# Number of sites that can send
+NumberInputSites                                = 64
+# Number of sites that can receive
+NumberOutputSites                               = 64
+# Bits per flit
+NumberBitsPerFlit                               = 64
+# Number of routers at each stage
+NumberIngressRouters                            = 8
+NumberMiddleRouters                             = 8
+NumberEgressRouters                             = 8
+
+# Router-specific parameters (see dsent.cfg.router for descriptions)
+Router->NumberVirtualNetworks                   = 3
+Router->NumberVirtualChannelsPerVirtualNetwork  = [1,1,1]
+Router->NumberBuffersPerVirtualChannel          = [4,1,1]
+Router->InputPort->BufferModel                  = DFFRAM
+Router->CrossbarModel                           = MultiplexerCrossbar
+Router->SwitchAllocator->ArbiterModel           = MatrixArbiter
+Router->ClockTreeModel                          = BroadcastHTree
+Router->ClockTree->NumberLevels                 = 6
+Router->ClockTree->WireLayer                    = Intermediate
+Router->ClockTree->WireWidthMultiplier          = 1.0
+
+# Electrical Link-specific parameters
+Link->WireLayer                                 = Global
+Link->WireWidthMultiplier                       = 1.0
+Link->WireSpacingMultiplier                     = 1.0
+
+# Photonic link-specfic parameters
+# Link data rate (Hz), must be >= Frequency of the network
+SWSR->LinkDataRate                              = 4e9
+# Optimize the laser/modulator power balance for the given utilization
+SWSR->OptUtil                                                  = 0.5
+# Type of the laser. Current valid choices are: (Standard, Throttled)
+# Note, if you change this to throttled, the laser gets lumped into dynamic
+# power, so change the Ndd power query for laser appropriately
+SWSR->LaserType                                 = Standard
+# Ring tuning method. Current valid choices are:
+# (FullThermal, AthermalWithTrim, ThermalWithBitReshuffle, ElectricalAssistWithBitReshuffle)
+SWSR->RingTuningMethod                          = ThermalWithBitReshuffle 
+    
+# Physical organization properties
+# Note: This model assumes a square network layout
+InputSitePitch                                  = 1e-3
+OutputSitePitch                                 = 1e-3
+
diff --git a/ext/dsent/configs/photonic-link.cfg b/ext/dsent/configs/photonic-link.cfg
new file mode 100644 (file)
index 0000000..755e38b
--- /dev/null
@@ -0,0 +1,75 @@
+
+# Name of model to be built and evaluated
+ModelName = SWSRLink
+
+# Query string to choose what to evaluate (use '\' to enable multiline config)
+QueryString = \
+    Energy>>SWSRLink:Send@1 \
+    NddPower>>SWSRLink:Leakage@0 \
+    NddPower>>SWSRLink:RingTuning@0 \
+    NddPower>>SWSRLink:Laser@0 \
+    Area>>SWSRLink:Active@0 \
+    Area>>SWSRLink:Photonic@0 \
+    
+# Injection rate (# words per core cycle)
+InjectionRate                           = 1.0
+# Evaluation string
+EvaluateString                          = \
+    dynamic         = $(InjectionRate) * $(CoreDataRate) * $(Energy>>SWSRLink:Send); \
+    leakage         = $(NddPower>>SWSRLink:Leakage); \
+    ring_heating    = $(NddPower>>SWSRLink:RingTuning); \
+    laser           = $(NddPower>>SWSRLink:Laser); \
+    total           = dynamic + leakage + ring_heating + laser; \
+    energy_per_bit  = total / ($(InjectionRate) * $(CoreDataRate) * $(NumberBits)); \
+    active_area     = $(Area>>SWSRLink:Active); \
+    photonic_area   = $(Area>>SWSRLink:Photonic); \
+    print "Photonic Clos Network:"; \
+    print "    Dynamic power: " dynamic; \
+    print "    Leakage power: " leakage; \
+    print "    Laser power: " laser; \
+    print "    Ring Heater Power: " ring_heating; \
+    print "    Total power: " total; \
+    print "    Energy per bit: " energy_per_bit; \
+    print "    Active Area: " active_area; \
+    print "    Photonic Area: " photonic_area; \
+    
+# Technology file (see other models in tech/models)
+ElectricalTechModelFilename             = tech/tech_models/Bulk45LVT.model
+PhotonicTechModelFilename               = tech/tech_models/Photonics.model
+
+###############################################################################
+# Model specifications
+###############################################################################
+
+# Clos Parameters
+# Number of bits the link is responsible for delivering
+NumberBits                                      = 64
+# Core data rate
+CoreDataRate                                    = 1e9
+# Link data rate, if link data-rate > core data rate, SerDes will be applied
+LinkDataRate                                    = 1e9
+
+# Optimization parameters
+# Whether link specs will be optimized for power
+OptimizeLoss                                    = true
+# Optimize the laser/modulator power balance for the given link utilization,
+# ignored if optimize loss is set to false
+OptUtil                                         = 0.5
+# Insertion loss and extinction ratio (in dB), ignored if optimize loss is set
+# to true
+InsertionLoss                                   = 2.0
+ExtinctionRatio                                 = 6.0
+
+# Technology-based parameters
+# Type of the laser. Current valid choices are: (Standard, Throttled)
+# Note, if you change this to throttled, the laser gets lumped into dynamic
+# power, so change the Ndd power query for laser appropriately
+LaserType                                       = Standard
+# Ring tuning method. Current valid choices are:
+# (FullThermal, AthermalWithTrim, ThermalWithBitReshuffle, ElectricalAssistWithBitReshuffle)
+RingTuningMethod                                = ThermalWithBitReshuffle 
+    
+# Physical organization properties
+# Length of the link (in meters)
+Length                                          = 10e-3
+
diff --git a/ext/dsent/configs/router.cfg b/ext/dsent/configs/router.cfg
new file mode 100644 (file)
index 0000000..2e68b7e
--- /dev/null
@@ -0,0 +1,131 @@
+
+# Name of model to be built and evaluated
+ModelName                               = Router
+
+# Query string to choose what to evaluate (use '\' to enable multiline config)
+QueryString                             = \
+    Energy>>Router:WriteBuffer@0 \
+    Energy>>Router:ReadBuffer@0 \
+    Energy>>Router:TraverseCrossbar->Multicast1@0 \
+    Energy>>Router:ArbitrateSwitch->ArbitrateStage1@0 \
+    Energy>>Router:ArbitrateSwitch->ArbitrateStage2@0 \
+    Energy>>Router:DistributeClock@0 \
+    NddPower>>Router:Leakage@1 \
+    Area>>Router:Active@1 \
+
+
+# Injection rate (# flits per cycle per port), assuming that the router is not
+# saturated
+InjectionRate                           = 0.3
+# Evaluation string
+EvaluateString                          = \
+    ejection_rate   = $(NumberInputPorts) * $(InjectionRate) / $(NumberOutputPorts); \
+    buf_rd_dynamic  = $(Energy>>Router:ReadBuffer) * $(Frequency); \
+    buf_wr_dynamic  = $(Energy>>Router:WriteBuffer) * $(Frequency); \
+    buf_static      = $(NddPower>>Router->InputPort:Leakage) * $(NumberInputPorts) + ($(NddPower>>Router->PipelineReg0:Leakage) + $(NddPower>>Router->PipelineReg1:Leakage)) * $(NumberInputPorts) * $(NumberBitsPerFlit); \
+    xbar_o_dynamic  = $(Energy>>Router:TraverseCrossbar->Multicast1) * $(Frequency); \
+    xbar_static     = $(NddPower>>Router->Crossbar:Leakage) + $(NddPower>>Router->PipelineReg2_0:Leakage) * $(NumberOutputPorts) * $(NumberBitsPerFlit); \
+    sa_o_dynamic    = ($(Energy>>Router:ArbitrateSwitch->ArbitrateStage1) + $(Energy>>Router:ArbitrateSwitch->ArbitrateStage2)) * $(Frequency); \
+    sa_static       = $(NddPower>>Router->SwitchAllocator:Leakage); \
+    clock_o_dynamic = $(Energy>>Router:DistributeClock) * $(Frequency); \
+    clock_static    = $(NddPower>>Router->ClockTree:Leakage); \
+    buffer_dynamic  = buf_wr_dynamic * $(InjectionRate) * $(NumberInputPorts) + buf_rd_dynamic * ejection_rate * $(NumberOutputPorts); \
+    buffer_leakage  = buf_static; \
+    xbar_dynamic    = xbar_o_dynamic * ejection_rate * $(NumberOutputPorts); \
+    xbar_leakage    = xbar_static; \
+    sa_dynamic      = sa_o_dynamic * ejection_rate * $(NumberOutputPorts); \
+    sa_leakage      = sa_static; \
+    clock_dynamic   = clock_o_dynamic; \
+    clock_leakage   = clock_static; \
+    total_dynamic   = buffer_dynamic + xbar_dynamic + sa_dynamic + clock_dynamic; \
+    total_leakage   = buffer_leakage + xbar_leakage + sa_leakage + clock_leakage; \
+    buf_area        = ($(Area>>Router->InputPort:Active) + ($(Area>>Router->PipelineReg0:Active) + $(Area>>Router->PipelineReg1:Active)) * $(NumberBitsPerFlit)) * $(NumberInputPorts); \
+    xbar_area       = $(Area>>Router->Crossbar:Active) + $(Area>>Router->Crossbar_Sel_DFF:Active) + $(Area>>Router->PipelineReg2_0:Active) * $(NumberBitsPerFlit) * $(NumberOutputPorts); \
+    sa_area         = $(Area>>Router->SwitchAllocator:Active); \
+    other_area      = $(Area>>Router->ClockTree:Active); \
+    print "Buffer:"; \
+    print "    Dynamic power: " buffer_dynamic; \
+    print "    Leakage power: " buffer_leakage; \
+    print "Crossbar:"; \
+    print "    Dynamic power: " xbar_dynamic; \
+    print "    Leakage power: " xbar_leakage; \
+    print "Switch allocator:"; \
+    print "    Dynamic power: " sa_dynamic; \
+    print "    Leakage power: " sa_leakage; \
+    print "Clock:"; \
+    print "    Dynamic power: " clock_dynamic; \
+    print "    Leakage power: " clock_leakage; \
+    print "Total:"; \
+    print "    Dynamic power: " total_dynamic; \
+    print "    Leakage power: " $(NddPower>>Router:Leakage); \
+    print "Area:"; \
+    print "    Buffer:           " buf_area; \
+    print "    Crossbar:         " xbar_area; \
+    print "    Switch allocator: " sa_area; \
+    print "    Other:            " other_area; \
+
+# Technology file (see other models in tech/models)
+ElectricalTechModelFilename             = tech/tech_models/Bulk45LVT.model
+
+###############################################################################
+# Timing optimization
+###############################################################################
+
+# True if want to perform timing optimization; otherwise, false.
+IsPerformTimingOptimization             = true
+# Nets that the timing optimizer starts from
+TimingOptimization->StartNetNames       = [*]
+# Operating frequency (Hz)
+Frequency                               = 1.0e9
+
+###############################################################################
+# Model specifications
+###############################################################################
+
+# Number of input ports
+NumberInputPorts                        = 5
+# Number of output ports
+NumberOutputPorts                       = 5
+# Flit width (bit)
+NumberBitsPerFlit                       = 64
+
+# In this example, we define 2 virtual networks (message classes), VN1 and VN2. 
+#                           VN1 VN2
+# Number of VCs              2   3
+# Number of buffers / VC     4   5
+#
+# So in total, there are (2 * 4) + (3 * 5) = 23 flit buffers
+#
+# Number of virtual networks (number of message classes)
+NumberVirtualNetworks                   = 2
+# Number of virtual channels per virtual network
+NumberVirtualChannelsPerVirtualNetwork  = [2, 3]
+# Number of buffers per virtual channel
+NumberBuffersPerVirtualChannel          = [4, 5]
+
+# InputPort 
+# ---------
+# buffer model
+InputPort->BufferModel                  = DFFRAM
+
+# Crossbar
+# --------
+# crossbar model
+CrossbarModel                           = MultiplexerCrossbar
+
+# Switch allocator
+# ----------------
+# arbiter model
+SwitchAllocator->ArbiterModel           = MatrixArbiter
+
+# Clock tree
+# ----------
+# clock tree model
+ClockTreeModel                          = BroadcastHTree
+# number of levels
+ClockTree->NumberLevels                 = 5
+# wire layer
+ClockTree->WireLayer                    = Global
+# wire width multiplier
+ClockTree->WireWidthMultiplier          = 1.0
+
diff --git a/ext/dsent/libutil/Assert.h b/ext/dsent/libutil/Assert.h
new file mode 100644 (file)
index 0000000..0fdd364
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef __ASSERT_H__
+#define __ASSERT_H__
+
+#include "String.h"
+#include "Exception.h"
+
+#ifdef NDEBUG
+#define ASSERT(test_value_,exception_msg_)
+#else
+#define ASSERT(test_value_,msg_) \
+    do \
+    { \
+        if(!(test_value_)) \
+        { \
+            const LibUtil::String& exception_msg = LibUtil::String::format("\nAt %s:%d\n", __FILE__, __LINE__) + (String)(msg_); \
+            throw LibUtil::Exception(exception_msg); \
+        } \
+    } while(0);
+#endif
+
+#endif // __ASSERT_H__
+
diff --git a/ext/dsent/libutil/Calculator.cc b/ext/dsent/libutil/Calculator.cc
new file mode 100644 (file)
index 0000000..e78e672
--- /dev/null
@@ -0,0 +1,239 @@
+#include "Calculator.h"
+
+#include <cctype>
+#include <iostream>
+
+namespace LibUtil
+{
+    using std::cout;
+    using std::endl;
+    using std::scientific;
+
+    Calculator::Calculator()
+    {
+        m_reserved_chars_ = "+-*/;=()\\";
+    }
+
+    Calculator::~Calculator()
+    {}
+
+    void Calculator::reset()
+    {
+        m_var_.clear();
+        return;
+    }
+
+    void Calculator::evaluateString(const String& str_)
+    {
+        istringstream ist(str_);
+        while(ist)
+        {
+            getToken(ist);
+            if(m_curr_token_ == END) break;
+            if(m_curr_token_ == SEP) continue;
+            if((m_curr_token_ == NAME) && (m_value_string_ == "print"))
+            {
+                getToken(ist);
+
+                if(m_curr_token_ == STRING)
+                {
+                    String print_str = m_value_string_;
+
+                    getToken(ist);
+                    if(m_curr_token_ == SEP)
+                    {
+                        cout << print_str << endl;
+                    }
+                    else
+                    {
+                        double v = expr(ist, false);
+                        cout << scientific << print_str << v << endl;
+                    }
+                }
+                else
+                {
+                    double v = expr(ist, false);
+                    cout << scientific << v << endl;
+                }
+            }
+            else
+            {
+                expr(ist, false);
+            }
+        }
+        return;
+    }
+
+    Calculator::Token Calculator::getToken(istringstream& ist_)
+    {
+        char ch;
+        do
+        {
+            ist_.get(ch);
+            if(!ist_)
+            {
+                m_curr_token_ = END;
+                return m_curr_token_;
+            }
+        }
+        while(ch != '\n' && isspace(ch));
+
+        switch(ch)
+        {
+            case '\n':
+                m_curr_token_ = END;
+                return m_curr_token_;
+            case ';':
+                m_curr_token_ = SEP;
+                return m_curr_token_;
+            case '*':
+            case '/':
+            case '+':
+            case '-':
+            case '(':
+            case ')':
+            case '=':
+                m_curr_token_ = Token(ch);
+                return m_curr_token_;
+            case '0': case '1': case '2': case '3': case '4':
+            case '5': case '6': case '7': case '8': case '9':
+            case '.':
+                ist_.putback(ch);
+                ist_ >> m_value_number_;
+                m_curr_token_ = NUMBER;
+                return m_curr_token_;
+            case '"':
+                ist_.get(ch);
+                m_value_string_ = "";
+                while(ist_ && ('"' != ch))
+                {
+                    m_value_string_ += String(1, ch);
+                    ist_.get(ch);
+                }
+                m_curr_token_ = STRING;
+                return m_curr_token_;
+            case '$':
+                ist_.get(ch);
+                ASSERT((ch == '('), "[Error] Bad token: '(' expected");
+                ist_.get(ch);
+                m_value_string_ = "";
+                while(ist_ && (!isspace(ch)) && (')' != ch))
+                {
+                    m_value_string_ += String(1, ch);
+                    ist_.get(ch);
+                }
+                m_curr_token_ = NAME2;
+                return m_curr_token_;
+            default:
+                if(isalpha(ch))
+                {
+                    m_value_string_ = ch;
+                    ist_.get(ch);
+                    while(ist_ && (isalnum(ch) || ('_' == ch)))
+                    {
+                        m_value_string_ += String(1, ch);
+                        ist_.get(ch);
+                    }
+                    ist_.putback(ch);
+                    m_curr_token_ = NAME;
+                    return m_curr_token_;
+                }
+                else
+                {
+                    String error_msg = "[Error] Bad token: '" + String(ch) + "'";
+                    throw Exception(error_msg);
+                }
+        }
+    }
+
+    double Calculator::prim(istringstream& ist_, bool is_get_)
+    {
+        if(is_get_)
+        {
+            getToken(ist_);
+        }
+
+        double v;
+        switch(m_curr_token_)
+        {
+            case NUMBER:
+                v = m_value_number_;
+                getToken(ist_);
+                return v;
+            case NAME:
+                if(getToken(ist_) == ASSIGN)
+                {
+                    String var_name = m_value_string_;
+                    v = expr(ist_, true);
+                    m_var_.set(var_name, v);
+                }
+                else
+                {
+                    v = m_var_.get(m_value_string_);
+                }
+                return v;
+            case NAME2:
+                v = getEnvVar(m_value_string_);
+                getToken(ist_);
+                return v;
+            case MINUS:
+                return -prim(ist_, true);
+            case LP:
+                v = expr(ist_, true);
+                ASSERT((m_curr_token_ == RP), "[Error] ')' expected");
+                getToken(ist_);
+                return v;
+            default:
+                ASSERT(0, "[Error] primary expected, get: '" + String(int(m_curr_token_)) + "'");
+        }
+    }
+
+    double Calculator::term(istringstream& ist_, bool is_get_)
+    {
+        double left = prim(ist_, is_get_);
+
+        while(1)
+        {
+            double d;
+            switch(m_curr_token_)
+            {
+                case MUL:
+                    left *= prim(ist_, true);
+                    break;
+                case DIV:
+                    d = prim(ist_, true);
+                    ASSERT(d, "[Error] divided by 0");
+                    left /= d;
+                    break;
+                default:
+                    return left;
+            }
+        }
+    }
+
+    double Calculator::expr(istringstream& ist_, bool is_get_)
+    {
+        double left = term(ist_, is_get_);
+
+        while(1)
+        {
+            switch(m_curr_token_)
+            {
+                case PLUS:
+                    left += term(ist_, true);
+                    break;
+                case MINUS:
+                    left -= term(ist_, true);
+                    break;
+                default:
+                    return left;
+            }
+        }
+    }
+
+    double Calculator::getEnvVar(const String& var_name_) const
+    {
+        return m_var_.get(var_name_);
+    }
+} // namespace LibUtil
+
diff --git a/ext/dsent/libutil/Calculator.h b/ext/dsent/libutil/Calculator.h
new file mode 100644 (file)
index 0000000..4fcdf47
--- /dev/null
@@ -0,0 +1,86 @@
+#ifndef __LIBUTIL_CALCULATOR_H__
+#define __LIBUTIL_CALCULATOR_H__
+
+#include <sstream>
+
+#include "String.h"
+#include "Map.h"
+#include "Assert.h"
+
+namespace LibUtil
+{
+    using std::istringstream;
+
+    /*
+     *  program:
+     *      END                         // END is end-of-input
+     *      expr_list END
+     *
+     *  expr_list:
+     *      expression SEP expr_list    // SEP is semicolon
+     *      expression                  
+     *      print expression
+     *      print STRING
+     *      print STRING expression
+     *      print STRING expression SEP expr_list
+     *
+     *
+     *  expression:
+     *      expression + term
+     *      expression - term
+     *      term
+     *
+     *  term:
+     *      term / primary
+     *      term * primary
+     *      primary
+     *
+     *  primary:
+     *      NUMBER
+     *      NAME
+     *      NAME = expression
+     *      NAME string expression      // NAME is print
+     *      - primary
+     *      ( expression )
+     *
+     *  string:
+     *      
+     **/
+
+    class Calculator
+    {
+        protected:
+            enum Token
+            {
+                NAME, NAME2, NUMBER, STRING, END,
+                PLUS = '+', MINUS = '-', MUL = '*', DIV = '/',
+                SEP = ';', ASSIGN = '=', LP = '(', RP = ')'
+            };
+
+        public:
+            Calculator();
+            virtual ~Calculator();
+
+        public:
+            void reset();
+            void evaluateString(const String& str_);
+
+        protected:
+            Token getToken(istringstream& ist_);
+            double prim(istringstream& ist_, bool is_get_);
+            double term(istringstream& ist_, bool is_get_);
+            double expr(istringstream& ist_, bool is_get_);
+            virtual double getEnvVar(const String& var_name_) const;
+
+        protected:
+            String m_reserved_chars_;
+            Map<double> m_var_;
+
+            Token m_curr_token_;
+            double m_value_number_;
+            String m_value_string_;
+    }; // class Calculator
+} // namespace LibUtil
+
+#endif // __LIBUTIL_CALCULATOR_H__
+
diff --git a/ext/dsent/libutil/Config.cc b/ext/dsent/libutil/Config.cc
new file mode 100644 (file)
index 0000000..f858c69
--- /dev/null
@@ -0,0 +1,144 @@
+#include "Config.h"
+
+#include <fstream>
+
+#include "Assert.h"
+
+namespace LibUtil
+{
+    Config::Config(const String& delimiter_, const String& comment_, const String& sentry_)
+        : mDelimiter(delimiter_), mComment(comment_), mSentry(sentry_)
+    {}
+
+    Config::Config(const Config& config_)
+        : StringMap(config_)
+    {
+        mDelimiter = config_.mDelimiter;
+        mComment = config_.mComment;
+        mSentry = config_.mSentry;
+    }
+
+    Config::~Config()
+    {}
+
+    Config* Config::clone() const
+    {
+        return new Config(*this);
+    }
+
+    void Config::readFile(const String& filename_)
+    {
+        std::ifstream fin(filename_.c_str());
+
+        ASSERT(fin, "File not found: " + filename_);
+        fin >> (*this);
+        return;
+    }
+
+    void Config::readString(const String& str_)
+    {
+        String newString = str_;
+        newString.substitute(";", "\n");
+        std::istringstream iss(newString, std::istringstream::in);
+
+        iss >> (*this);
+    }
+
+    std::ostream& operator<<(std::ostream& ost_, const Config& config_)
+    {
+        Config::ConstIterator it;
+        for(it = config_.begin(); it != config_.end(); it++)
+        {
+            ost_ << it->first << " " << config_.mDelimiter << " ";
+            ost_ << it->second << std::endl;
+        }
+        return ost_;
+    }
+
+    std::istream& operator>>(std::istream& ist_, Config& config_)
+    {
+        // Set a Config from ist_
+        // Read in keys and values, keeping internal whitespace
+        typedef String::size_type pos;
+        const String& delim  = config_.mDelimiter;  // separator
+        const String& comm   = config_.mComment;    // comment
+        const String& sentry = config_.mSentry;     // end of file sentry
+        const pos skip = delim.length();        // length of separator
+
+        String nextline = "";  // might need to read ahead to see where value ends
+
+        while(ist_ || nextline.length() > 0)
+        {
+            // Read an entire line at a time
+            String line;
+            if(nextline.length() > 0)
+            {
+                line = nextline;  // we read ahead; use it now
+                nextline = "";
+            }
+            else
+            {
+                //std::getline(ist_, line);
+                safeGetline(ist_, line);
+            }
+
+            // Ignore comments and the spaces on both ends
+            line = line.substr(0, line.find(comm));
+            line.trim();
+
+            // Check for end of file sentry
+            if((sentry != "") && (line.find(sentry) != String::npos)) return ist_;
+
+            if(line.length() == 0)
+                continue;
+
+            // Parse the line if it contains a delimiter
+            pos delimPos = line.find(delim);
+            ASSERT((delimPos < String::npos), "Invalid config line: '" + line + "'");
+
+            // Extract the key
+            String key = line.substr(0, delimPos);
+            line.replace(0, delimPos+skip, "");
+
+            // See if value continues on the next line
+            // Stop at blank line, next line with a key, end of stream,
+            // or end of file sentry
+            bool terminate = false;
+            while(!terminate && ist_)
+            {
+                if(line.at(line.size() - 1) == '\\')
+                    line.erase(line.size() - 1);
+                else
+                    break;
+
+                //std::getline(ist_, nextline);
+                safeGetline(ist_, nextline);
+                terminate = true;
+
+                String nlcopy = nextline;
+                nlcopy.trim();
+                if(nlcopy == "") continue;
+
+                nextline = nextline.substr(0, nextline.find(comm));
+                //if(nextline.find(delim) != String::npos)
+                //    continue;
+                if((sentry != "") && (nextline.find(sentry) != String::npos))
+                    continue;
+
+                //nlcopy = nextline;
+                //nlcopy.trim();
+                //if(nlcopy != "") line += "\n";
+                line += nextline;
+                nextline = "";
+                terminate = false;
+            }
+
+            // Store key and value
+            key.trim();
+            line.trim();
+            config_.set(key, line);  // overwrites if key is repeated
+        }
+        return ist_;
+    }
+}
+
diff --git a/ext/dsent/libutil/Config.h b/ext/dsent/libutil/Config.h
new file mode 100644 (file)
index 0000000..a60c4b8
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef __LIBUTIL_CONFIG_H__
+#define __LIBUTIL_CONFIG_H__
+
+#include <iostream>
+
+#include "Map.h"
+
+namespace LibUtil
+{
+    class Config : public StringMap
+    {
+        public:
+            Config(const String& delimiter_ = "=", const String& comment_ = "#", const String& sentry_ = "End");
+            Config(const Config& config_);
+            virtual ~Config();
+
+        public:
+            // Make a copy of this instance
+            virtual Config* clone() const;
+            // Load the config from file
+            virtual void readFile(const String& filename_);
+            // Parse string and overwrite the Config instance if keys exist
+            virtual void readString(const String& str_);
+
+            // Write or read map using standard IO
+            friend std::ostream& operator<<(std::ostream& ost_, const Config& config_);
+            friend std::istream& operator>>(std::istream& ist_, Config& config_);
+
+        protected:
+            String mDelimiter;
+            String mComment;
+            String mSentry;
+    };
+}
+
+#endif // __LIBUTIL_CONFIG_H__
+
diff --git a/ext/dsent/libutil/Exception.cc b/ext/dsent/libutil/Exception.cc
new file mode 100644 (file)
index 0000000..c6db0e3
--- /dev/null
@@ -0,0 +1,17 @@
+#include "Exception.h"
+
+namespace LibUtil
+{
+    Exception::Exception(const String& exception_msg_) throw()
+        : exception(), mExceptionMsg(exception_msg_)
+    {}
+
+    Exception::~Exception() throw()
+    {}
+
+    const char* Exception::what() const throw()
+    {
+        return mExceptionMsg.c_str();
+    }
+}
+
diff --git a/ext/dsent/libutil/Exception.h b/ext/dsent/libutil/Exception.h
new file mode 100644 (file)
index 0000000..88d68cc
--- /dev/null
@@ -0,0 +1,29 @@
+#ifndef __EXCEPTION_H__
+#define __EXCEPTION_H__
+
+#include <exception>
+
+#include "String.h"
+
+namespace LibUtil
+{
+    using std::exception;
+
+    // Exception class handles the all exception messages in the program
+    class Exception : public exception
+    {
+        public:
+            // All constructors/destructors/functions in this class don't throw any events
+            Exception(const String& exception_msg_) throw();
+            ~Exception() throw();
+
+            // Derived from std::exception class that returns a null-terminated char string
+            const char* what() const throw();
+
+        private:
+            String mExceptionMsg;
+    };
+}
+
+#endif // __EXCEPTION_H__
+
diff --git a/ext/dsent/libutil/LibUtil.h b/ext/dsent/libutil/LibUtil.h
new file mode 100644 (file)
index 0000000..12eb76f
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef __LIBUTIL_H__
+#define __LIBUTIL_H__
+
+#include <vector>
+
+#include "String.h"
+#include "Exception.h"
+#include "Assert.h"
+#include "Map.h"
+#include "Log.h"
+#include "Config.h"
+#include "MathUtil.h"
+
+namespace LibUtil
+{
+    template<class T> void clearPtrVector(std::vector<T*>* vec_)
+    {
+        for(typename std::vector<T*>::iterator it = vec_->begin(); it != vec_->end(); ++it)
+        {
+            T* temp_T = (*it);
+            delete temp_T;
+        }
+        vec_->clear();
+        return;
+    }
+
+    template<class T> void deletePtrVector(std::vector<T*>* vec_)
+    {
+        clearPtrVector<T>(vec_);
+        delete vec_;
+        return;
+    }
+
+} // namespace LibUtil
+
+#endif // __LIBUTIL_H__
+
diff --git a/ext/dsent/libutil/Log.cc b/ext/dsent/libutil/Log.cc
new file mode 100644 (file)
index 0000000..cb4266b
--- /dev/null
@@ -0,0 +1,86 @@
+#include "Log.h"
+
+#include "Assert.h"
+
+namespace LibUtil
+{
+    using std::ostream;
+    using std::endl;
+
+    Log* Log::msSingleton = NULL;
+    const bool Log::msIsLog = LIBUTIL_IS_LOG;
+
+    void Log::allocate(const String& log_file_name_)
+    {
+        if(msIsLog)
+        {
+            // Allocate static Config instance
+            ASSERT(!msSingleton, "Log singleton is allocated");
+            msSingleton = new Log(log_file_name_);
+        }
+    }
+
+    void Log::release()
+    {
+        if(msIsLog)
+        {
+            ASSERT(msSingleton, "Log singleton is not allocated");
+            delete msSingleton;
+            msSingleton = NULL;
+        }
+        return;
+    }
+
+    void Log::print(const String& str_)
+    {
+        if(msIsLog)
+        {
+            ASSERT(msSingleton, "Log singleton is not allocated");
+            msSingleton->ofs << str_;
+        }
+        return;
+    }
+
+    void Log::print(ostream& stream_, const String& str_)
+    {
+        if(msIsLog)
+        {
+            ASSERT(msSingleton, "Log singleton is not allocated");
+            msSingleton->ofs << str_;
+        }
+        stream_ << str_;
+        return;
+    }
+
+    void Log::printLine(const String& str_)
+    {
+        if(msIsLog)
+        {
+            ASSERT(msSingleton, "Log singleton is not allocated");
+            msSingleton->ofs << str_ << endl;
+        }
+        return;
+    }
+
+    void Log::printLine(ostream& stream_, const String& str_)
+    {
+        if(msIsLog)
+        {
+            ASSERT(msSingleton, "Log singleton is not allocated");
+            msSingleton->ofs << str_ << endl;
+        }
+        stream_ << str_ << endl;
+        return;
+    }
+
+    Log::Log(const String& log_file_name_)
+    {
+        ofs.open(log_file_name_.c_str());
+    }
+
+    Log::~Log()
+    {
+        ofs.close();
+    }
+}
+
diff --git a/ext/dsent/libutil/Log.h b/ext/dsent/libutil/Log.h
new file mode 100644 (file)
index 0000000..9c759e7
--- /dev/null
@@ -0,0 +1,43 @@
+#ifndef __LOG_H__
+#define __LOG_H__
+
+#include <cstdio>
+#include <iostream>
+#include <fstream>
+
+#include "String.h"
+
+#ifndef LIBUTIL_IS_LOG
+#define LIBUTIL_IS_LOG false
+#endif
+
+namespace LibUtil
+{
+    using std::cerr;
+
+    class Log
+    {
+        public:
+            static void allocate(const String& log_file_name_);
+            static void release();
+
+            static void print(const String& str_);
+            static void print(std::ostream& stream_, const String& str_);
+            static void printLine(const String& str_);
+            static void printLine(std::ostream& stream_, const String& str_);
+
+        protected:
+            static Log* msSingleton;
+            static const bool msIsLog;
+
+        protected:
+            Log(const String& log_file_name_);
+            ~Log();
+
+        protected:
+            std::ofstream ofs;
+    };
+}
+
+#endif // __LOG_H__
+
diff --git a/ext/dsent/libutil/Makefile b/ext/dsent/libutil/Makefile
new file mode 100644 (file)
index 0000000..1500283
--- /dev/null
@@ -0,0 +1,43 @@
+
+# Define the directories that will be compiled
+DIRS_TO_COMPILE := . \
+
+DIRS = $(patsubst %,$(CURDIR)/%,$(DIRS_TO_COMPILE))
+
+SRCS = $(foreach dir, $(DIRS), $(wildcard $(dir)/*.cc))
+
+OBJS = $(SRCS:%.cc=%.o)
+
+DEF_FLAGS = 
+
+ifdef LIBUTIL_IS_LOG
+       LIBUTIL_IS_LOG = true
+else
+       LIBUTIL_IS_LOG = false
+endif
+DEF_FLAGS += -DLIBUTIL_IS_LOG=$(LIBUTIL_IS_LOG)
+
+INCLUDE_FLAGS = $(foreach dir, $(DIRS), -I$(dir))
+OPT_FLAGS = -O2 -g 
+WARN_FLAGS = -pedantic -Wall -W -Wextra -Werror
+CXXFLAGS = $(OPT_FLAGS) $(WARN_FLAGS) $(INCLUDE_FLAGS) $(DEF_FLAGS)
+
+TARGET = $(CURDIR)/libutil.a
+
+all: $(TARGET)
+
+$(TARGET): $(OBJS)
+       ar rcs $@ $^
+#$(TARGET): $(OBJS)
+#      $(CXX) $(CXXFLAGS) $^ -o $(TARGET)
+
+%.o: %.cc
+       $(CXX) $(CXXFLAGS) -c $< -o $@
+
+%/created:
+       mkdir -p $(dir $@)
+       touch $@
+
+clean:
+       $(RM) -rf $(OBJS) $(TARGET)
+
diff --git a/ext/dsent/libutil/Map.h b/ext/dsent/libutil/Map.h
new file mode 100644 (file)
index 0000000..0352c86
--- /dev/null
@@ -0,0 +1,242 @@
+#ifndef __MAP_H__
+#define __MAP_H__
+
+#include <iostream>
+#include <map>
+
+#include "String.h"
+#include "Assert.h"
+
+namespace LibUtil
+{
+    using std::map;
+
+    template<class T> class Map
+    {
+        public:
+            typedef typename map<String, T>::iterator       Iterator;
+            typedef typename map<String, T>::const_iterator ConstIterator;
+            typedef typename map<String, T>::size_type      SizeType;
+
+        public:
+            Map();
+            virtual ~Map();
+
+        public:
+            // Return a new copy of this Map instance
+            Map* clone() const;
+            // Copy map_ to this instance
+            void copyFrom(const Map<T>* map_);
+            // Return the size of the map
+            SizeType size() const;
+            // Check if the map is empty
+            bool isEmpty() const;
+            // Check if the key exists
+            bool keyExist(const String& key_) const;
+            // Get the value_ corresponding to the key_
+            const T& get(const String& key_) const;
+            // Get the value_ corresponding to the key_ if the key_ exist, otherwise, the default_value_is returned
+            const T& getIfKeyExist(const String& key_, const T& default_value_ = T()) const;
+            // Add/Update a <key_, value_> entry
+            void set(const String& key_, const T& value_);
+            // Get iterator to the element
+            Iterator find(const String& key_);
+            ConstIterator find(const String& key_) const;
+            // Remove an entry corresponding to key_
+            void remove(const String& key_);
+            // Remove an entry at 'it' 
+            void remove(Iterator it);
+            // Remove all keys
+            void clear();
+            // Merge a map. Values with same key will be overwritten.
+            void merge(const Map<T>* map_);
+            // Returns a MapIterator referring to the first element in the map
+            Iterator begin();
+            ConstIterator begin() const;
+            // Returns a MapIterator referring to the past-the-end element in the map
+            Iterator end();
+            ConstIterator end() const;
+
+        protected:
+            Map(const Map& map_);
+
+        protected:
+            map<String, T> mMap;
+    };
+
+    template<class T> Map<T>::Map()
+    {}
+
+    template<class T> Map<T>::~Map()
+    {}
+
+    template<class T> Map<T>* Map<T>::clone() const
+    {
+        return new Map<T>(*this);
+    }
+
+    template<class T> void Map<T>::copyFrom(const Map<T>* map_)
+    {
+        // Remove all keys (it won't free the content if T is a pointer)
+        mMap.clear();
+
+        // Copy the contents
+        mMap = map_->mMap;
+    }
+
+    template<class T> typename Map<T>::SizeType Map<T>::size() const
+    {
+        return mMap.size();
+    }
+
+    template<class T> bool Map<T>::isEmpty() const
+    {
+        return (mMap.empty());
+    }
+
+    template<class T> bool Map<T>::keyExist(const String& key_) const
+    {
+        ConstIterator it = mMap.find(key_);
+        return (it != mMap.end());
+    }
+
+    template<class T> const T& Map<T>::get(const String& key_) const
+    {
+        ConstIterator it;
+
+        it = mMap.find(key_);
+        ASSERT((it != mMap.end()), "Key not found: " + key_);
+        return (it->second);
+    }
+
+    template<class T> const T& Map<T>::getIfKeyExist(const String& key_, const T& default_value_) const
+    {
+        if(keyExist(key_))
+        {
+            return get(key_);
+        }
+        else
+        {
+            return default_value_;
+        }
+    }
+
+    template<class T> void Map<T>::set(const String& key_, const T& value_)
+    {
+        mMap[key_] = value_;
+        return;
+    }
+
+    template<class T> typename Map<T>::Iterator Map<T>::find(const String& key_)
+    {
+        return mMap.find(key_);
+    }
+
+    template<class T> typename Map<T>::ConstIterator Map<T>::find(const String& key_) const
+    {
+        return mMap.find(key_);
+    }
+
+    template<class T> void Map<T>::remove(const String& key_)
+    {
+        mMap.erase(key_);
+        return;
+    }
+
+    template<class T> void Map<T>::remove(Iterator it)
+    {
+        mMap.erase(it);
+        return;
+    }
+
+    template<class T> void Map<T>::clear()
+    {
+        mMap.clear();
+        return;
+    }
+
+    template<class T> void Map<T>::merge(const Map<T>* map_)
+    {
+        ConstIterator it;
+        for(it = map_->begin(); it != map_->end(); it++)
+        {
+            const String& key = it->first;
+            const T& value = it->second;
+            set(key, value);
+        }
+        return;
+    }
+
+    template<class T> typename Map<T>::Iterator Map<T>::begin()
+    {
+        return mMap.begin();
+    }
+
+    template<class T> typename Map<T>::ConstIterator Map<T>::begin() const
+    {
+        return mMap.begin();
+    }
+
+    template<class T> typename Map<T>::Iterator Map<T>::end()
+    {
+        return mMap.end();
+    }
+
+    template<class T> typename Map<T>::ConstIterator Map<T>::end() const
+    {
+        return mMap.end();
+    }
+
+    inline std::ostream& operator<<(std::ostream& ost_, const Map<String>& map_)
+    {
+        Map<String>::ConstIterator it;
+        for(it = map_.begin(); it != map_.end(); it++)
+        {
+            ost_ << it->first << " = " << it->second << std::endl;
+        }
+        return ost_;
+    }
+
+    template<class T> Map<T>::Map(const Map<T>& map_)
+        : mMap(map_.mMap)
+    {}
+
+    typedef Map<String> StringMap;
+
+
+    // Handy function to delete all pointers in a map
+    template<class T> void clearPtrMap(Map<T*>* map_)
+    {
+        for(typename Map<T*>::Iterator it = map_->begin(); it != map_->end(); ++it)
+        {
+            T* temp_T = it->second;
+            delete temp_T;
+        }
+        map_->clear();
+        return;
+    }
+
+    // Handy function to delete all pointers in a map and the map itself
+    template<class T> void deletePtrMap(Map<T*>* map_)
+    {
+        clearPtrMap<T>(map_);
+        delete map_;
+        return;
+    }
+
+    // Handy function to clone all pointers in a map
+    template<class T> Map<T*>* clonePtrMap(const Map<T*>* map_)
+    {
+        Map<T*>* new_T_map = new Map<T*>;
+        for(typename Map<T*>::ConstIterator it = map_->begin(); it != map_->end(); ++it)
+        {
+            const String& temp_name = it->first;
+            const T* temp_T = it->second;
+            new_T_map->set(temp_name, temp_T->clone());
+        }
+        return new_T_map;
+    }
+}
+
+#endif // __MAP_H__
+
diff --git a/ext/dsent/libutil/MathUtil.cc b/ext/dsent/libutil/MathUtil.cc
new file mode 100644 (file)
index 0000000..0e177b5
--- /dev/null
@@ -0,0 +1,7 @@
+#include "MathUtil.h"
+
+namespace LibUtil
+{
+    const double Math::epsilon = 1e-15;
+} // namespace LibUtil
+
diff --git a/ext/dsent/libutil/MathUtil.h b/ext/dsent/libutil/MathUtil.h
new file mode 100644 (file)
index 0000000..1f3341e
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef __MATH_H__
+#define __MATH_H__
+
+#include <cmath>
+
+namespace LibUtil
+{
+    class Math
+    {
+        public:
+            static const double epsilon;
+
+            static inline bool isEqual(double value1_, double value2_)
+            {
+                return (std::fabs(value1_ - value2_) < epsilon);
+            }
+    };
+} // namespace LibUtil
+
+#endif // __MATH_H__
+
diff --git a/ext/dsent/libutil/OptionParser.cc b/ext/dsent/libutil/OptionParser.cc
new file mode 100644 (file)
index 0000000..6d2695f
--- /dev/null
@@ -0,0 +1,177 @@
+#include "OptionParser.h"
+
+#include <cstdlib>
+#include <iostream>
+
+namespace LibUtil
+{
+    using std::cout;
+    using std::cerr;
+    using std::endl;
+
+    OptionParser::OptionInfo::OptionInfo(
+            const String& var_name_,
+            bool has_arg_, 
+            const String& arg_name_, 
+            bool has_default_arg_value_,
+            const String& default_arg_value_, 
+            const String& description_
+            )
+        : m_var_name_(var_name_),
+        m_has_arg_(has_arg_), 
+        m_arg_name_(arg_name_), 
+        m_has_default_arg_value_(has_default_arg_value_),
+        m_default_arg_value_(default_arg_value_),
+        m_description_(description_)
+    {}
+
+    OptionParser::OptionInfo::~OptionInfo()
+    {
+    }
+
+    OptionParser::OptionParser()
+    {}
+
+    OptionParser::~OptionParser()
+    {
+        clearPtrMap(&m_option_infos_);
+    }
+
+    void OptionParser::addOption(
+            const String& option_name_, 
+            const String& var_name_, 
+            bool has_arg_, 
+            const String& arg_name_, 
+            bool has_default_arg_value_,
+            const String& default_arg_value_, 
+            const String& description_)
+    {
+        OptionInfo* option_info = new OptionInfo(var_name_, has_arg_, arg_name_, 
+                has_default_arg_value_, default_arg_value_, description_);
+
+        ASSERT(!m_option_infos_.keyExist(option_name_), "Option exists: " + option_name_);
+
+        // Add the option name to an array for sorting
+        m_option_names_.push_back(option_name_);
+
+        // Add option info 
+        m_option_infos_.set(option_name_, option_info);
+
+        // Set the default argument value
+        if(has_default_arg_value_)
+        {
+            set(var_name_, default_arg_value_);
+        }
+
+        return;
+    }
+
+    void OptionParser::parseArguments(int argc_, char** argv_)
+    {
+        bool is_print_options = false;
+        int arg_idx = 0;
+
+        while(arg_idx < argc_)
+        {
+            String option_name = String(argv_[arg_idx]);
+
+            // Print the options page if -help is specified
+            if(option_name == "-help")
+            {
+                is_print_options = true;
+                break;
+            }
+            else if(m_option_infos_.keyExist(option_name))
+            {
+                const OptionInfo* option_info = m_option_infos_.get(option_name);
+                const String& var_name = option_info->getVarName();
+                if(option_info->hasArg())
+                {
+                    if((arg_idx + 1) >= argc_)
+                    {
+                        cerr << "[Error] Missing argument for option: '" << option_name << "'" << endl;
+                        is_print_options = true;
+                        break;
+                    }
+
+                    String option_arg = String(argv_[arg_idx + 1]);
+                    set(var_name, option_arg);
+
+                    arg_idx += 2;
+                }
+                else
+                {
+                    // If the option does not require an argument
+                    // then set it to true
+                    set(var_name, "true");
+
+                    arg_idx += 1;
+                }
+            }
+            else
+            {
+                cerr << "[Error] Unknown option: '" << option_name << "'" << endl;
+                is_print_options = true;
+                break;
+            }
+        }
+
+        // Check if all required options are set (the ones without default values)
+        vector<String>::const_iterator it;
+        for(it = m_option_names_.begin(); it != m_option_names_.end(); ++it)
+        {
+            const String& option_name = *it;
+            const OptionInfo* option_info = m_option_infos_.get(option_name);
+
+            if(!option_info->hasDefaultArgValue())
+            {
+                const String& var_name = option_info->getVarName();
+                if(!keyExist(var_name))
+                {
+                    cerr << "[Error] Missing required option: '" << option_name << "'" << endl;
+                    is_print_options = true;
+                }
+            }
+        }
+
+        if(is_print_options)
+        {
+            printOptions();
+            exit(0);
+        }
+        return;
+    }
+
+    void OptionParser::printOptions() const
+    {
+        cout << endl;
+        cout << "Available options:" << endl;
+        cout << "==================" << endl << endl;
+
+        vector<String>::const_iterator it;
+        for(it = m_option_names_.begin(); it != m_option_names_.end(); ++it)
+        {
+            const String& option_name = *it;
+            const OptionInfo* option_info = m_option_infos_.get(option_name);
+
+            cout << option_name;
+            if(option_info->hasArg())
+            {
+                cout << " <" << option_info->getArgName() << ">";
+            }
+            cout << endl;
+
+            cout << "    " << option_info->getDescription() << endl;
+            if(option_info->hasArg() && option_info->hasDefaultArgValue())
+            {
+                cout << "    " << "Default: " << option_info->getDefaultArgValue() << endl;
+            }
+            cout << endl;
+        }
+        cout << "-help" << endl;
+        cout << "    " << "Print this page" << endl;
+        cout << endl;
+        return;
+    }
+
+} // namespace LibUtil
diff --git a/ext/dsent/libutil/OptionParser.h b/ext/dsent/libutil/OptionParser.h
new file mode 100644 (file)
index 0000000..b98012a
--- /dev/null
@@ -0,0 +1,57 @@
+#ifndef __LIBUTIL_OPTION_PARSER_H__
+#define __LIBUTIL_OPTION_PARSER_H__
+
+#include <vector>
+
+#include "Map.h"
+
+namespace LibUtil
+{
+    using std::vector;
+
+    // Simple option parser
+    class OptionParser : public StringMap
+    {
+        private:
+            class OptionInfo
+            {
+                public:
+                    OptionInfo(const String& var_name_, bool has_arg_, const String& arg_name_, bool has_default_arg_value_, const String& default_arg_value_, const String& description_);
+                    ~OptionInfo();
+
+                public:
+                    inline const String& getVarName() const { return m_var_name_; }
+                    inline bool hasArg() const { return m_has_arg_; }
+                    inline const String& getArgName() const { return m_arg_name_; }
+                    inline bool hasDefaultArgValue() const { return m_has_default_arg_value_; }
+                    inline const String& getDefaultArgValue() const { return m_default_arg_value_; }
+                    inline const String& getDescription() const { return m_description_; }
+
+                private:
+                    String m_var_name_;
+                    bool m_has_arg_;
+                    String m_arg_name_;
+                    bool m_has_default_arg_value_;
+                    String m_default_arg_value_;
+                    String m_description_;
+            }; // class Option
+
+        public:
+            OptionParser();
+            virtual ~OptionParser();
+
+        public:
+            void addOption(const String& option_name_, const String& var_name_, bool has_arg_, const String& arg_name_, bool has_default_arg_value_, const String& default_arg_value_, const String& description_);
+
+            void parseArguments(int argc_, char** argv_);
+
+            void printOptions() const;
+
+        protected:
+            vector<String> m_option_names_;
+            Map<OptionInfo*> m_option_infos_;
+    }; // class OptionParser
+} // LibUtil
+
+#endif // __LIBUTIL_OPTION_PARSER_H__
+
diff --git a/ext/dsent/libutil/String.cc b/ext/dsent/libutil/String.cc
new file mode 100644 (file)
index 0000000..146e9f8
--- /dev/null
@@ -0,0 +1,347 @@
+#include "String.h"
+
+#include <cstdarg>
+#include <cstdio>
+#include <iostream>
+#include <ios>
+
+namespace LibUtil
+{
+    const unsigned int String::msBufferSize = 4096;
+
+    String String::format(const String& format_, ...)
+    {
+        char buffer[msBufferSize];
+
+        va_list args;
+        va_start(args, format_);
+        vsnprintf(buffer, msBufferSize, format_.c_str(), args);
+        va_end(args);
+
+        return (String)(buffer);
+    }
+
+    String String::format(const String& format_, va_list args_)
+    {
+        char buffer[msBufferSize];
+
+        vsnprintf(buffer, msBufferSize, format_.c_str(), args_);
+
+        return (String)(buffer);
+    }
+
+    String::String()
+    {}
+
+    String::String(const string& str_)
+        : string(str_)
+    {}
+
+    String::String(const char* str_, size_t n_)
+        : string(str_, n_)
+    {}
+
+    String::String(const char* str_)
+        : string(str_)
+    {}
+
+    String::String(size_t n_, char c_)
+        : string(n_, c_)
+    {}
+
+    String::String(int value_)
+        : string(toString<int>(value_))
+    {}
+
+    String::String(unsigned int value_)
+        : string(toString<unsigned int>(value_))
+    {}
+
+    String::String(long value_)
+        : string(toString<long>(value_))
+    {}
+
+    String::String(unsigned long value_)
+        : string(toString<unsigned long>(value_))
+    {}
+
+    String::String(float value_)
+        : string(toString<float>(value_))
+    {}
+
+    String::String(double value_)
+        : string(toString<double>(value_))
+    {}
+
+    String::String(bool value_)
+        : string(toString<bool>(value_))
+    {}
+
+    String::~String()
+    {}
+
+    String& String::trim()
+    {
+        // Remove leading and trailing whitespace
+        static const char whitespace[] = " \n\t\v\r\f";
+        erase(0, find_first_not_of(whitespace));
+        erase(find_last_not_of(whitespace) + 1U);
+        return (*this);
+    }
+
+    String& String::substitute(const String& str1_, const String& str2_)
+    {
+        size_t str1Size = str1_.size();
+        size_t str2Size = str2_.size();
+
+        size_t pos;
+        pos = find(str1_);
+        while(pos != string::npos)
+        {
+            replace(pos, str1Size, str2_);
+            pos += str2Size;
+            pos = find(str1_, pos);
+        }
+        return (*this);
+    }
+
+    vector<String> String::split(const char* delimiters_) const
+    {
+        vector<String> result;
+
+        if(size() == 0)
+        {
+            return result;
+        }
+
+        size_t currPos, nextPos;
+        currPos = 0;
+        nextPos = find_first_of(delimiters_);
+        while(1)
+        {
+            if(nextPos == string::npos)
+            {
+                if(currPos != size())
+                {
+                    result.push_back(substr(currPos));
+                }
+                break;
+            }
+
+            if(nextPos != currPos)
+            {
+                result.push_back(substr(currPos, nextPos - currPos));
+            }
+            currPos = nextPos + 1;
+            nextPos = find_first_of(delimiters_, currPos);
+        }
+
+        return result;
+    }
+
+    vector<String> String::split(const String* delimiters_, unsigned int num_delimiters_) const
+    {
+        vector<String> result;
+
+        if(size() == 0)
+        {
+            return result;
+        }
+
+        if(num_delimiters_ == 1)
+        {
+            size_t currPos, nextPos;
+            currPos = 0;
+            nextPos = find(delimiters_[0]);
+            while(1)
+            {
+                if(nextPos == String::npos)
+                {
+                    result.push_back(substr(currPos));
+                    break;
+                }
+
+                if(nextPos != currPos)
+                {
+                    result.push_back(substr(currPos, nextPos - currPos));
+                }
+                currPos = nextPos + delimiters_[0].size();
+                nextPos = find(delimiters_[0], currPos);
+            }
+        }
+        else
+        {
+            // Currently the length of the delimiters are not checked
+            unsigned int delimiterLength = 0;
+            size_t currPos, nextPos;
+            currPos = 0;
+            nextPos = size();
+            for(unsigned int i = 0; i < num_delimiters_; ++i)
+            {
+                size_t tempPos = find(delimiters_[i], currPos);
+                if((tempPos != String::npos) && (tempPos < nextPos))
+                {
+                    nextPos = tempPos;
+                    delimiterLength = delimiters_[i].size();
+                }
+            }
+            while(1)
+            {
+                if((nextPos == String::npos) || (nextPos == size()))
+                {
+                    result.push_back(substr(currPos));
+                    break;
+                }
+
+                if(nextPos != currPos)
+                {
+                    result.push_back(substr(currPos, nextPos - currPos));
+                }
+                currPos = nextPos + delimiterLength;
+                nextPos = size();
+                delimiterLength = 0;
+                for(unsigned int i = 0; i < num_delimiters_; ++i)
+                {
+                    size_t tempPos = find(delimiters_[i], currPos);
+                    if((tempPos != String::npos) && (tempPos < nextPos))
+                    {
+                        nextPos = tempPos;
+                        delimiterLength = delimiters_[i].size();
+                    }
+                }
+            }
+        }
+        return result;
+    }
+
+    vector<String> String::splitByString(const String& delimiter_) const
+    {
+        return split(&delimiter_, 1);
+    }
+
+    bool String::contain(const String& str_) const
+    {
+        return (find(str_) != String::npos);
+    }
+
+    const char* String::toCString() const
+    {
+        return this->c_str();
+    }
+
+    int String::toInt() const
+    {
+        return fromString<int>(*this);
+    }
+
+    unsigned int String::toUInt() const
+    {
+        return fromString<unsigned int>(*this);
+    }
+
+    long String::toLong() const
+    {
+        return fromString<long>(*this);
+    }
+
+    unsigned long String::toULong() const
+    {
+        return fromString<unsigned long>(*this);
+    }
+
+    float String::toFloat() const
+    {
+        return fromString<float>(*this);
+    }
+
+    double String::toDouble() const
+    {
+        return fromString<double>(*this);
+    }
+
+    bool String::toBool() const
+    {
+        return fromString<bool>(*this);
+    }
+
+    String::operator const char*() const
+    {
+        return this->c_str();
+    }
+
+    String::operator int() const
+    {
+        return fromString<int>(*this);
+    }
+
+    String::operator unsigned int() const
+    {
+        return fromString<unsigned int>(*this);
+    }
+
+    String::operator long() const
+    {
+        return fromString<long>(*this);
+    }
+
+    String::operator unsigned long() const
+    {
+        return fromString<unsigned long>(*this);
+    }
+
+    String::operator float() const
+    {
+        return fromString<float>(*this);
+    }
+
+    String::operator double() const
+    {
+        return fromString<double>(*this);
+    }
+
+    String::operator bool() const
+    {
+        return fromString<bool>(*this);
+    }
+
+    String& String::operator=(char c_)
+    {
+        this->assign(1, c_);
+        return *this;
+    }
+
+    std::istream& safeGetline(std::istream& is_, String& str_)
+    {
+        str_.clear();
+
+        // The characters in the stream are read one-by-one using a std::streambuf.
+        // That is faster than reading them one-by-one using the std::istream.
+        // Code that uses streambuf this way must be guarded by a sentry object.
+        // The sentry object performs various tasks,
+        // such as thread synchronization and updating the stream state.
+
+        std::istream::sentry se(is_, true);
+        std::streambuf* sb = is_.rdbuf();
+
+        while(1)
+        {
+            int c = sb->sbumpc();
+            switch(c)
+            {
+                case '\r':
+                    c = sb->sgetc();
+                    if(c == '\n')
+                        sb->sbumpc();
+                    return is_;
+                case '\n':
+                    return is_;
+                case EOF:
+                    is_.setstate(std::ios_base::failbit|std::ios_base::eofbit);
+                    return is_;
+                default:
+                    str_ += String(1, (char)c);
+            }
+        }
+    }
+} // namespace LibUtil
+
diff --git a/ext/dsent/libutil/String.h b/ext/dsent/libutil/String.h
new file mode 100644 (file)
index 0000000..95fe175
--- /dev/null
@@ -0,0 +1,218 @@
+#ifndef __STRING_H__
+#define __STRING_H__
+
+#include <string>
+#include <cstdarg>
+#include <vector>
+#include <sstream>
+#include <bitset>
+
+namespace LibUtil
+{
+    using std::string;
+    using std::vector;
+
+    class String : public string
+    {
+        public:
+            static String format(const String& format_, ...);
+            static String format(const String& format_, va_list args_);
+            template<class T> static String toString(const T& value_);
+            static String toBitString(unsigned int value_, unsigned int num_bits_);
+            template<class T> static T fromString(const String& str_);
+
+        private:
+            static const unsigned int msBufferSize;
+
+        public:
+            String();
+            String(const string& str_);
+            String(const char* str_, size_t n);
+            String(const char* str_);
+            String(size_t n, char c);
+            String(int value_);
+            String(unsigned int value_);
+            String(long value_);
+            String(unsigned long value_);
+            String(float value_);
+            String(double value_);
+            String(bool value_);
+            ~String();
+
+        public:
+            // Remove leading and trailing whitespace
+            String& trim();
+            // Substitute str1 with str2
+            String& substitute(const String& str1_, const String& str2_);
+            // Split the String into vector of Strings separated by delimiters_
+            vector<String> split(const char* delimiters_) const;
+            vector<String> split(const String* delimiters_, unsigned int num_delimiters_ = 1) const;
+            vector<String> splitByString(const String& delimiters_) const;
+
+            // Check if contains str
+            bool contain(const String& str_) const;
+
+        public:
+            // Convertions
+            const char* toCString() const;
+            int toInt() const;
+            unsigned int toUInt() const;
+            long toLong() const;
+            unsigned long toULong() const;
+            float toFloat() const;
+            double toDouble() const;
+            bool toBool() const;
+            operator const char*() const;
+            operator int() const;
+            operator unsigned int() const;
+            operator long() const;
+            operator unsigned long() const;
+            operator float() const;
+            operator double() const;
+            operator bool() const;
+            String& operator=(char c_);
+    };
+
+    template<class T> String String::toString(const T& value_)
+    {
+        std::ostringstream ost;
+        ost << value_;
+        return ost.str();
+    }
+
+    template<> inline String String::toString<bool>(const bool& value_)
+    {
+        if(value_ == true)
+        {
+            return "TRUE";
+        }
+        else
+        {
+            return "FALSE";
+        }
+    }
+
+    inline String String::toBitString(unsigned int value_, unsigned int num_bits_)
+    {
+        std::bitset<sizeof(unsigned int)*8> bitSet(value_);
+        String ret = String(bitSet.to_string());
+        ret = ret.substr(ret.length()-num_bits_);
+        return ret;
+    }
+
+    template<class T> T String::fromString(const String& str_)
+    {
+        T ret;
+        std::istringstream ist(str_);
+        ist >> ret;
+        return ret;
+    }
+
+    template<> inline String String::fromString<String>(const String& str_)
+    {
+        return str_;
+    }
+
+    template<> inline bool String::fromString<bool>(const String& str_)
+    {
+        bool ret;
+        if((str_ == String("TRUE")) || (str_ == String("true")))
+        {
+            ret = true;
+        }
+        else if((str_ == string("FALSE")) || (str_ == String("false")))
+        {
+            ret = false;
+        }
+        else
+        {
+            //std::cerr << "Invalid bool value: " << str_ << std::endl;
+            throw ("Invalid bool value: " + str_);
+        }
+        return ret;
+    }
+
+    template<class T> String arrayToString(
+            const T* array_, unsigned int start_index_, unsigned int end_index_, 
+            const String& delimiters_
+            )
+    {
+        // Ensure end_index_ >= start_index_ + 1
+        if(end_index_ <= start_index_)
+        {
+            throw("Invalid index range: start_index = " + (String)start_index_ + ", end_index = " + (String)end_index_);
+        }
+
+        String ret = "[";
+        for(unsigned int i = start_index_; i < (end_index_-1); ++i)
+        {
+            ret += (String)array_[i] + delimiters_;
+        }
+        ret += (String)array_[end_index_-1] + "]";
+        return ret;
+    }
+
+    template<class T> String arrayToString(const T* array_, unsigned int num_elements_)
+    {
+        return arrayToString(array_, 0, num_elements_, ", ");
+    }
+
+    template<class T> String arrayToString(const T* array_, unsigned int start_index_, unsigned int end_index_)
+    {
+        return arrayToString(array_, start_index_, end_index_);
+    }
+
+    template<class T> String vectorToString(
+        const vector<T>& vector_, unsigned int start_index_, unsigned int end_index_,
+        const String& delimiters_
+        )
+    {
+        // Ensure end_index_ >= start_index_ + 1, or if the vector is empty
+        if((end_index_ <= start_index_) || (end_index_ > vector_.size()))
+        {
+            // If the vector is empty, return empty array
+            if (vector_.size() == 0)
+                return "[]";
+                
+            throw("Invalid index range: start_index = " + (String)start_index_ + ", end_index = " + (String)end_index_);
+        }
+
+        String ret = "[";
+        for(unsigned int i = start_index_; i < (end_index_-1); ++i)
+        {
+            ret += (String)vector_[i] + delimiters_;
+        }
+        ret += (String)vector_[end_index_-1] + "]";
+        return ret;
+    }
+
+    template<class T> String vectorToString(const vector<T>& vector_)
+    {
+        return vectorToString(vector_, 0, vector_.size(), ", ");
+    }
+
+    template<class T> String vectorToString(const vector<T>& vector_, unsigned int num_elements_)
+    {
+        return vectorToString(vector_, 0, num_elements_, ", ");
+    }
+
+    template<class T> String vectorToString(const vector<T>& vector_, unsigned int start_index_, unsigned int end_index_)
+    {
+        return vectorToString(vector_, start_index_, end_index_);
+    }
+
+    template<class T> vector<T> castStringVector(const vector<String>& vector_)
+    {
+        vector<T> ret_vector;
+        for(unsigned int i = 0; i < vector_.size(); ++i)
+        {
+            ret_vector.push_back((T)vector_[i]);
+        }
+        return ret_vector;
+    }
+
+    std::istream& safeGetline(std::istream& is_, String& str_);
+} // namespace LibUtil
+
+#endif // __STRING_H__
+
diff --git a/ext/dsent/main.cc b/ext/dsent/main.cc
new file mode 100644 (file)
index 0000000..f826829
--- /dev/null
@@ -0,0 +1,10 @@
+
+#include "DSENT.h"
+
+int main(int argc, char** argv)
+{
+    DSENT::DSENT::run(argc-1, argv+1);
+
+    return 0;
+}
+
diff --git a/ext/dsent/model/ElectricalModel.cc b/ext/dsent/model/ElectricalModel.cc
new file mode 100644 (file)
index 0000000..469e26c
--- /dev/null
@@ -0,0 +1,871 @@
+#include "model/ElectricalModel.h"
+
+#include "model/PortInfo.h"
+#include "model/EventInfo.h"
+#include "model/timing_graph/ElectricalDriver.h"
+#include "model/timing_graph/ElectricalDriverMultiplier.h"
+#include "model/timing_graph/ElectricalNet.h"
+#include "model/timing_graph/ElectricalLoad.h"
+#include "model/timing_graph/ElectricalDelay.h"
+
+namespace DSENT
+{
+    ElectricalModel::ElectricalModel(const String& instance_name_, const TechModel* tech_model_)
+        : Model(instance_name_, tech_model_)
+    {
+        m_curr_driving_strengths_idx_ = -1;
+        m_input_ports_ = new Map<PortInfo*>;
+        m_output_ports_ = new Map<PortInfo*>;
+        m_net_references_ = new Map<NetIndex>;
+        m_drivers_ = new Map<ElectricalDriver*>;
+        m_driver_multipliers_ = new Map<ElectricalDriverMultiplier*>;
+        m_nets_ = new Map<ElectricalNet*>;
+        m_loads_ = new Map<ElectricalLoad*>;
+        m_delays_ = new Map<ElectricalDelay*>;
+        m_event_infos_ = new Map<EventInfo*>;
+    }
+
+    ElectricalModel::~ElectricalModel()
+    {
+        deletePtrMap<PortInfo>(m_input_ports_);
+        deletePtrMap<PortInfo>(m_output_ports_);
+        delete m_net_references_;
+        deletePtrMap<ElectricalDriver>(m_drivers_);
+        deletePtrMap<ElectricalDriverMultiplier>(m_driver_multipliers_);
+        deletePtrMap<ElectricalNet>(m_nets_);
+        deletePtrMap<ElectricalLoad>(m_loads_);
+        deletePtrMap<ElectricalDelay>(m_delays_);
+        deletePtrMap<EventInfo>(m_event_infos_);
+        m_input_ports_ = NULL;
+        m_output_ports_ = NULL;
+        m_net_references_ = NULL;
+        m_drivers_ = NULL;
+        m_driver_multipliers_ = NULL;
+        m_nets_ = NULL;
+        m_loads_ = NULL;
+        m_net_references_ = NULL;
+        m_event_infos_ = NULL;
+    }
+
+    void ElectricalModel::checkProperties() const
+    {
+        // Check if the specified driving strength exists in the available driving strengths
+        if(getProperties()->keyExist("DrivingStrength"))
+        {
+            const double driving_strength = getProperty("DrivingStrength");
+            bool is_found = false;
+            for(int i = 0; i < (int)m_driving_strengths_.size(); ++i)
+            {
+                if(driving_strength == m_driving_strengths_[i])
+                {
+                    is_found = true;
+                    break;
+                }
+            }
+            ASSERT(is_found, "[Error] " + getInstanceName() + 
+                " -> Driving strength (" + String(driving_strength) + ")"
+                " not found in available driving strengths (" + 
+                getParameter("AvailableDrivingStrengths"));
+        }
+
+        // Do normal check on the properties
+        Model::checkProperties();
+        return;
+    }
+
+    double ElectricalModel::getDrivingStrength() const
+    {
+        if(m_curr_driving_strengths_idx_ == -1)
+        {
+            return 0;
+        }
+        else
+        {
+            return m_driving_strengths_[m_curr_driving_strengths_idx_];
+        }
+    }
+
+    int ElectricalModel::getDrivingStrengthIdx() const
+    {
+        return m_curr_driving_strengths_idx_;
+    }
+
+    void ElectricalModel::setDrivingStrengthIdx(int idx_)
+    {
+        ASSERT(((idx_ >= 0) && (idx_ < (int)m_driving_strengths_.size())), 
+                "[Error] " + getInstanceName() + 
+                " -> Driving strength index out of range (" + String(idx_) + ")");
+
+        m_curr_driving_strengths_idx_ = idx_;
+        setProperty("DrivingStrength", m_driving_strengths_[m_curr_driving_strengths_idx_]);
+        
+        Log::printLine(getInstanceName() + " -> Changing drive strength to " + (String) m_driving_strengths_[m_curr_driving_strengths_idx_]);
+        update();
+        return;
+    }
+
+    void ElectricalModel::setMinDrivingStrength()
+    {
+        setDrivingStrengthIdx(0);
+        return;
+    }
+
+    bool ElectricalModel::hasMinDrivingStrength() const
+    {
+        return (m_curr_driving_strengths_idx_ == 0);
+    }
+
+    bool ElectricalModel::hasMaxDrivingStrength() const
+    {
+        return (m_curr_driving_strengths_idx_ == ((int)m_driving_strengths_.size() - 1));
+    }
+
+    void ElectricalModel::increaseDrivingStrength()
+    {
+        if(!hasMaxDrivingStrength())
+        {
+            setDrivingStrengthIdx(m_curr_driving_strengths_idx_ + 1);
+        }
+        return;
+    }
+
+    void ElectricalModel::decreaseDrivingStrength()
+    {
+        if(!hasMinDrivingStrength())
+        {
+            setDrivingStrengthIdx(m_curr_driving_strengths_idx_ - 1);
+        }
+        return;
+    }
+
+    void ElectricalModel::setAvailableDrivingStrengths(const String& driving_strengths_)
+    {
+        setParameter("AvailableDrivingStrengths", driving_strengths_);
+        const vector<String>& split_str = driving_strengths_.split("[,");
+
+        // Check if there is at least one driving strength specified
+        ASSERT(!split_str.empty(), "[Error] " + getInstanceName() + 
+            " -> Specified driving strength string does not contain any driving strengths (" +
+            driving_strengths_ + ")");
+
+        // TODO - check if the driving strengths is sorted
+
+        // Overwrite the available driving strengths
+        m_driving_strengths_.clear();
+        for(int i = 0; i < (int)split_str.size(); ++i)
+        {
+            m_driving_strengths_.push_back(split_str[i].toDouble());
+        }
+
+        // Set the driving strength to minimum
+        m_curr_driving_strengths_idx_ = 0;
+        setProperty("DrivingStrength", m_driving_strengths_[m_curr_driving_strengths_idx_]);
+        return;
+    }
+    
+    // Connect a port (input or output) to some ElectricalNet
+    void ElectricalModel::portConnect(ElectricalModel* connect_model_, const String& connect_port_name_, const String& connect_net_name_)
+    {
+        ASSERT(m_net_references_->keyExist(connect_net_name_), "[Error] " + getInstanceName() +
+            " -> Net '" + connect_net_name_ + "' does not exist!");
+            
+        portConnect(connect_model_, connect_port_name_, connect_net_name_, m_net_references_->get(connect_net_name_));        
+    }
+        
+    void ElectricalModel::portConnect(ElectricalModel* connect_model_, const String& connect_port_name_, const String& connect_net_name_, const NetIndex& connect_net_indices_)
+    {
+        ASSERT(m_net_references_->keyExist(connect_net_name_), "[Error] " + getInstanceName() +
+            " -> Net '" + connect_net_name_ + "' does not exist!");
+            
+        // Check whether the port name is an input or output, ASSERTion error if neither
+        bool is_input = connect_model_->getInputs()->keyExist(connect_port_name_);
+        bool is_output = connect_model_->getOutputs()->keyExist(connect_port_name_);
+        
+        ASSERT(is_input || is_output, "[Error] " + getInstanceName() + " -> Model '" + connect_model_->getInstanceName() + 
+            "' does not have a port named '" + connect_port_name_ + "'!");
+        
+        int connect_net_width = connect_net_indices_.second - connect_net_indices_.first + 1;
+        const NetIndex& port_indices = connect_model_->getNetReference(connect_port_name_);
+        int port_width = port_indices.second - port_indices.first + 1;
+        
+        ASSERT(connect_net_width == port_width, "[Error] " + getInstanceName() + " -> Port width mismatch for Model '" + 
+            connect_model_->getInstanceName() + "." + connect_port_name_ + toString(port_indices) + 
+            "' and net '" + connect_net_name_ + toString(connect_net_indices_) + "'!");
+
+        int port_index = port_indices.first;
+        int connect_net_index = connect_net_indices_.first;
+        
+        if(is_input)
+        {
+            while(port_index <= port_indices.second)
+            {
+                getNet(connect_net_name_, makeNetIndex(connect_net_index))->addDownstreamNode(
+                    connect_model_->getNet(connect_port_name_, makeNetIndex(port_index)));
+                ++port_index;
+                ++connect_net_index;
+            }
+        }
+        else if(is_output)
+        {
+            while (port_index <= port_indices.second)
+            {
+                connect_model_->getNet(connect_port_name_, makeNetIndex(port_index))->addDownstreamNode(
+                    getNet(connect_net_name_, makeNetIndex(connect_net_index)));
+                ++port_index;
+                ++connect_net_index;
+            }
+        }
+    }
+    
+    //Get Drivers
+    const Map<ElectricalDriver*>* ElectricalModel::getDrivers() const
+    {
+        return m_drivers_;
+    }
+    
+    ElectricalDriver* ElectricalModel::getDriver(const String& name_)
+    {
+        return m_drivers_->get(name_);
+    }
+
+    //Get Driver Multipliers
+    const Map<ElectricalDriverMultiplier*>* ElectricalModel::getDriverMultipliers() const
+    {
+        return m_driver_multipliers_;
+    }
+    
+    ElectricalDriverMultiplier* ElectricalModel::getDriverMultiplier(const String& name_)
+    {
+        return m_driver_multipliers_->get(name_);
+    }
+
+    //Get Nets
+    const Map<ElectricalNet*>* ElectricalModel::getNets() const
+    {
+        return m_nets_;
+    }
+    
+    ElectricalNet* ElectricalModel::getNet(const String& name_)
+    {
+        return getNet(name_, m_net_references_->get(name_));
+    }
+
+    ElectricalNet* ElectricalModel::getNet(const String& name_, const NetIndex& index_)
+    {
+        ASSERT(index_.first == index_.second, "[Error] " + getInstanceName() +
+            " -> Ambiguous get net since (" + name_ + ") is a bus consisting of several nets!");
+        return m_nets_->get(name_ + "[" + (String) index_.first + "]");
+    }
+    
+    //Get Loads
+    const Map<ElectricalLoad*>* ElectricalModel::getLoads() const
+    {
+        return m_loads_;
+    }
+
+    ElectricalLoad* ElectricalModel::getLoad(const String& name_)
+    {
+        return m_loads_->get(name_);
+    }
+    
+    //Get Delays
+    const Map<ElectricalDelay*>* ElectricalModel::getDelays() const
+    {
+        return m_delays_;
+    }
+
+    ElectricalDelay* ElectricalModel::getDelay(const String& name_)
+    {
+        return m_delays_->get(name_);
+    }
+
+    //Get Inputs
+    const Map<PortInfo*>* ElectricalModel::getInputs() const
+    {
+        return m_input_ports_;
+    }
+    
+    PortInfo* ElectricalModel::getInputPort(const String& name_)
+    {
+        ASSERT(m_input_ports_->keyExist(name_), "[Error] " + getInstanceName() +
+                " -> Input port (" + name_ + ") does not exist");
+
+        return m_input_ports_->get(name_);
+    }
+
+    const PortInfo* ElectricalModel::getInputPort(const String& name_) const
+    {
+        ASSERT(m_input_ports_->keyExist(name_), "[Error] " + getInstanceName() +
+                " -> Input port (" + name_ + ") does not exist");
+
+        return m_input_ports_->get(name_);
+    }
+
+    //Get Outputs
+    const Map<PortInfo*>* ElectricalModel::getOutputs() const
+    {
+        return m_output_ports_;
+    }
+
+    PortInfo* ElectricalModel::getOutputPort(const String& name_)
+    {
+        ASSERT(m_output_ports_->keyExist(name_), "[Error] " + getInstanceName() +
+                " -> Output port (" + name_ + ") does not exist");
+
+        return m_output_ports_->get(name_);
+    }
+    
+    const PortInfo* ElectricalModel::getOutputPort(const String& name_) const
+    {
+        ASSERT(m_output_ports_->keyExist(name_), "[Error] " + getInstanceName() +
+                " -> Output port (" + name_ + ") does not exist");
+
+        return m_output_ports_->get(name_);
+    }
+    
+    const Map<NetIndex>* ElectricalModel::getNetReferences() const
+    {
+        return m_net_references_;
+    }
+
+    const NetIndex ElectricalModel::getNetReference(const String& name_) const
+    {
+        return m_net_references_->get(name_);
+    }
+
+    //-------------------------------------------------------------------------
+    //  Electrical Connectivity and Timing Element Creation Functions
+    //-------------------------------------------------------------------------
+
+    // Input Port creation
+    void ElectricalModel::createInputPort(const String& name_, const NetIndex& net_indices_)
+    {
+        // Create the new nets (including its net reference)
+        // This should already check that it has not been previously declared
+        createNet(name_, net_indices_);
+        // Add the net name to list of input ports
+        m_input_ports_->set(name_, new PortInfo(name_, net_indices_));
+        return;
+    }
+
+    // Output Port creation
+    void ElectricalModel::createOutputPort(const String& name_, const NetIndex& net_indices_)
+    {
+        // Create the new nets (including its net reference)
+        // This should already check that it has not been previously declared
+        createNet(name_, net_indices_);
+        // Add the net name to list of output ports
+        m_output_ports_->set(name_, new PortInfo(name_, net_indices_));
+        return;
+    }
+
+    // Net creation
+    void ElectricalModel::createNet(const String& name_)
+    {
+        // Creating a net with specifying an index range means that the net is just
+        // a 1-bit wire indexed at [0]
+        createNet(name_, makeNetIndex(0, 0));
+        return;
+    }
+
+    void ElectricalModel::createNet(const String& name_, const NetIndex& net_indices_)
+    {
+        // Check that it hasn't been previously declared
+        ASSERT( !m_nets_->keyExist(name_) && !m_net_references_->keyExist(name_),
+                "[Error] " + getInstanceName() + " -> Redeclaration of net " + name_);
+
+        int start = net_indices_.first;
+        int end = net_indices_.second;
+        
+        for (int index = start; index <= end; ++index)
+        {
+            String indexed_name = name_ + "[" + (String) index + "]";
+            // Create the new net
+            ElectricalNet* net = new ElectricalNet(indexed_name, this);
+            // Add the net to net map
+            m_nets_->set(indexed_name, net);
+        }
+        // Add net to net references
+        m_net_references_->set(name_, net_indices_);        
+        return;
+    }
+    
+    // Driver creation
+    void ElectricalModel::createDriver(const String& name_, bool sizable_)
+    {
+        // Check that it hasn't been previously declared
+        ASSERT( !m_drivers_->keyExist(name_),
+                "[Error] " + getInstanceName() + " -> Redeclaration of driver " + name_);
+
+        ElectricalDriver* driver = new ElectricalDriver(name_, this, sizable_);
+        m_drivers_->set(name_, driver);
+        return;
+    }
+
+    /*
+    void ElectricalModel::createDriver(const String& name_, bool sizable_, int start_index_, int end_index_)
+    {
+        for (int index = start_index_; index <= end_index_; ++index)
+        {
+            createDriver(name_ + "[" + (String) index + "]", sizable_);
+        }
+        return;
+    }
+    */
+    
+    // Driver Multiplier creation
+    void ElectricalModel::createDriverMultiplier(const String& name_)
+    {
+        // Check that it hasn't been previously declared
+        ASSERT( !m_driver_multipliers_->keyExist(name_),
+                "[Error] " + getInstanceName() + " -> Redeclaration of driver_multiplier " + name_);
+
+        ElectricalDriverMultiplier* driver_multiplier = new ElectricalDriverMultiplier(name_, this);
+        m_driver_multipliers_->set(name_, driver_multiplier);
+        return;
+    }
+
+    // Load creation
+    
+    void ElectricalModel::createLoad(const String& name_)
+    {
+        // Check that it hasn't been previously declared
+        ASSERT( !m_loads_->keyExist(name_),
+                "[Error] " + getInstanceName() + " -> Redeclaration of load " + name_);
+
+        ElectricalLoad* load = new ElectricalLoad(name_, this);
+        m_loads_->set(name_, load);
+        return;
+    }
+    
+    /*
+    void ElectricalModel::createLoad(const String& name_, int start_index_, int end_index_)
+    {
+        for (int index = start_index_; index <= end_index_; ++index)
+        {
+            createLoad(name_ + "[" + (String) index + "]");
+        }
+        return;
+    }
+    */
+
+    // Delay creation
+    void ElectricalModel::createDelay(const String& name_)
+    {
+        // Check that it hasn't been previously declared
+        ASSERT( !m_delays_->keyExist(name_),
+                "[Error] " + getInstanceName() + " -> Redeclaration of delay " + name_);
+
+        ElectricalDelay* delay = new ElectricalDelay(name_, this);
+        m_delays_->set(name_, delay);
+        return;
+    }
+
+    /*
+    void ElectricalModel::createDelay(const String& name_, int start_index_, int end_index_)
+    {
+        for (int index = start_index_; index <= end_index_; ++index)
+        {
+            createDelay(name_ + "[" + (String) index + "]");
+        }
+        return;
+    }
+    */
+    //-------------------------------------------------------------------------
+    
+    // Assign a net to be downstream from another net
+    // case 1: 'assign downstream_net_name_ = upstream_net_name_'
+    void ElectricalModel::assign(const String& downstream_net_name_, const String& upstream_net_name_)
+    {
+        ASSERT(getNetReferences()->keyExist(downstream_net_name_), "[Error] " + getInstanceName() + " -> Net '" +
+            downstream_net_name_ + "' does not exist!");
+
+        ASSERT(getNetReferences()->keyExist(upstream_net_name_), "[Error] " + getInstanceName() + " -> Net '" +
+            upstream_net_name_ + "' does not exist!");
+        
+        assign(downstream_net_name_, getNetReference(downstream_net_name_),
+            upstream_net_name_, getNetReference(upstream_net_name_));
+            
+        return;
+    }
+
+    // case 2: 'assign downstream_net_name_[begin:end] = upstream_net_name_'
+    void ElectricalModel::assign(const String& downstream_net_name_, const NetIndex& downstream_net_indices_, const String& upstream_net_name_)
+    {
+        ASSERT(getNetReferences()->keyExist(downstream_net_name_), "[Error] " + getInstanceName() + " -> Net '" +
+            downstream_net_name_ + "' does not exist!");
+
+        ASSERT(getNetReferences()->keyExist(upstream_net_name_), "[Error] " + getInstanceName() + " -> Net '" +
+            upstream_net_name_ + "' does not exist!");
+            
+        assign(downstream_net_name_, downstream_net_indices_,
+            upstream_net_name_, getNetReference(upstream_net_name_));
+
+        return;
+    }
+
+    // case 3: 'assign downstream_net_name_ = upstream_net_name_[begin:end]'
+    void ElectricalModel::assign(const String& downstream_net_name_, const String& upstream_net_name_, const NetIndex& upstream_net_indices_)
+    {
+        ASSERT(getNetReferences()->keyExist(downstream_net_name_), "[Error] " + getInstanceName() + " -> Net '" +
+            downstream_net_name_ + "' does not exist!");
+
+        ASSERT(getNetReferences()->keyExist(upstream_net_name_), "[Error] " + getInstanceName() + " -> Net '" +
+            upstream_net_name_ + "' does not exist!");
+            
+        assign(downstream_net_name_, getNetReference(downstream_net_name_),
+            upstream_net_name_, upstream_net_indices_);
+
+        return;    
+    }
+    // case 4: 'assign downstream_net_name_[begin:end] = upstream_net_name_[begin:end]'
+    void ElectricalModel::assign(const String& downstream_net_name_, const NetIndex& downstream_net_indices_, const String& upstream_net_name_, const NetIndex& upstream_net_indices_)
+    {
+        ASSERT(getNetReferences()->keyExist(downstream_net_name_), "[Error] " + getInstanceName() + " -> Net '" +
+            downstream_net_name_ + "' does not exist!");
+
+        ASSERT(getNetReferences()->keyExist(upstream_net_name_), "[Error] " + getInstanceName() + " -> Net '" +
+            upstream_net_name_ + "' does not exist!");
+            
+        // Check that the assignment widths are the same
+        int downstream_width = downstream_net_indices_.second - downstream_net_indices_.first + 1;
+        int upstream_width = upstream_net_indices_.second - upstream_net_indices_.first + 1;
+
+        ASSERT(downstream_width == upstream_width, "[Error] " + getInstanceName() + " -> Assignment width mismatch: " +
+            downstream_net_name_ + " (" + (String) downstream_width + ") and " +
+            upstream_net_name_ + " (" + (String) upstream_width + ")");
+
+        // Loop through indices and connect them together
+        int down_index = downstream_net_indices_.first;
+        int up_index = upstream_net_indices_.first;        
+        while (down_index <= downstream_net_indices_.second)
+        {
+            getNet(upstream_net_name_, makeNetIndex(up_index))->addDownstreamNode(
+                getNet(downstream_net_name_, makeNetIndex(down_index)));
+            
+            ++up_index;
+            ++down_index;
+        }
+        
+        return;
+    }
+
+    // Assign a net to another net through a driver multiplier
+    void ElectricalModel::assignVirtualFanout(const String& downstream_net_name_, const String& upstream_net_name_)
+    {
+        ASSERT(getNetReferences()->keyExist(upstream_net_name_), "[Error] " + getInstanceName() + 
+                " -> Net '" + upstream_net_name_ + "' does not exist!");
+        ASSERT(getNetReferences()->keyExist(downstream_net_name_), "[Error] " + getInstanceName() + 
+                " -> Net '" + downstream_net_name_ + "' does not exist!");
+
+        assignVirtualFanout(downstream_net_name_, getNetReference(downstream_net_name_), upstream_net_name_, getNetReference(upstream_net_name_));
+        return;
+    }
+
+    // Assign a net to another net through a driver multiplier
+    void ElectricalModel::assignVirtualFanout(const String& downstream_net_name_, const NetIndex& downstream_net_indices_, const String& upstream_net_name_, const NetIndex& upstream_net_indices_)
+    {
+        ASSERT(getNetReferences()->keyExist(upstream_net_name_), "[Error] " + getInstanceName() + 
+                " -> Net '" + upstream_net_name_ + "' does not exist!");
+        ASSERT(getNetReferences()->keyExist(downstream_net_name_), "[Error] " + getInstanceName() + 
+                " -> Net '" + downstream_net_name_ + "' does not exist!");
+
+        const String& drive_mult_name = upstream_net_name_ + "_" + (String) upstream_net_indices_.first + "_DriverMultiplier";
+        bool is_drive_mult_exist = getDriverMultipliers()->keyExist(drive_mult_name);
+
+        // Create a driver multiplier and assign it to upstream_net since it doesn't exist 
+        if(!is_drive_mult_exist)
+        {
+            createDriverMultiplier(drive_mult_name);
+            getNet(upstream_net_name_, upstream_net_indices_)->addDownstreamNode(getDriverMultiplier(drive_mult_name));
+        }
+
+        // Assign downstream_net_name_[end:begin] = driver_multiplier_name_
+        ElectricalDriverMultiplier* drive_mult = getDriverMultiplier(drive_mult_name);
+        int begin_index = downstream_net_indices_.first;
+        int end_index = downstream_net_indices_.second;
+        for(int i = begin_index; i <= end_index; ++i)
+        {
+            drive_mult->addDownstreamNode(getNet(downstream_net_name_, makeNetIndex(i)));
+        }
+        return;
+    }
+
+    void ElectricalModel::assignVirtualFanin(const String& downstream_net_name_, const String& upstream_net_name_)
+    {
+        ASSERT(getNetReferences()->keyExist(upstream_net_name_), "[Error] " + getInstanceName() + 
+                " -> Net '" + upstream_net_name_ + "' does not exist!");
+        ASSERT(getNetReferences()->keyExist(downstream_net_name_), "[Error] " + getInstanceName() + 
+                " -> Net '" + downstream_net_name_ + "' does not exist!");
+
+        assignVirtualFanin(downstream_net_name_, getNetReference(downstream_net_name_), upstream_net_name_, getNetReference(upstream_net_name_));
+        return;
+    }
+
+    void ElectricalModel::assignVirtualFanin(const String& downstream_net_name_, const NetIndex& downstream_net_indices_, const String& upstream_net_name_, const NetIndex& upstream_net_indices_)
+    {
+        ASSERT(getNetReferences()->keyExist(upstream_net_name_), "[Error] " + getInstanceName() + 
+                " -> Net '" + upstream_net_name_ + "' does not exist!");
+        ASSERT(getNetReferences()->keyExist(downstream_net_name_), "[Error] " + getInstanceName() + 
+                " -> Net '" + downstream_net_name_ + "' does not exist!");
+
+        int begin_index = upstream_net_indices_.first;
+        int end_index = upstream_net_indices_.second;
+
+        for(int i = begin_index; i <= end_index; ++i)
+        {
+            getNet(upstream_net_name_, makeNetIndex(i))->addDownstreamNode(getNet(downstream_net_name_, downstream_net_indices_));
+        }
+        return;
+    }
+
+    void ElectricalModel::createElectricalResults()
+    {
+        // Add active area result
+        addAreaResult(new Result("Active"));
+
+        // Add wire area result
+        TechModel::ConstWireLayerIterator it_begin = getTechModel()->getAvailableWireLayers()->begin();
+        TechModel::ConstWireLayerIterator it_end = getTechModel()->getAvailableWireLayers()->end();
+        TechModel::ConstWireLayerIterator it;
+        for(it = it_begin; it != it_end; ++it)
+        {
+            const String& layer_name = (*it);
+            addAreaResult(new Result(layer_name + "Wire"));
+        }
+
+        // Add leakage result
+        addNddPowerResult(new Result("Leakage"));
+
+        // Add idle event result
+        createElectricalEventResult("Idle");
+        return;
+    }
+
+    void ElectricalModel::addElectricalSubResults(const ElectricalModel* model_, double number_models_)
+    {
+        // Add active area sub result
+        getAreaResult("Active")->addSubResult(model_->getAreaResult("Active"), model_->getInstanceName(), number_models_);
+
+        // Add wire area sub result
+        TechModel::ConstWireLayerIterator it_begin = getTechModel()->getAvailableWireLayers()->begin();
+        TechModel::ConstWireLayerIterator it_end = getTechModel()->getAvailableWireLayers()->end();
+        TechModel::ConstWireLayerIterator it;
+        for(it = it_begin; it != it_end; ++it)
+        {
+            const String& layer_name = (*it);
+            const String& result_name = layer_name + "Wire";
+            getAreaResult(result_name)->addSubResult(model_->getAreaResult(result_name), model_->getInstanceName(), number_models_);
+        }
+
+        // Add leakage sub result
+        getNddPowerResult("Leakage")->addSubResult(model_->getNddPowerResult("Leakage"), model_->getInstanceName(), number_models_);
+
+        // Add idle event sub result
+        getEventResult("Idle")->addSubResult(model_->getEventResult("Idle"), model_->getInstanceName(), number_models_);
+        return;
+    }
+
+    void ElectricalModel::addElectricalWireSubResult(const String& wire_layer_, const Result* result_, const String& producer_, double number_results_)
+    {
+        getAreaResult(wire_layer_ + "Wire")->addSubResult(result_, producer_, number_results_);
+        return;
+    }
+
+    void ElectricalModel::createElectricalAtomicResults()
+    {
+        // Add active area result
+        addAreaResult(new AtomicResult("Active"));
+
+        // Add wire area result
+        TechModel::ConstWireLayerIterator it_begin = getTechModel()->getAvailableWireLayers()->begin();
+        TechModel::ConstWireLayerIterator it_end = getTechModel()->getAvailableWireLayers()->end();
+        TechModel::ConstWireLayerIterator it;
+        for(it = it_begin; it != it_end; ++it)
+        {
+            const String& layer_name = (*it);
+            addAreaResult(new AtomicResult(layer_name + "Wire"));
+        }
+
+        // Add leakage result
+        addNddPowerResult(new AtomicResult("Leakage"));
+
+        // Add idle event result
+        createElectricalEventAtomicResult("Idle");
+        return;
+    }
+
+    void ElectricalModel::addElecticalAtomicResultValues(const ElectricalModel* model_, double number_models_)
+    {
+        getAreaResult("Active")->addValue(model_->getAreaResult("Active")->calculateSum() * number_models_);
+
+        // Add wire area sub result
+        TechModel::ConstWireLayerIterator it_begin = getTechModel()->getAvailableWireLayers()->begin();
+        TechModel::ConstWireLayerIterator it_end = getTechModel()->getAvailableWireLayers()->end();
+        TechModel::ConstWireLayerIterator it;
+        for(it = it_begin; it != it_end; ++it)
+        {
+            const String& layer_name = (*it);
+            const String& result_name = layer_name + "Wire";
+            getAreaResult(result_name)->addValue(model_->getAreaResult(result_name)->calculateSum() * number_models_);
+        }
+
+        // Add leakage sub result
+        getNddPowerResult("Leakage")->addValue(model_->getNddPowerResult("Leakage")->calculateSum() * number_models_);
+
+        // Add idle event sub result
+        getEventResult("Idle")->addValue(model_->getEventResult("Idle")->calculateSum() * number_models_);
+        return;
+    }
+
+    void ElectricalModel::addElecticalWireAtomicResultValue(const String& wire_layer_, double value_)
+    {
+        getAreaResult(wire_layer_ + "Wire")->addValue(value_);
+        return;
+    }
+
+    void ElectricalModel::resetElectricalAtomicResults()
+    {
+        getAreaResult("Active")->setValue(0.0);
+
+        // Reset wire area sub result
+        TechModel::ConstWireLayerIterator it_begin = getTechModel()->getAvailableWireLayers()->begin();
+        TechModel::ConstWireLayerIterator it_end = getTechModel()->getAvailableWireLayers()->end();
+        TechModel::ConstWireLayerIterator it;
+        for(it = it_begin; it != it_end; ++it)
+        {
+            const String& layer_name = (*it);
+            const String& result_name = layer_name + "Wire";
+            getAreaResult(result_name)->setValue(0.0);
+        }
+
+        // Reset leakage sub result
+        getNddPowerResult("Leakage")->setValue(0.0);
+
+        // Reset idle event sub result
+        getEventResult("Idle")->setValue(0.0);
+
+        return;
+    }
+
+    void ElectricalModel::createElectricalEventResult(const String& name_)
+    {
+        // Add the event result
+        addEventResult(new Result(name_));
+        // Add event info
+        m_event_infos_->set(name_, new EventInfo(name_, getInputs()));
+        return;
+    }
+
+    void ElectricalModel::createElectricalEventAtomicResult(const String& name_)
+    {
+        // Add the event result
+        addEventResult(new AtomicResult(name_));
+        // Add event info
+        m_event_infos_->set(name_, new EventInfo(name_, getInputs()));
+        return;
+    }
+
+    void ElectricalModel::assignPortTransitionInfo(ElectricalModel* downstream_model_, const String& downstream_port_name_, const TransitionInfo& trans_info_)
+    {
+        ASSERT(downstream_model_ != NULL, "[Error] " + getInstanceName() +
+                " -> Downstream model does not exist");
+
+        downstream_model_->getInputPort(downstream_port_name_)->setTransitionInfo(trans_info_);
+        return;
+    }
+
+    void ElectricalModel::propagatePortTransitionInfo(const String& downstream_port_name_, const String& upstream_port_name_)
+    {
+        const TransitionInfo& trans_info = getInputPort(upstream_port_name_)->getTransitionInfo();
+        getOutputPort(downstream_port_name_)->setTransitionInfo(trans_info);
+        return;
+    }
+
+    void ElectricalModel::propagatePortTransitionInfo(ElectricalModel* downstream_model_, const String& downstream_port_name_, const String& upstream_port_name_)
+    {
+        ASSERT(downstream_model_ != NULL, "[Error] " + getInstanceName() +
+                " -> Downstream model does not exist");
+
+        const TransitionInfo& trans_info = getInputPort(upstream_port_name_)->getTransitionInfo();
+        downstream_model_->getInputPort(downstream_port_name_)->setTransitionInfo(trans_info);
+        return;
+    }
+
+    void ElectricalModel::propagatePortTransitionInfo(ElectricalModel* downstream_model_, const String& downstream_port_name_, const ElectricalModel* upstream_model_, const String& upstream_port_name_)
+    {
+        ASSERT(downstream_model_ != NULL, "[Error] " + getInstanceName() +
+                " -> Downstream model does not exist");
+        ASSERT(upstream_model_ != NULL, "[Error] " + getInstanceName() +
+                " -> Upstream model does not exist");
+
+        const TransitionInfo& trans_info = upstream_model_->getOutputPort(upstream_port_name_)->getTransitionInfo();
+
+        downstream_model_->getInputPort(downstream_port_name_)->setTransitionInfo(trans_info);
+        return;
+    }
+
+    void ElectricalModel::propagatePortTransitionInfo(const String& downstream_port_name_, const ElectricalModel* upstream_model_, const String& upstream_port_name_)
+    {
+        ASSERT(upstream_model_ != NULL, "[Error] " + getInstanceName() +
+                " -> Upstream model does not exist");
+    
+        const TransitionInfo& trans_info = upstream_model_->getOutputPort(upstream_port_name_)->getTransitionInfo();
+        getOutputPort(downstream_port_name_)->setTransitionInfo(trans_info);
+        return;
+    }
+
+    void ElectricalModel::propagateTransitionInfo()
+    {
+        // by default do nothing.
+    }
+
+    void ElectricalModel::useModel(const String& event_name_)
+    {
+        getGenProperties()->set("UseModelEvent", event_name_);
+        applyTransitionInfo(event_name_);
+        useModel();
+        return;
+    }
+
+    void ElectricalModel::useModel()
+    {
+        propagateTransitionInfo();
+        return;
+    }
+
+    void ElectricalModel::applyTransitionInfo(const String& event_name_)
+    {
+        // Check if the event actually exists
+        ASSERT(hasEventResult(event_name_), "[Error] " + getInstanceName() +
+                " -> Event (" + event_name_ + ") does not exist in the result map");
+        ASSERT(m_event_infos_->keyExist(event_name_), "[Error] " + getInstanceName() +
+                " -> Event (" + event_name_ + ") does not exist in the event info map");
+
+        const EventInfo* event_info = m_event_infos_->get(event_name_);
+
+        // Set the input ports' transition information for the event
+        Map<PortInfo*>::ConstIterator it_begin = m_input_ports_->begin();
+        Map<PortInfo*>::ConstIterator it_end = m_input_ports_->end();
+        Map<PortInfo*>::ConstIterator it;
+        for(it = it_begin; it != it_end; ++it)
+        {
+            const String& port_name = it->first;
+            PortInfo* port_info = it->second;
+            const TransitionInfo& trans_info = event_info->getTransitionInfo(port_name);
+            port_info->setTransitionInfo(trans_info);
+        }
+
+        return;
+    }
+
+    EventInfo* ElectricalModel::getEventInfo(const String& event_name_)
+    {
+        ASSERT(m_event_infos_->keyExist(event_name_), "[Error] " + getInstanceName() +
+                " -> Event (" + event_name_ + ") does not exist");
+
+        return m_event_infos_->get(event_name_);
+    }
+
+} // namespace DSENT
+
diff --git a/ext/dsent/model/ElectricalModel.h b/ext/dsent/model/ElectricalModel.h
new file mode 100644 (file)
index 0000000..15dfefd
--- /dev/null
@@ -0,0 +1,244 @@
+#ifndef __DSENT_MODEL_ELECTRICALMODEL_H__
+#define __DSENT_MODEL_ELECTRICALMODEL_H__
+
+#include "util/CommonType.h"
+#include "model/Model.h"
+#include "model/TransitionInfo.h"
+
+namespace DSENT
+{
+    class PortInfo;
+    class EventInfo;
+    class ElectricalDriver;
+    class ElectricalDriverMultiplier;
+    class ElectricalNet;
+    class ElectricalLoad;
+    class ElectricalDelay;
+
+    // A Net index consisting of a start and end index
+    typedef std::pair<int, int> NetIndex;
+
+    // Helper function to make net index
+    inline NetIndex makeNetIndex(int start_index_, int end_index_)
+    {
+        ASSERT((end_index_ >= start_index_), (String)"[Error] Invalid net index range " +
+
+                "[" + (String)start_index_ + ":" + (String)end_index_ + "]");
+
+        return NetIndex(start_index_, end_index_);
+    }
+
+    // Helper function to make net index
+    inline NetIndex makeNetIndex(int index_)
+    {
+        return makeNetIndex(index_, index_);
+    }
+
+    // Helper function to trun NetIndex to String
+    inline String toString(const NetIndex& net_index_)
+    {
+        return "[" + String(net_index_.second) + ":" + String(net_index_.first) + "]";
+    }
+
+    // ElectricalModel specifies physical connectivity to other models as well as the port
+    // parameters for the current model
+    class ElectricalModel : public Model
+    {
+        public:
+            ElectricalModel(const String& instance_name_, const TechModel* tech_model_);
+            virtual ~ElectricalModel();
+
+        public:
+            // Check if all properties needed exist in the m_properties_
+            virtual void checkProperties() const;
+            // Set available driving strength vector from string
+            void setAvailableDrivingStrengths(const String& driving_strengths_);
+
+            //-----------------------------------------------------------------
+            // Connectivity specification
+            //-----------------------------------------------------------------
+            // Net Indices
+            const Map<NetIndex>* getNetReferences() const;
+            const NetIndex getNetReference(const String& name_) const;
+            // Input Ports
+            void createInputPort(const String& name_, const NetIndex& net_indices_ = NetIndex(0, 0));
+            const Map<PortInfo*>* getInputs() const;
+            PortInfo* getInputPort(const String& name_);
+            const PortInfo* getInputPort(const String& name_) const;
+            // Output Ports
+            void createOutputPort(const String& name_, const NetIndex& net_indices_ = NetIndex(0, 0));
+            const Map<PortInfo*>* getOutputs() const;
+            PortInfo* getOutputPort(const String& name_);
+            const PortInfo* getOutputPort(const String& name_) const;
+            // Electrical Nets
+            void createNet(const String& name_);
+            void createNet(const String& name_, const NetIndex& net_indices_);
+            const Map<ElectricalNet*>* getNets() const;
+            ElectricalNet* getNet(const String& name_);
+            ElectricalNet* getNet(const String& name_, const NetIndex& index_);
+
+            // Assign a net to be downstream from another net
+            // case 1: 'assign downstream_net_name_ = upstream_net_name_'
+            void assign(const String& downstream_net_name_, const String& upstream_net_name_);
+            // case 2: 'assign downstream_net_name_[end:begin] = upstream_net_name_'
+            void assign(const String& downstream_net_name_, const NetIndex& downstream_net_indices_, const String& upstream_net_name_);
+            // case 3: 'assign downstream_net_name_ = upstream_net_name_[end:begin]'
+            void assign(const String& downstream_net_name_, const String& upstream_net_name_, const NetIndex& upstream_net_indices_);
+            // case 4: 'assign downstream_net_name_[end:begin] = upstream_net_name_[end:begin]'
+            void assign(const String& downstream_net_name_, const NetIndex& downstream_net_indices_, const String& upstream_net_name_, const NetIndex& upstream_net_indices_);
+
+            // Connect a port (input or output) to some ElectricalNet
+            // case 1: .connect_port_name_(connect_net_name_)
+            void portConnect(ElectricalModel* connect_model_, const String& connect_port_name_, const String& connect_net_name_);
+            // case 2: .connect_port_name_(connect_net_name[end:begin])
+            void portConnect(ElectricalModel* connect_model_, const String& connect_port_name_, const String& connect_net_name_, const NetIndex& connect_net_indices_);
+
+            // Assign a net to be downstream from another net through a driver multipliers
+            void assignVirtualFanout(const String& downstream_net_name_, const String& upstream_net_name_);
+            void assignVirtualFanout(const String& downstream_net_name_, const NetIndex& downstream_net_indices_, const String& upstream_net_name_, const NetIndex& upstream_net_indices_);
+            // Assign a net to be downstream from another net
+            // This is used to enable bit_duplication 
+            void assignVirtualFanin(const String& downstream_net_name_, const String& upstream_net_name_);
+            void assignVirtualFanin(const String& downstream_net_name_, const NetIndex& downstream_net_indices_, const String& upstream_net_name_, const NetIndex& upstream_net_indices_);
+            //-----------------------------------------------------------------
+
+            //-----------------------------------------------------------------
+            // Timing Model Components
+            //-----------------------------------------------------------------
+            // Electrical Drivers
+            void createDriver(const String& name_, bool sizable_);
+            //void createDriver(const String& name_, bool sizable_, int start_index_, int end_index_);
+            const Map<ElectricalDriver*>* getDrivers() const;
+            ElectricalDriver* getDriver(const String& name_);
+            // Electrical Driver Multipliers
+            void createDriverMultiplier(const String& name_);
+            const Map<ElectricalDriverMultiplier*>* getDriverMultipliers() const;
+            ElectricalDriverMultiplier* getDriverMultiplier(const String& name_);
+
+
+            // Electrical Loads
+            void createLoad(const String& name_);                        
+            //void createLoad(const String& name_, int start_index_, int end_index_);                        
+            const Map<ElectricalLoad*>* getLoads() const;
+            ElectricalLoad* getLoad(const String& name_);
+            // Electrical Delay creation
+            void createDelay(const String& name_);                        
+            //void createDelay(const String& name_, int start_index_, int end_index_);
+            const Map<ElectricalDelay*>* getDelays() const;
+            ElectricalDelay* getDelay(const String& name_);
+            //-----------------------------------------------------------------
+
+            // Get current driving strength
+            double getDrivingStrength() const;
+            // Get current driving strength index
+            int getDrivingStrengthIdx() const;
+            // Set driving strength by index
+            void setDrivingStrengthIdx(int idx_);
+            // Set the instance to minimum driving strength
+            void setMinDrivingStrength();
+            // Return true if the instance has minimum driving strength
+            bool hasMinDrivingStrength() const;
+            // Return true if the instance has maximum driving strength
+            bool hasMaxDrivingStrength() const;
+            // Increase driving strength index by 1
+            void increaseDrivingStrength();
+            // Decrease driving strength index by 1
+            void decreaseDrivingStrength();
+
+            // Create the default sets of the electrical results
+            void createElectricalResults();
+            // Add the default sets of the electrical results from a model
+            void addElectricalSubResults(const ElectricalModel* model_, double number_models_);
+            // Add extra wire sub results
+            void addElectricalWireSubResult(const String& wire_layer_, const Result* result_, const String& producer_, double number_results_);
+            // Create the default sets of the electrical atomic results
+            void createElectricalAtomicResults();
+            // Accumulate the electrical atomic results' values
+            void addElecticalAtomicResultValues(const ElectricalModel* model_, double number_models_);
+            // Add extra wire sub results
+            void addElecticalWireAtomicResultValue(const String& wire_layer_, double value_);
+            // Reset the electrical atomic results' values
+            void resetElectricalAtomicResults();
+            // Create an electrical event result. This will add an event associate to all input/output ports
+            void createElectricalEventResult(const String& name_);
+            // Create an electrical event atomic result
+            void createElectricalEventAtomicResult(const String& name_);
+
+            //-----------------------------------------------------------------
+            // Helper functions to propagate transition information
+            //-----------------------------------------------------------------
+            void assignPortTransitionInfo(ElectricalModel* downstream_model_, const String& downstream_port_name_, const TransitionInfo& trans_info_);
+            void propagatePortTransitionInfo(const String& downstream_port_name_, const String& upstream_port_name_);
+            void propagatePortTransitionInfo(ElectricalModel* downstream_model_, const String& downstream_port_name_, const String& upstream_port_name_);
+            void propagatePortTransitionInfo(ElectricalModel* downstream_model_, const String& downstream_port_name_, const ElectricalModel* upstream_model_, const String& upstream_port_name_);
+            void propagatePortTransitionInfo(const String& downstream_port_name_, const ElectricalModel* upstream_model_, const String& upstream_port_name_);
+            virtual void propagateTransitionInfo();
+            //-----------------------------------------------------------------
+
+            //-----------------------------------------------------------------
+            // Helper functions to insert and remove buffers
+            //-----------------------------------------------------------------
+            
+            //-----------------------------------------------------------------
+
+            virtual void useModel(const String& event_name_);
+            virtual void useModel();
+            // TODO - add comments
+            void applyTransitionInfo(const String& event_name_);
+            // TODO - add comments
+            EventInfo* getEventInfo(const String& event_name_);
+
+        protected:
+            // In an ElectricalModel, the complete port-to-port connectivity
+            // of all sub-instance must be specified. Addition/Removal ports or
+            // port-related nets cannot happen after this step
+            //virtual void constructModel() = 0;
+            // In an ElectricalModel, updateModel MUST finish all necessary
+            // calculations such that a timing model can be run
+            //virtual void updateModel() = 0;
+            // In an ElectricalModel, evaluateModel should calculate all
+            // event energies, now that the connectivity and timing has been
+            // completed
+            //virtual void evaluateModel() = 0;
+
+        private:
+            // Private copy constructor. Use clone to perform copy operation.
+            ElectricalModel(const ElectricalModel& model_);
+
+        private:
+            // Contains the driving strengths in increasing order
+            vector<double> m_driving_strengths_;
+            // Driving strength index in the driving strength vector
+            int m_curr_driving_strengths_idx_;
+
+            //Connectivity elements
+            // Nets can come in various bus widths. A net reference is really
+            // just a helper map mapping a referenced map name to a bunch of
+            // net indices. A net index returns the starting and end indices of
+            // a net if the net is a multi-bit bus of some sort
+            Map<NetIndex>* m_net_references_;
+            // Map of the input ports
+            Map<PortInfo*>* m_input_ports_;
+            // Map of the output ports
+            Map<PortInfo*>* m_output_ports_;
+            // Map of all our electrical nets
+            Map<ElectricalNet*>* m_nets_;
+
+            //Timing model elements
+            // Map of all our electrical drivers
+            Map<ElectricalDriver*>* m_drivers_;
+            // Map of all our driver multipliers
+            Map<ElectricalDriverMultiplier*>* m_driver_multipliers_;
+            // Map of all our electrical loads
+            Map<ElectricalLoad*>* m_loads_;
+            // Map of all our idealized delays
+            Map<ElectricalDelay*>* m_delays_;            
+
+            // Map of the event infos
+            Map<EventInfo*>* m_event_infos_;
+
+    }; // class ElectricalModel
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_ELECTRICALMODEL_H__
+
diff --git a/ext/dsent/model/EventInfo.cc b/ext/dsent/model/EventInfo.cc
new file mode 100644 (file)
index 0000000..6bbe781
--- /dev/null
@@ -0,0 +1,86 @@
+#include "model/EventInfo.h"
+
+#include "model/PortInfo.h"
+#include "model/TransitionInfo.h"
+
+namespace DSENT
+{
+    EventInfo::EventInfo(const String& event_name_, const Map<PortInfo*>* port_infos_)
+        : m_event_name_(event_name_)
+    {
+        m_trans_info_map_ = new Map<TransitionInfo>;
+
+        // Get the name of each input port and add a transition info for it
+        Map<PortInfo*>::ConstIterator it_begin = port_infos_->begin();
+        Map<PortInfo*>::ConstIterator it_end = port_infos_->end();
+        Map<PortInfo*>::ConstIterator it;
+        for(it = it_begin; it != it_end; ++it)
+        {
+            const String& port_name = it->first;
+            m_trans_info_map_->set(port_name, TransitionInfo());
+        }
+    }
+
+    EventInfo::~EventInfo()
+    {
+        delete m_trans_info_map_;
+    }
+
+    const String& EventInfo::getEventName() const
+    {
+        return m_event_name_;
+    }
+
+    void EventInfo::setTransitionInfo(const String& port_name_, const TransitionInfo& trans_info_)
+    {
+        ASSERT(m_trans_info_map_->keyExist(port_name_), "[Error] " + getEventName() + 
+                " -> Port (" + port_name_ + ") does not exist!");
+
+        m_trans_info_map_->set(port_name_, trans_info_);
+        return;
+    }
+
+    void EventInfo::setStaticTransitionInfo(const String& port_name_)
+    {
+        ASSERT(m_trans_info_map_->keyExist(port_name_), "[Error] " + getEventName() + 
+                " -> Port (" + port_name_ + ") does not exist!");
+
+        m_trans_info_map_->set(port_name_, TransitionInfo(0.5, 0.0, 0.5));
+        return;
+    }
+
+    void EventInfo::setRandomTransitionInfos()
+    {
+        Map<TransitionInfo>::Iterator it_begin = m_trans_info_map_->begin();
+        Map<TransitionInfo>::Iterator it_end = m_trans_info_map_->end();
+        Map<TransitionInfo>::Iterator it;
+        for(it = it_begin; it != it_end; ++it)
+        {
+            TransitionInfo& trans_info = it->second;
+            trans_info = TransitionInfo();
+        }
+        return;
+    }
+
+    void EventInfo::setStaticTransitionInfos()
+    {
+        Map<TransitionInfo>::Iterator it_begin = m_trans_info_map_->begin();
+        Map<TransitionInfo>::Iterator it_end = m_trans_info_map_->end();
+        Map<TransitionInfo>::Iterator it;
+        for(it = it_begin; it != it_end; ++it)
+        {
+            TransitionInfo& trans_info = it->second;
+            trans_info = TransitionInfo(0.5, 0.0, 0.5);
+        }
+        return;
+    }
+
+    const TransitionInfo& EventInfo::getTransitionInfo(const String& port_name_) const
+    {
+        ASSERT(m_trans_info_map_->keyExist(port_name_), "[Error] " + getEventName() + 
+                " -> Port (" + port_name_ + ") does not exist!");
+
+        return m_trans_info_map_->get(port_name_);
+    }
+} // namespace DSENT
+
diff --git a/ext/dsent/model/EventInfo.h b/ext/dsent/model/EventInfo.h
new file mode 100644 (file)
index 0000000..646a6e1
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef __DSENT_MODEL_EVENT_INFO_H__
+#define __DSENT_MODEL_EVENT_INFO_H__
+
+#include "util/CommonType.h"
+#include "model/TransitionInfo.h"
+
+namespace DSENT
+{
+    class PortInfo;
+
+    class EventInfo
+    {
+        public:
+            EventInfo(const String& event_name_, const Map<PortInfo*>* port_infos_);
+            ~EventInfo();
+
+        public:
+            const String& getEventName() const;
+            void setTransitionInfo(const String& port_name_, const TransitionInfo& trans_info_);
+            void setStaticTransitionInfo(const String& port_name_);
+            void setRandomTransitionInfos();
+            void setStaticTransitionInfos();
+            const TransitionInfo& getTransitionInfo(const String& port_name_) const;
+
+        private:
+            String m_event_name_;
+            Map<TransitionInfo>* m_trans_info_map_;
+    }; // class EventInfo
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_EVENT_INFO_H__
+
diff --git a/ext/dsent/model/Model.cc b/ext/dsent/model/Model.cc
new file mode 100644 (file)
index 0000000..5a7bfe3
--- /dev/null
@@ -0,0 +1,698 @@
+#include "model/Model.h"
+
+#include <vector>
+
+#include "util/Result.h"
+
+namespace DSENT
+{
+    using std::vector;
+    using LibUtil::deletePtrMap;
+    using LibUtil::clonePtrMap;
+
+    Model::SubModel::SubModel(Model* model_, double num_models_)
+        : m_model_(model_), m_num_models_(num_models_)
+    {}
+
+    Model::SubModel::~SubModel()
+    {
+        delete m_model_;
+    }
+
+    Model* Model::SubModel::getModel()
+    {
+        return m_model_;
+    }
+
+    const Model* Model::SubModel::getModel() const
+    {
+        return m_model_;
+    }
+
+    double Model::SubModel::getNumModels() const
+    {
+        return m_num_models_;
+    }
+
+    Model::SubModel* Model::SubModel::clone() const
+    {
+        return new SubModel(*this);
+    }
+
+    Model::SubModel::SubModel(const SubModel& sub_model_)
+    {
+        m_model_ = sub_model_.m_model_->clone();
+        m_num_models_ = sub_model_.m_num_models_;
+    }
+
+    const char Model::TYPE_SEPARATOR[] = ">>";
+    const char Model::HIERARCHY_SEPARATOR[] = "->";
+    const char Model::SUBFIELD_SEPARATOR[] = ":";
+    const char Model::DETAIL_SEPARATOR[] = "@";
+
+    Model::Model(const String& instance_name_, const TechModel* tech_model_)
+        : m_instance_name_(instance_name_), m_tech_model_(tech_model_),
+            m_constructed_(false), m_updated_(false), m_evaluated_(false)
+    {
+        m_property_names_ = new vector<String>;
+        m_parameter_names_ = new vector<String>;
+        m_parameters_ = new ParameterMap();        
+        m_properties_ = new PropertyMap();
+        m_generated_properties_ = new PropertyMap();
+        m_sub_instances_ = new Map<SubModel*>();
+        m_event_map_ = new Map<Result*>();
+        m_area_map_ = new Map<Result*>();
+        m_ndd_power_map_ = new Map<Result*>();
+    }
+
+    Model::~Model()
+    {
+        // Clear parameter names
+        delete m_parameter_names_;
+        // Clear property name
+        delete m_property_names_;
+
+        // Clear parameters
+        delete m_parameters_;
+        m_parameters_ = NULL;
+        // Clear input properties
+        delete m_properties_;
+        m_properties_ = NULL;
+
+        // Clear generated properties
+        delete m_generated_properties_;
+        m_generated_properties_ = NULL;
+
+        // Clear sub models
+        deletePtrMap<SubModel>(m_sub_instances_);
+        m_sub_instances_ = NULL;
+
+        // Clear all results
+        deletePtrMap<Result>(m_event_map_);
+        m_event_map_ = NULL;
+        deletePtrMap<Result>(m_area_map_);
+        m_area_map_ = NULL;
+        deletePtrMap<Result>(m_ndd_power_map_);
+        m_ndd_power_map_ = NULL;
+    }
+
+    void Model::setInstanceName(const String& instance_name_)
+    {
+        m_instance_name_ = instance_name_;
+        return;
+    }
+
+    const String& Model::getInstanceName() const
+    {
+        return m_instance_name_;
+    }
+
+    void Model::setIsTopModel(bool is_top_model_)
+    {
+        m_is_top_model_ = is_top_model_;
+        return;
+    }
+
+    bool Model::getIsTopModel() const
+    {
+        return m_is_top_model_;
+    }
+
+    //-------------------------------------------------------------------------
+    //  Parameters and properties checks
+    //-------------------------------------------------------------------------
+    void Model::addParameterName(const String& parameter_name_)
+    {
+        ASSERT(!m_constructed_, "[Error] " + getInstanceName() +
+            " -> Cannot add additional parameters names after model is constructed!");
+        m_parameter_names_->push_back(parameter_name_);
+
+        return;
+    }
+
+    void Model::addParameterName(const String& parameter_name_, const String& parameter_default_)
+    {
+        ASSERT(!m_constructed_, "[Error] " + getInstanceName() +
+            " -> Cannot add additional parameters names after model is constructed!");
+        m_parameter_names_->push_back(parameter_name_);
+        setParameter(parameter_name_, parameter_default_);
+        return;
+    }
+    
+    const vector<String>* Model::getParameterNames() const
+    {
+        return m_parameter_names_;
+    }
+
+    void Model::addPropertyName(const String& property_name_)
+    {
+        ASSERT(!m_constructed_, "[Error] " + getInstanceName() +
+            " -> Cannot add additional property names after model is constructed!");
+        m_property_names_->push_back(property_name_);
+        return;
+    }
+
+    void Model::addPropertyName(const String& property_name_, const String& property_default_)
+    {
+        ASSERT(!m_constructed_, "[Error] " + getInstanceName() +
+            " -> Cannot add additional property names after model is constructed!");
+        m_property_names_->push_back(property_name_);
+        setProperty(property_name_, property_default_);
+        return;
+    }
+
+    const vector<String>* Model::getPropertyNames() const
+    {
+        return m_property_names_;
+    }
+
+    void Model::checkParameters() const
+    {
+        String missing_parameters = "";
+        
+        for(int i = 0; i < (int)m_parameter_names_->size(); ++i)
+        {
+            const String& parameter_name = m_parameter_names_->at(i);
+            if (!m_parameters_->keyExist(parameter_name))
+                missing_parameters += "    " + parameter_name + "\n";
+        }
+        
+        ASSERT(missing_parameters.size() == 0, "[Error] " + m_instance_name_ + 
+                " -> Missing parameters:\n" + missing_parameters);
+        return;
+    }
+
+    void Model::checkProperties() const
+    {
+        String missing_properties = "";
+        
+        for(int i = 0; i < (int)m_property_names_->size(); ++i)
+        {
+            const String& property_name = m_property_names_->at(i);
+            if (!m_properties_->keyExist(property_name))
+                missing_properties += "    " + property_name + "\n";
+        }
+        
+        ASSERT(missing_properties.size() == 0, "[Error] " + m_instance_name_ + 
+                " -> Missing properties:\n" + missing_properties);
+        return;
+    }
+    //-------------------------------------------------------------------------
+
+    //-------------------------------------------------------------------------
+    //  Parameters Manipulation
+    //-------------------------------------------------------------------------
+    const ParameterMap* Model::getParameters() const
+    {
+        return m_parameters_;
+    }
+
+    const String Model::getParameter(const String& parameter_name_) const
+    {
+        return m_parameters_->get(parameter_name_);
+    }
+    
+    void Model::setParameter(const String& parameter_name_, const String& parameter_value_)
+    {
+        ASSERT(!m_constructed_, "[Error] " + getInstanceName() +
+            " -> Cannot set parameters after model is constructed!");
+        m_parameters_->set(parameter_name_, parameter_value_);
+    }
+    //-------------------------------------------------------------------------
+    
+    //-------------------------------------------------------------------------
+    // Properties Manipulation
+    //-------------------------------------------------------------------------
+    const PropertyMap* Model::getProperties() const
+    {
+        return m_properties_;
+    }
+
+    const String Model::getProperty(const String& property_name_) const
+    {
+        return m_properties_->get(property_name_);
+    }
+    
+    void Model::setProperty(const String& property_name_, const String& property_value_)
+    {
+        // If any properties changed, reset updated and evaluated flags
+        m_updated_ = false;
+        m_evaluated_ = false;
+        m_properties_->set(property_name_, property_value_);
+    }
+    //-------------------------------------------------------------------------
+            
+    PropertyMap* Model::getGenProperties()
+    {
+        return m_generated_properties_;
+    }
+
+    const PropertyMap* Model::getGenProperties() const
+    {
+        return m_generated_properties_;
+    }
+
+    void Model::addSubInstances(Model* sub_instance_, double num_sub_instances_)
+    {
+        // Get instance name
+        const String& sub_instance_name = sub_instance_->getInstanceName();
+
+        // Check if the instance exists
+        if(m_sub_instances_->keyExist(sub_instance_name))
+        {
+            const String& error_msg = "[Error] " + m_instance_name_ + 
+            " -> Instance exists (" + sub_instance_name + ")";
+            throw Exception(error_msg);
+        }
+
+        // Check if the num_sub_instances_ is a positive number
+        ASSERT((num_sub_instances_ >= 0), "[Error] " + m_instance_name_ + 
+        " -> Invalid number of instance (" + String(num_sub_instances_) + ")");
+
+        // Add the instance
+        m_sub_instances_->set(sub_instance_name, new SubModel(sub_instance_, num_sub_instances_));
+        return;
+    }
+
+    Model* Model::getSubInstance(const String& sub_instance_name_)
+    {
+        // Throw an Exception if the instance already exists
+        if(!m_sub_instances_->keyExist(sub_instance_name_))
+        {
+            const String& error_msg = "[Error] " + m_instance_name_ + 
+            " -> Instance not exists (" + sub_instance_name_ + ")";
+            throw Exception(error_msg);
+        }
+
+        return m_sub_instances_->get(sub_instance_name_)->getModel();
+    }
+
+    const Model* Model::getSubInstance(const String& sub_instance_name_) const
+    {
+        // Throw an Exception if the instance does not exist
+        if(!m_sub_instances_->keyExist(sub_instance_name_))
+        {
+            const String& error_msg = "[Error] " + m_instance_name_ + 
+            " -> Instance not exists (" + sub_instance_name_ + ")";
+            throw Exception(error_msg);
+        }
+
+        return m_sub_instances_->get(sub_instance_name_)->getModel();
+    }
+
+    bool Model::hasSubInstance(const String& sub_instance_name_) const
+    {
+        return m_sub_instances_->keyExist(sub_instance_name_);
+    }
+
+    void Model::addAreaResult(Result* area_)
+    {
+        const String& area_name = area_->getName();
+
+        // Throw an Exception if the area already exists
+        if(m_area_map_->keyExist(area_name))
+        {
+            const String& error_msg = "Internal error: area (" + area_name + 
+                ") exists";
+            throw Exception(error_msg);
+        }
+
+        // Add the area
+        m_area_map_->set(area_name, area_);
+        return;
+    }
+
+    Result* Model::getAreaResult(const String& area_name_)
+    {
+        return m_area_map_->get(area_name_);
+    }
+
+    const Result* Model::getAreaResult(const String& area_name_) const
+    {
+        return m_area_map_->get(area_name_);
+    }
+
+    bool Model::hasAreaResult(const String& area_name_) const
+    {
+        return m_area_map_->keyExist(area_name_);
+    }
+
+    void Model::addNddPowerResult(Result* ndd_power_)
+    {
+        const String& ndd_power_name = ndd_power_->getName();
+
+        // Throw an Exception if the ndd_power already exists
+        if(m_ndd_power_map_->keyExist(ndd_power_name))
+        {
+            const String& error_msg = "Internal error: ndd_power (" + ndd_power_name + 
+                ") exists";
+            throw Exception(error_msg);
+        }
+
+        // Add the ndd_power
+        m_ndd_power_map_->set(ndd_power_name, ndd_power_);
+        return;
+    }
+
+    Result* Model::getNddPowerResult(const String& ndd_power_name_)
+    {
+        return m_ndd_power_map_->get(ndd_power_name_);
+    }
+
+    const Result* Model::getNddPowerResult(const String& ndd_power_name_) const
+    {
+        return m_ndd_power_map_->get(ndd_power_name_);
+    }
+
+    bool Model::hasNddPowerResult(const String& ndd_power_name_) const
+    {
+        return m_ndd_power_map_->keyExist(ndd_power_name_);
+    }
+
+    void Model::addEventResult(Result* event_)
+    {
+        const String& event_name = event_->getName();
+
+        // Throw an Exception if the event already exists
+        if(m_event_map_->keyExist(event_name))
+        {
+            const String& error_msg = "Internal error: event (" + event_name + 
+                ") exists";
+            throw Exception(error_msg);
+        }
+
+        // Add the event
+        m_event_map_->set(event_name, event_);
+        return;
+    }
+
+    Result* Model::getEventResult(const String& event_name_)
+    {
+        return m_event_map_->get(event_name_);
+    }
+
+    const Result* Model::getEventResult(const String& event_name_) const
+    {
+        return m_event_map_->get(event_name_);
+    }
+
+    bool Model::hasEventResult(const String& event_name_) const
+    {
+        return m_event_map_->keyExist(event_name_);
+    }
+
+    const TechModel* Model::getTechModel() const
+    {
+        return m_tech_model_;
+    }
+
+    const void* Model::parseQuery(const String& query_type_, const String& query_hier_, const String& query_sub_field_)
+    {
+        // Break query by hierarchy separator
+        vector<String> hier_split = query_hier_.splitByString(HIERARCHY_SEPARATOR);
+
+        // Check if the query_hier matches the instance name
+        ASSERT((hier_split[0] == m_instance_name_), "[Error] " + 
+                m_instance_name_ + " -> Mismatch in instance name (" + 
+                hier_split[0] + ")");
+
+        // If there is no more hierarchy separator, this process the query
+        if(hier_split.size() == 1)
+        {
+            // Query the model
+            return processQuery(query_type_, query_sub_field_);
+        }
+        else
+        {
+            // Reconstruct the query
+            String temp_query_hier = hier_split[1];
+            for(int i = 2; i < (int)hier_split.size(); ++i)
+            {
+                temp_query_hier += HIERARCHY_SEPARATOR + hier_split[i];
+            }
+
+            // Get sub instance's name
+            const String& temp_sub_instance_name = hier_split[1];
+            ASSERT(m_sub_instances_->keyExist(temp_sub_instance_name), "[Error] " + 
+                    m_instance_name_ + " -> No sub-instances queried (" + 
+                    temp_sub_instance_name + ")");
+
+            return m_sub_instances_->get(temp_sub_instance_name)->getModel()->parseQuery(query_type_, temp_query_hier, query_sub_field_);
+        }
+    }
+
+    const void* Model::processQuery(const String& query_type_, const String& query_sub_field_)
+    {
+        if(query_type_ == "Property")
+        {
+            return getProperties();
+        }
+        else if(query_type_ == "Parameter")
+        {
+            return getParameters();
+        }
+        else if(query_type_.contain("Hier"))
+        {
+            return this;
+        }
+        else if(query_type_ == "Area")
+        {
+            return queryArea(query_sub_field_);
+        }
+        else if(query_type_ == "NddPower")
+        {
+            return queryNddPower(query_sub_field_);
+        }
+        else if(query_type_ == "Energy")
+        {
+            return queryEventEnergyCost(query_sub_field_);
+        }
+        else 
+        {
+            const String& error_msg = "[Error] " + m_instance_name_ + " -> Unknown query type (" + query_type_ + ")";
+            throw Exception(error_msg);
+            return NULL;
+        }
+    }
+
+    const Result* Model::queryArea(const String& area_name_) const
+    {
+        ASSERT(m_area_map_->keyExist(area_name_), "[Error] " + m_instance_name_ + 
+                " -> Unknown queried area name (" + area_name_ + ")");
+        return m_area_map_->get(area_name_);
+    }
+
+    const Result* Model::queryNddPower(const String& ndd_power_name_)
+    {
+        ASSERT(m_ndd_power_map_->keyExist(ndd_power_name_), "[Error] " + m_instance_name_ + 
+                " -> Unknown queried ndd power name (" + ndd_power_name_ + ")");
+
+        use("Idle");
+        return m_ndd_power_map_->get(ndd_power_name_);
+    }
+
+    const Result* Model::queryEventEnergyCost(const String& event_name_)
+    {
+        ASSERT(m_event_map_->keyExist(event_name_), "[Error] " + m_instance_name_ + 
+                " -> Unknown queried event name (" + event_name_ + ")");
+
+        use(event_name_);
+        return m_event_map_->get(event_name_);
+    }
+
+    // Update checks whether the model needs updating, whether all properties have been specified,
+    // and calls updateModel if update is necessary
+    void Model::construct()
+    {
+        // Model should not be constructed yet
+        ASSERT(!m_constructed_, "[Error] " + getInstanceName() + " -> Cannot construct an already contructed model!");
+        // Check if whether all needed parameters are defined
+        checkParameters();
+        constructModel();
+        m_constructed_ = true;
+        m_updated_ = false;
+        m_evaluated_ = false;        
+        return;
+    }
+    
+    // Update checks whether the model needs updating, whether all properties have been specified,
+    // and calls updateModel if update is necessary
+    void Model::update()
+    {
+        // Model should be constructed
+        ASSERT(m_constructed_, "[Error] " + getInstanceName() + " -> Cannot update an unconstructed model!");
+        // If the model needs updating (due to property change)
+        // an update is necessary
+        if (!m_updated_)
+        {
+            // Check if all properties needed exist
+            checkProperties();
+            updateModel();
+            m_updated_ = true;
+            m_evaluated_ = false;
+        }        
+        return;
+    }
+
+    // Evaluate checks whether the model needs to be evaluated. 
+    void Model::evaluate()
+    {
+        // Model should be constructed
+        ASSERT(m_constructed_, "[Error] " + getInstanceName() + " -> Cannot evaluate an unconstructed model!");
+        // Model should be updated
+        ASSERT(m_updated_, "[Error] " + getInstanceName() + " -> Cannot evaluate without first updating!");
+        // If the model needs evaluating
+        if (!m_evaluated_)
+        {
+            evaluateModel();
+            m_evaluated_ = true;
+        }
+
+        return;
+    }
+
+    void Model::use(const String& event_name_)
+    {
+        useModel(event_name_);
+        return;
+    }
+    
+    void Model::use()
+    {
+        useModel();
+        return;
+    }
+
+    // By default, update model will iterate through all sub-instances and do updateModel on them
+    void Model::updateModel()
+    {
+        Map<SubModel*>::Iterator iter = m_sub_instances_->begin();
+        Map<SubModel*>::Iterator end = m_sub_instances_->end();
+        while (iter != end)
+        {
+            iter->second->getModel()->update();
+            iter++;
+        }        
+        return;
+    }
+
+    // By default, update model will iterate through all sub-instances and do updateModel on them
+    void Model::evaluateModel()
+    {
+        Map<SubModel*>::Iterator iter = m_sub_instances_->begin();
+        Map<SubModel*>::Iterator end = m_sub_instances_->end();
+        while (iter != end)
+        {
+            iter->second->getModel()->evaluate();
+            iter++;
+        }        
+        return;
+    }
+
+    void Model::useModel(const String& /* event_name_ */)
+    {}
+
+    void Model::useModel()
+    {}
+
+    void Model::printHierarchy(const String& query_type_, const String& query_sub_field_, const String& prepend_str_, int detail_level_, ostream& ost_) const
+    {
+        if(query_type_ == "InstHier")
+        {
+            ost_ << prepend_str_ << getInstanceName() << endl;
+            printInstHierarchy(prepend_str_, detail_level_, ost_);
+            //if(detail_level_ > 0)
+            //{
+                //for(Map<SubModel*>::ConstIterator it = m_sub_instances_->begin(); it != m_sub_instances_->end(); ++it)
+                //{
+                    //const Model* sub_model = (it->second)->getModel();
+                    //String temp_prepend_str = prepend_str_ + "    ";
+                    //sub_model->printHierarchy(query_type_, query_sub_field_, temp_prepend_str, detail_level_ - 1, ost_);
+                //}
+            //}
+        }
+        else
+        {
+            const Map<Result*>* result_map;
+
+            if(query_type_ == "AreaHier")
+            {
+                result_map = m_area_map_;
+            }
+            else if(query_type_ == "NddPowerHier")
+            {
+                result_map = m_ndd_power_map_;
+            }
+            else if(query_type_ == "EventHier")
+            {
+                result_map = m_event_map_;
+            }
+            else
+            {
+                const String& error_msg = "[Error] " + m_instance_name_ + " -> Unknown query type (" + query_type_ + ")";
+                throw Exception(error_msg);
+                return;
+            }
+
+            if(query_sub_field_ == "")
+            {
+                for(Map<Result*>::ConstIterator it = result_map->begin(); it != result_map->end(); ++it)
+                {
+                    const Result* result = it->second;
+                    ost_ << prepend_str_ << getInstanceName() << "->" << result->getName() << endl;
+                    result->printHierarchy(prepend_str_, detail_level_, ost_);
+                }
+            }
+            else
+            {
+                const Result* result = result_map->get(query_sub_field_);
+                ost_ << prepend_str_ << getInstanceName() << "->" << result->getName() << endl;
+                result->printHierarchy(prepend_str_, detail_level_, ost_);
+            }
+        }
+        return;
+    }
+
+    void Model::printInstHierarchy(const String& prepend_str_, int detail_level_, ostream& ost_) const
+    {
+        if(detail_level_ > 0)
+        {
+            for(Map<SubModel*>::ConstIterator it = m_sub_instances_->begin(); it != m_sub_instances_->end(); ++it)
+            {
+                const Model* sub_model = it->second->getModel();
+                String temp_prepend_str = prepend_str_ + "    ";
+
+                ost_ << prepend_str_ << " |--" << sub_model->getInstanceName() << endl;
+                sub_model->printInstHierarchy(temp_prepend_str, detail_level_ - 1, ost_);
+            }
+        }
+        return;
+    }
+
+    Model* Model::clone() const
+    {
+        throw Exception(getInstanceName() + " -> Cannot be cloned!");
+    }
+    
+    Model::Model(const Model& model_)
+    {
+        // Copy instance's name
+        m_instance_name_ = model_.m_instance_name_;
+
+        // Clone properties
+        m_properties_ = model_.m_properties_->clone();
+
+        // Clone instances
+        m_sub_instances_ = clonePtrMap(model_.m_sub_instances_);
+
+        // Clone events, area, ndd_power
+        m_event_map_ = clonePtrMap(model_.m_event_map_);
+        m_area_map_ = clonePtrMap(model_.m_area_map_);
+        m_ndd_power_map_ = clonePtrMap(model_.m_ndd_power_map_);
+
+        // Copy tech model pointer
+        m_tech_model_ = model_.m_tech_model_;
+    }
+
+} // namespace DSENT
+
diff --git a/ext/dsent/model/Model.h b/ext/dsent/model/Model.h
new file mode 100644 (file)
index 0000000..9e516d5
--- /dev/null
@@ -0,0 +1,223 @@
+#ifndef __DSENT_MODEL_MODEL_H__
+#define __DSENT_MODEL_MODEL_H__
+
+#include <vector>
+
+#include "util/CommonType.h"
+
+namespace DSENT
+{
+    using std::vector;
+
+    class TechModel;
+    class Result;
+
+    // Base class for all the models
+    class Model
+    {
+        protected:
+            class SubModel
+            {
+                public:
+                    SubModel(Model* model_, double num_models_);
+                    ~SubModel();
+
+                public:
+                    Model* getModel();
+                    const Model* getModel() const;
+                    double getNumModels() const;
+
+                    SubModel* clone() const;
+
+                protected:
+                    SubModel(const SubModel& sub_model_);
+
+                private:
+                    // Pointer to the actual model instance
+                    Model* m_model_;
+                    // Number of models are added
+                    double m_num_models_;
+            };
+
+        public:
+            // Model Constants
+            static const char TYPE_SEPARATOR[];
+            static const char HIERARCHY_SEPARATOR[];
+            static const char SUBFIELD_SEPARATOR[];
+            static const char DETAIL_SEPARATOR[];
+
+        public:
+            Model(const String& instance_name_, const TechModel* tech_model_);
+            virtual ~Model();
+
+        public:
+            // Set the name of this instance
+            void setInstanceName(const String& instance_name_);
+            // Get the name of this instance
+            const String& getInstanceName() const;
+
+            // Set if the model is the top model
+            void setIsTopModel(bool is_top_model_);
+            bool getIsTopModel() const;
+
+            // Add a parameter name (with and without default)
+            void addParameterName(const String& parameter_name_);
+            void addParameterName(const String& parameter_name_, const String& parameter_default_);
+            const vector<String>* getParameterNames() const;
+            
+            // Add a property name
+            void addPropertyName(const String& property_name_);
+            void addPropertyName(const String& property_name_, const String& property_default_);
+            const vector<String>* getPropertyNames() const;
+
+            // Check if all parameters needed exist in the m_parameters_
+            void checkParameters() const;
+            // Check if all properties needed exist in the m_properties_
+            void checkProperties() const;
+
+            // Get the pointer to parameters
+            const ParameterMap* getParameters() const;
+            const String getParameter(const String& parameter_name_) const;
+            void setParameter(const String& parameter_name_, const String& parameter_value_);
+            
+            // Get the pointer to properties
+            const PropertyMap* getProperties() const;
+            const String getProperty(const String& property_name_) const;
+            void setProperty(const String& property_name_, const String& property_value_);
+
+            // Get the pointer to generated properties
+            PropertyMap* getGenProperties();
+            const PropertyMap* getGenProperties() const;
+
+            // Add an instance to this model. num_sub_instances_ specifies the 
+            // number of the same instance is added.
+            void addSubInstances(Model* sub_instance_, double num_sub_instances_);
+            // Get an instance by name.            
+            Model* getSubInstance(const String& sub_instance_name_);
+            const Model* getSubInstance(const String& sub_instance_name_) const;
+            // Check if an instance exists
+            bool hasSubInstance(const String& sub_instance_name_) const;
+
+            // Add a new area
+            void addAreaResult(Result* area_);
+            // Get the pointer to an area. The area is specified by name.
+            Result* getAreaResult(const String& area_name_);
+            const Result* getAreaResult(const String& area_name_) const;
+            // Check if an area exists
+            bool hasAreaResult(const String& area_name_) const;
+
+            // Add a new ndd_power
+            void addNddPowerResult(Result* ndd_power_);
+            // Get the pointer to an ndd_power. The ndd_power is specified by name.
+            Result* getNddPowerResult(const String& ndd_power_name_);
+            const Result* getNddPowerResult(const String& ndd_power_name_) const;
+            // Check if a ndd_power exists
+            bool hasNddPowerResult(const String& ndd_power_name_) const;
+
+            // Add a new event
+            void addEventResult(Result* event_);
+            // Get the pointer to an event. The event is specified by name.
+            Result* getEventResult(const String& event_name_);
+            const Result* getEventResult(const String& event_name_) const;
+            // Check if an event exists
+            bool hasEventResult(const String& event_name_) const;
+
+            // Get the pointer to the TechModel.
+            const TechModel* getTechModel() const;
+
+            // Clone and return a new instance
+            virtual Model* clone() const;
+
+            // Checks to make sure all required parameters are present, makes sure that the model
+            // has not been constructed yet, and calls constructModel. This function is not meant
+            // to be overwritten by child classes; constructModel should be overwritten instead
+            void construct();
+            // Update checks whether the model needs updating, whether all properties have been specified,
+            // and calls updateModel if update is necessary. This function is not meant
+            // to be overwritten by child classes; updateModel should be overwritten instead
+            void update();
+            // Evaluate checks whether the model needs to be evaluated. Note that this function is
+            // not meant to be overwritten by child classes; evaluateModel should be overwritten
+            // instead
+            void evaluate();
+            void use(const String& event_name_);
+            void use();
+
+            // Resolve query hierarchy and process query
+            const void* parseQuery(const String& query_type_, const String& query_hier_, const String& query_sub_field_);
+            // Process the query
+            virtual const void* processQuery(const String& query_type_, const String& query_sub_field_);
+
+            // Print hierarchically
+            void printHierarchy(const String& query_type_, const String& query_sub_field_, const String& prepend_str_, int detail_level_, ostream& ost_) const;
+            void printInstHierarchy(const String& prepend_str_, int detail_level_, ostream& ost_) const;
+
+        protected:
+            // Query area
+            const Result* queryArea(const String& area_name_) const;
+            // Query non-data-dependent power
+            const Result* queryNddPower(const String& ndd_power_name_);
+            // Query event energy cost
+            const Result* queryEventEnergyCost(const String& event_name_);
+            
+            // Constructs the model
+            virtual void constructModel() = 0;
+            // Updates timing related information of the model
+            virtual void updateModel();
+            // Evaluate non data dependent power of the model
+            virtual void evaluateModel();
+            virtual void useModel(const String& event_name_);
+            virtual void useModel();
+
+        private:
+            // Private copy constructor. Use clone to perform copy operation.
+            Model(const Model& model_);
+
+        private:
+            // Name of this instance
+            String m_instance_name_;
+            // Set if this model is the top model
+            bool m_is_top_model_;
+            
+            // Contains the parameters of a model
+            // Parameters are needed in order to constructModel() and CANNOT be
+            // changed after constructModel() has been called
+            ParameterMap* m_parameters_;
+            // Contains the names of all model parameters
+            vector<String>* m_parameter_names_;
+            // Contains the properties of a model
+            // Properties are required in order to updateModel() and CAN be
+            // changed be changed after constructModel(). Call updateModel()
+            // after properties have been changed to use the new properties
+            PropertyMap* m_properties_;
+            // Contains the property names needed to update the model
+            vector<String>* m_property_names_;
+            // Contains generated properties of the model
+            // Generated properties are used mostly as a scratch space for
+            // variables used in the model that must be passed from one
+            // function to another
+            PropertyMap* m_generated_properties_;
+            
+            // Contains the instances of this model
+            Map<SubModel*>* m_sub_instances_;
+            // Contains the area resulst of a model
+            Map<Result*>* m_area_map_;
+            // Contains the noo power results of a model
+            Map<Result*>* m_ndd_power_map_;
+            // Contains the event results of a model
+            Map<Result*>* m_event_map_;
+            // Pointer to a TechModel which contains the technology information
+            const TechModel* m_tech_model_;
+            
+            // Set when a model is constructed
+            bool m_constructed_;
+            // Set when a model is updated
+            bool m_updated_;
+            // Set when a model is evaluated
+            bool m_evaluated_;
+            
+    }; // class Model
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_MODEL_H__
+
diff --git a/ext/dsent/model/ModelGen.cc b/ext/dsent/model/ModelGen.cc
new file mode 100644 (file)
index 0000000..06957d6
--- /dev/null
@@ -0,0 +1,306 @@
+#include "model/ModelGen.h"
+
+#include <iostream>
+
+#include "model/Model.h"
+// Standard cells
+#include "model/std_cells/StdCell.h"
+#include "model/std_cells/INV.h"
+#include "model/std_cells/NAND2.h"
+#include "model/std_cells/NOR2.h"
+#include "model/std_cells/MUX2.h"
+#include "model/std_cells/XOR2.h"
+#include "model/std_cells/DFFQ.h"
+#include "model/std_cells/LATQ.h"
+#include "model/std_cells/ADDF.h"
+#include "model/std_cells/OR2.h"
+#include "model/std_cells/AND2.h"
+#include "model/std_cells/BUF.h"
+// Electrical functional units
+#include "model/electrical/TestModel.h"
+#include "model/electrical/RippleAdder.h"
+#include "model/electrical/Multiplexer.h"
+#include "model/electrical/MultiplexerCrossbar.h"
+#include "model/electrical/OR.h"
+#include "model/electrical/Decoder.h"
+#include "model/electrical/DFFRAM.h"
+#include "model/electrical/MatrixArbiter.h"
+#include "model/electrical/SeparableAllocator.h"
+#include "model/electrical/router/Router.h"
+#include "model/electrical/RepeatedLink.h"
+#include "model/electrical/BroadcastHTree.h"
+// Optical functional units
+#include "model/optical/OpticalLinkBackendTx.h"
+#include "model/optical/OpticalLinkBackendRx.h"
+#include "model/optical/SWMRLink.h"
+#include "model/optical/SWSRLink.h"
+#include "model/optical/LaserSource.h"
+#include "model/optical/ThrottledLaserSource.h"
+#include "model/optical/RingModulator.h"
+#include "model/optical/RingDetector.h"
+// Networks
+#include "model/network/ElectricalMesh.h"
+#include "model/network/ElectricalClos.h"
+#include "model/network/PhotonicClos.h"
+
+namespace DSENT
+{
+    using std::cout;
+    using std::endl;
+
+    //TODO: Eventually automate the creation of this file
+
+    Model* ModelGen::createModel(const String& model_name_, const String& instance_name_, const TechModel* tech_model_)
+    {
+        Log::printLine("ModelGen::createModel -> " + model_name_);
+        
+        if("INV" == model_name_)
+        {
+            return new INV(instance_name_, tech_model_);
+        }
+        else if("NAND2" == model_name_)
+        {
+            return new NAND2(instance_name_, tech_model_);
+        }
+        else if("NOR2" == model_name_)
+        {
+            return new NOR2(instance_name_, tech_model_);
+        }
+        else if("MUX2" == model_name_)
+        {
+            return new MUX2(instance_name_, tech_model_);
+        }
+        else if("XOR2" == model_name_)
+        {
+            return new XOR2(instance_name_, tech_model_);
+        }
+        else if("DFFQ" == model_name_)
+        {
+            return new DFFQ(instance_name_, tech_model_);
+        }
+        else if("LATQ" == model_name_)
+        {
+            return new LATQ(instance_name_, tech_model_);
+        }
+        else if("ADDF" == model_name_)
+        {
+            return new ADDF(instance_name_, tech_model_);
+        }
+        else if("OR2" == model_name_)
+        {
+            return new OR2(instance_name_, tech_model_);
+        }
+        else if("AND2" == model_name_)
+        {
+            return new AND2(instance_name_, tech_model_);
+        }
+        else if("BUF" == model_name_)
+        {
+            return new BUF(instance_name_, tech_model_);
+        }
+        else if("TestModel" == model_name_)
+        {
+            return new TestModel(instance_name_, tech_model_);
+        }
+        else if("RippleAdder" == model_name_)
+        {
+            return new RippleAdder(instance_name_, tech_model_);
+        }
+        else if("Multiplexer" == model_name_)
+        {
+            return new Multiplexer(instance_name_, tech_model_);
+        }
+        else if("OR" == model_name_)
+        {
+            return new OR(instance_name_, tech_model_);
+        }
+        else if("MultiplexerCrossbar" == model_name_)
+        {
+            return new MultiplexerCrossbar(instance_name_, tech_model_);
+        }
+        else if("Decoder" == model_name_)
+        {
+            return new Decoder(instance_name_, tech_model_);
+        }
+        else if("DFFRAM" == model_name_)
+        {
+            return new DFFRAM(instance_name_, tech_model_);
+        }
+        else if("MatrixArbiter" == model_name_)
+        {
+            return new MatrixArbiter(instance_name_, tech_model_);
+        }
+        else if("SeparableAllocator" == model_name_)
+        {
+            return new SeparableAllocator(instance_name_, tech_model_);
+        }
+        else if("Router" == model_name_)
+        {
+            return new Router(instance_name_, tech_model_);
+        }
+        else if("OpticalLinkBackendTx" == model_name_)
+        {
+            return new OpticalLinkBackendTx(instance_name_, tech_model_);
+        }
+        else if("OpticalLinkBackendRx" == model_name_)
+        {
+            return new OpticalLinkBackendRx(instance_name_, tech_model_);
+        }
+        else if("SWMRLink" == model_name_)
+        {
+            return new SWMRLink(instance_name_, tech_model_);
+        }
+        else if("SWSRLink" == model_name_)
+        {
+            return new SWSRLink(instance_name_, tech_model_);
+        }
+        else if("LaserSource" == model_name_)
+        {
+            return new LaserSource(instance_name_, tech_model_);
+        }
+        else if("ThrottledLaserSource" == model_name_)
+        {
+            return new ThrottledLaserSource(instance_name_, tech_model_);
+        }
+        else if("RingModulator" == model_name_)
+        {
+            return new RingModulator(instance_name_, tech_model_);
+        }
+        else if("RingDetector" == model_name_)
+        {
+            return new RingDetector(instance_name_, tech_model_);
+        }
+        else if("RepeatedLink" == model_name_)
+        {
+            return new RepeatedLink(instance_name_, tech_model_);
+        }
+        else if("BroadcastHTree" == model_name_)
+        {
+            return new BroadcastHTree(instance_name_, tech_model_);
+        }
+        else if("ElectricalMesh" == model_name_)
+        {
+            return new ElectricalMesh(instance_name_, tech_model_);
+        }
+        else if("ElectricalClos" == model_name_)
+        {
+            return new ElectricalClos(instance_name_, tech_model_);
+        }
+        else if("PhotonicClos" == model_name_)
+        {
+            return new PhotonicClos(instance_name_, tech_model_);
+        }
+        else
+        {
+            const String& error_msg = "[Error] Invalid model name (" + model_name_ + ")";
+            throw Exception(error_msg);
+            return NULL;
+        }
+        return NULL;
+    }
+    
+    StdCell* ModelGen::createStdCell(const String& std_cell_name_, const String& instance_name_, const TechModel* tech_model_)
+    {
+        Log::printLine("ModelGen::createStdCell -> " + std_cell_name_);
+        
+        if("INV" == std_cell_name_)
+        {
+            return new INV(instance_name_, tech_model_);
+        }
+        else if("NAND2" == std_cell_name_)
+        {
+            return new NAND2(instance_name_, tech_model_);
+        }
+        else if("NOR2" == std_cell_name_)
+        {
+            return new NOR2(instance_name_, tech_model_);
+        }
+        else if("MUX2" == std_cell_name_)
+        {
+            return new MUX2(instance_name_, tech_model_);
+        }
+        else if("XOR2" == std_cell_name_)
+        {
+            return new XOR2(instance_name_, tech_model_);
+        }
+        else if("DFFQ" == std_cell_name_)
+        {
+            return new DFFQ(instance_name_, tech_model_);
+        }
+        else if("LATQ" == std_cell_name_)
+        {
+            return new LATQ(instance_name_, tech_model_);
+        }
+        else if("ADDF" == std_cell_name_)
+        {
+            return new ADDF(instance_name_, tech_model_);
+        }
+        else if("OR2" == std_cell_name_)
+        {
+            return new OR2(instance_name_, tech_model_);
+        }
+        else if("AND2" == std_cell_name_)
+        {
+            return new AND2(instance_name_, tech_model_);
+        }
+        else if("BUF" == std_cell_name_)
+        {
+            return new BUF(instance_name_, tech_model_);
+        }
+        else
+        {
+            const String& error_msg = "[Error] Invalid Standard Cell name (" + std_cell_name_ + ")";
+            throw Exception(error_msg);
+            return NULL;
+        }
+        return NULL;
+    }
+
+    ElectricalModel* ModelGen::createRAM(const String& ram_name_, const String& instance_name_, const TechModel* tech_model_)
+    {
+        Log::printLine("ModelGen::createRAM -> " + ram_name_);
+        
+        if("DFFRAM" == ram_name_)
+        {
+            return new DFFRAM(instance_name_, tech_model_);
+        }
+        else
+        {
+            const String& error_msg = "[Error] Invalid RAM name (" + ram_name_ + ")";
+            throw Exception(error_msg);
+            return NULL;
+        }
+        return NULL;
+    }
+
+    ElectricalModel* ModelGen::createCrossbar(const String& crossbar_name_, const String& instance_name_, const TechModel* tech_model_)
+    {
+        Log::printLine("ModelGen::createCrossbar -> " + crossbar_name_);
+        
+        if("MultiplexerCrossbar" == crossbar_name_)
+        {
+            return new MultiplexerCrossbar(instance_name_, tech_model_);
+        }
+        else
+        {
+            const String& error_msg = "[Error] Invalid Crossbar name (" + crossbar_name_ + ")";
+            throw Exception(error_msg);
+            return NULL;
+        }
+        return NULL;
+    }
+    //-----------------------------------------------------------------
+
+    void ModelGen::printAvailableModels()
+    {
+        // TODO: Need more descriptions
+        cout << "INV NAND2 NOR2 MUX2 XOR2 DFFQ LATQ ADDF OR2 AND2 BUF" << endl;
+        cout << "RippleAdder Multiplexer OR RepeatedLink BroadcastHTree" << endl;
+        cout << "MultiplexerCrossbar Decoder DFFRAM MatrixArbiter SeparableAllocator Router" << endl;
+        cout << "OpticalLinkBackendTx OpticalLinkBackendRx SWMRLink SWSRLink" << endl;
+        cout << "LaserSource ThrottledLaserSource RingModulator RingDetector" << endl;
+        cout << "ElectricalMesh ElectricalClos PhotonicClos" << endl;
+        return;
+    }
+} // namespace DSENT
+
diff --git a/ext/dsent/model/ModelGen.h b/ext/dsent/model/ModelGen.h
new file mode 100644 (file)
index 0000000..c11f435
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef __DSENT_MODEL_MODELGEN_H__
+#define __DSENT_MODEL_MODELGEN_H__
+
+#include "util/CommonType.h"
+
+namespace DSENT
+{
+    class Model;
+    class ElectricalModel;
+    class StdCell;
+    class TechModel;
+
+    class ModelGen
+    {
+        public:
+            // Create the model corresponding to the given String
+            static Model* createModel(const String& model_name_, const String& instance_name_, const TechModel* tech_model_);
+            // Create the standard cell corresponding to the given String
+            static StdCell* createStdCell(const String& std_cell_name_, const String& instance_name_, const TechModel* tech_model_);
+            // Create the ram corresponding to the given String
+            static ElectricalModel* createRAM(const String& ram_name_, const String& instance_name_, const TechModel* tech_model_);
+            // Create the crossbar corresponding to the given String
+            static ElectricalModel* createCrossbar(const String& crossbar_name_, const String& instance_name_, const TechModel* tech_model_);
+            // Print the available models
+            static void printAvailableModels();
+    };
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_MODELGEN_H__
+
diff --git a/ext/dsent/model/OpticalModel.cc b/ext/dsent/model/OpticalModel.cc
new file mode 100644 (file)
index 0000000..7236d6b
--- /dev/null
@@ -0,0 +1,277 @@
+#include "model/OpticalModel.h"
+
+#include "model/PortInfo.h"
+#include "model/EventInfo.h"
+#include "model/optical_graph/OpticalWaveguide.h"
+#include "model/optical_graph/OpticalNode.h"
+#include "model/optical_graph/OpticalLaser.h"
+#include "model/optical_graph/OpticalModulator.h"
+#include "model/optical_graph/OpticalFilter.h"
+#include "model/optical_graph/OpticalDetector.h"
+#include "model/optical_graph/OpticalWavelength.h"
+
+namespace DSENT
+{
+    OpticalModel::OpticalModel(const String& instance_name_, const TechModel* tech_model_)
+        : ElectricalModel(instance_name_, tech_model_)
+    {
+        m_optical_input_ports_ = new Map<PortInfo*>;
+        m_optical_output_ports_ = new Map<PortInfo*>;
+
+        m_waveguides_ = new Map<OpticalWaveguide*>;
+        m_lasers_ = new Map<OpticalLaser*>;
+        m_modulators_ = new Map<OpticalModulator*>;
+        m_filters_ = new Map<OpticalFilter*>;
+        m_detectors_ = new Map<OpticalDetector*>;
+    }
+
+    OpticalModel::~OpticalModel()
+    {
+        delete m_optical_input_ports_;
+        delete m_optical_output_ports_;
+        deletePtrMap<OpticalWaveguide>(m_waveguides_);
+        deletePtrMap<OpticalLaser>(m_lasers_);
+        deletePtrMap<OpticalModulator>(m_modulators_);
+        deletePtrMap<OpticalFilter>(m_filters_);
+        deletePtrMap<OpticalDetector>(m_detectors_);
+        m_optical_input_ports_ = NULL;
+        m_optical_output_ports_ = NULL;
+        m_waveguides_ = NULL;
+        m_lasers_ = NULL;
+        m_modulators_ = NULL;
+        m_filters_ = NULL;
+        m_detectors_ = NULL;
+    }
+
+    // Connect an optical port (input or output) to some OpticalWaveguide
+    void OpticalModel::opticalPortConnect(OpticalModel* connect_model_, const String& port_name_, const String& waveguide_name_)
+    {
+        // Check that the connecting waveguide exists
+        ASSERT(m_waveguides_->keyExist(waveguide_name_), "[Error] " + getInstanceName() +
+            " -> Waveguide '" + waveguide_name_ + "' does not exist!");
+            
+        // Check whether the port name is an input or output, assertion error if neither
+        bool is_input = connect_model_->getOpticalInputs()->keyExist(port_name_);
+        bool is_output = connect_model_->getOpticalOutputs()->keyExist(port_name_);                        
+        ASSERT(is_input || is_output, "[Error] " + getInstanceName() + " -> Model '" + connect_model_->getInstanceName() + 
+            "' does not have a port named '" + port_name_ + "'!");
+        
+        // Get the two waveguides
+        OpticalWaveguide* port_waveguide = connect_model_->getWaveguide(port_name_);
+        OpticalWaveguide* connect_waveguide = getWaveguide(waveguide_name_);
+        
+        // Check that the two waveguides expect the same wavelengths
+        ASSERT((port_waveguide->getWavelengths().first == connect_waveguide->getWavelengths().first) &&
+            (port_waveguide->getWavelengths().second == connect_waveguide->getWavelengths().second),
+            "[Error] " + getInstanceName() + " -> Optical port expects different wavelengths for Model '" + 
+            connect_model_->getInstanceName() + "." + port_name_ + "' and waveguide '" + waveguide_name_ + "'!");
+        
+        if(is_input)
+        {
+            connect_waveguide->addDownstreamNode(port_waveguide);
+        }
+        else if(is_output)
+        {
+            port_waveguide->addDownstreamNode(connect_waveguide);
+        }
+    }
+        
+    //Get Waveguides
+    const Map<OpticalWaveguide*>* OpticalModel::getWaveguides() const
+    {
+        return m_waveguides_;
+    }
+    
+    OpticalWaveguide* OpticalModel::getWaveguide(const String& name_)
+    {
+        return m_waveguides_->get(name_);
+    }
+
+    //Get Lasers
+    const Map<OpticalLaser*>* OpticalModel::getLasers() const
+    {
+        return m_lasers_;
+    }
+
+    OpticalLaser* OpticalModel::getLaser(const String& name_)
+    {
+        return m_lasers_->get(name_);
+    }
+
+    //Get Modulators
+    const Map<OpticalModulator*>* OpticalModel::getModulators() const
+    {
+        return m_modulators_;
+    }
+    
+    OpticalModulator* OpticalModel::getModulator(const String& name_)
+    {
+        return m_modulators_->get(name_);
+    }
+
+    //Get Filters
+    const Map<OpticalFilter*>* OpticalModel::getFilters() const
+    {
+        return m_filters_;
+    }
+    
+    OpticalFilter* OpticalModel::getFilter(const String& name_)
+    {
+        return m_filters_->get(name_);
+    }
+
+    //Get Detectors
+    const Map<OpticalDetector*>* OpticalModel::getDetectors() const
+    {
+        return m_detectors_;
+    }
+
+    OpticalDetector* OpticalModel::getDetector(const String& name_)
+    {
+        return m_detectors_->get(name_);
+    }
+        
+    //Get Inputs
+    const Map<PortInfo*>* OpticalModel::getOpticalInputs() const
+    {
+        return m_optical_input_ports_;
+    }
+    
+    PortInfo* OpticalModel::getOpticalInputPort(const String& name_)
+    {
+        ASSERT(m_optical_input_ports_->keyExist(name_), "[Error] " + getInstanceName() +
+                " -> Input port (" + name_ + ") does not exist");
+
+        return m_optical_input_ports_->get(name_);
+    }
+
+    const PortInfo* OpticalModel::getOpticalInputPort(const String& name_) const
+    {
+        ASSERT(m_optical_input_ports_->keyExist(name_), "[Error] " + getInstanceName() +
+                " -> Input port (" + name_ + ") does not exist");
+
+        return m_optical_input_ports_->get(name_);
+    }
+    
+    //Get Outputs
+    const Map<PortInfo*>* OpticalModel::getOpticalOutputs() const
+    {
+        return m_optical_output_ports_;
+    }
+
+    PortInfo* OpticalModel::getOpticalOutputPort(const String& name_)
+    {
+        ASSERT(m_optical_output_ports_->keyExist(name_), "[Error] " + getInstanceName() +
+                " -> Input port (" + name_ + ") does not exist");
+
+        return m_optical_output_ports_->get(name_);
+    }
+
+    const PortInfo* OpticalModel::getOpticalOutputPort(const String& name_) const
+    {
+        ASSERT(m_optical_output_ports_->keyExist(name_), "[Error] " + getInstanceName() +
+                " -> Input port (" + name_ + ") does not exist");
+
+        return m_optical_output_ports_->get(name_);
+    }
+
+    //-------------------------------------------------------------------------
+    //  Optical Connectivity Creation Functions
+    //-------------------------------------------------------------------------
+    void OpticalModel::createOpticalInputPort(const String& name_, const WavelengthGroup& wavelength_group_)
+    {
+        // Create the new waveguides
+        // This should already check that it has not been previously declared
+        createWaveguide(name_, wavelength_group_);
+        // Add the waveguide name to list of input ports
+        m_optical_input_ports_->set(name_, new PortInfo(name_, wavelength_group_));
+        return;
+    }
+
+    void OpticalModel::createOpticalOutputPort(const String& name_, const WavelengthGroup& wavelength_group_)
+    {
+        // Create the new waveguides (including its waveguide reference)
+        // This should already check that it has not been previously declared
+        createWaveguide(name_, wavelength_group_);
+        // Add the waveguide name to list of output ports
+        m_optical_output_ports_->set(name_, new PortInfo(name_, wavelength_group_));
+        return;
+    }
+
+    // Waveguide creation
+    void OpticalModel::createWaveguide(const String& name_, const WavelengthGroup& wavelengths_)
+    {
+        // Check that the waveguide hasn't been previously declared
+        ASSERT( !m_waveguides_->keyExist(name_), "[Error] " + getInstanceName() +
+            " -> Redeclaration of waveguide " + name_);
+        m_waveguides_->set(name_, new OpticalWaveguide(name_, this, wavelengths_));
+        return;
+    }
+
+    // Laser creation
+    void OpticalModel::createLaser(const String& name_, const WavelengthGroup& wavelengths_)
+    {
+        // Check that the laser hasn't been previously declared
+        ASSERT( !m_lasers_->keyExist(name_), "[Error] " + getInstanceName() +
+            " -> Redeclaration of laser " + name_);
+        m_lasers_->set(name_, new OpticalLaser(name_, this, wavelengths_));
+        return;
+    }
+
+    // Modulator creation
+    void OpticalModel::createModulator(const String& name_, const WavelengthGroup& wavelengths_, bool opt_loss_, OpticalTransmitter* transmitter_)
+    {
+        // Check that the modulator hasn't been previously declared
+        ASSERT( !m_modulators_->keyExist(name_), "[Error] " + getInstanceName() +
+            " -> Redeclaration of modulator " + name_);
+        m_modulators_->set(name_, new OpticalModulator(name_, this, wavelengths_, opt_loss_, transmitter_));
+        return;
+    }
+
+    // Modulator Multiplier creation
+    void OpticalModel::createFilter(const String& name_, const WavelengthGroup& wavelengths_, bool drop_all_, const WavelengthGroup& drop_wavelengths_)
+    {
+        // Check that the filter hasn't been previously declared
+        ASSERT( !m_filters_->keyExist(name_), "[Error] " + getInstanceName() +
+            " -> Redeclaration of filter " + name_);
+        m_filters_->set(name_, new OpticalFilter(name_, this, wavelengths_, drop_all_, drop_wavelengths_));
+        return;
+    }
+
+    // Detector creation    
+    void OpticalModel::createDetector(const String& name_, const WavelengthGroup& wavelengths_, OpticalReceiver* receiver_)
+    {
+        // Check that the detector hasn't been previously declared
+        ASSERT( !m_detectors_->keyExist(name_), "[Error] " + getInstanceName() +
+            " -> Redeclaration of detector " + name_);
+        m_detectors_->set(name_, new OpticalDetector(name_, this, wavelengths_, receiver_));
+        return;
+    }
+    
+    //-------------------------------------------------------------------------    
+
+    // Assign a waveguide to be downstream from another waveguide
+    // assign downtream_waveguide_name_ = upstream_waveguide_name_
+    void OpticalModel::opticalAssign(const String& downstream_waveguide_name_, const String& upstream_waveguide_name_)
+    {
+        ASSERT(getWaveguides()->keyExist(downstream_waveguide_name_), "[Error] " + getInstanceName() + " -> Waveguide '" +
+            downstream_waveguide_name_ + "' does not exist!");
+
+        ASSERT(getWaveguides()->keyExist(upstream_waveguide_name_), "[Error] " + getInstanceName() + " -> Waveguide '" +
+            upstream_waveguide_name_ + "' does not exist!");
+        
+        // Get the two waveguides
+        OpticalWaveguide* upstream_waveguide = getWaveguide(upstream_waveguide_name_);
+        OpticalWaveguide* downstream_waveguide = getWaveguide(downstream_waveguide_name_);        
+        
+        // Check that the two waveguides expect the same wavelengths
+        ASSERT((upstream_waveguide->getWavelengths().first == downstream_waveguide->getWavelengths().first) &&
+            (upstream_waveguide->getWavelengths().second == downstream_waveguide->getWavelengths().second),
+            "[Error] " + getInstanceName() + " -> Assignment expects different wavelengths for waveguide '" +
+                upstream_waveguide_name_ + "' and waveguide '" + downstream_waveguide_name_ + "'!");
+
+        // Connect the downstream waveguide and the upstream waveguide
+        upstream_waveguide->addDownstreamNode(downstream_waveguide);
+        return;
+    }
+} // namespace DSENT
diff --git a/ext/dsent/model/OpticalModel.h b/ext/dsent/model/OpticalModel.h
new file mode 100644 (file)
index 0000000..0b4f27d
--- /dev/null
@@ -0,0 +1,143 @@
+#ifndef __DSENT_MODEL_OPTICALMODEL_H__
+#define __DSENT_MODEL_OPTICALMODEL_H__
+
+#include "util/CommonType.h"
+#include "model/ElectricalModel.h"
+
+namespace DSENT
+{
+    class PortInfo;
+    class EventInfo;
+    class OpticalWaveguide;
+    class OpticalLaser;
+    class OpticalFilter;
+    class OpticalModulator;
+    class OpticalDetector;
+    class OpticalReceiver;
+    class OpticalTransmitter;
+    
+    // A Wavelength group consisting of start and end wavelength indices
+    // Assuming it is the same as a net index so I can use the PortInfo class
+    typedef NetIndex WavelengthGroup;
+
+    // Helper function for making waveguide groups
+    inline WavelengthGroup makeWavelengthGroup(int start_index_, int end_index_)
+    {
+        ASSERT(end_index_ >= start_index_, (String) "[Error] Invalid wavelength group range " +
+            "[" + (String) start_index_ + ":" + (String) end_index_ + "]");
+            
+        return WavelengthGroup(start_index_, end_index_);
+    }    
+    
+    // Helper function for making wavelength groups
+    inline WavelengthGroup makeWavelengthGroup(int index_)
+    {
+        return makeWavelengthGroup(index_, index_);
+    }
+
+    // OpticalModel specifies optical connectivity to other optical models as well
+    class OpticalModel : public ElectricalModel
+    {        
+        
+        public:
+            OpticalModel(const String& instance_name_, const TechModel* tech_model_);
+            virtual ~OpticalModel();
+
+        public:
+            //-----------------------------------------------------------------
+            // Connectivity specification
+            //-----------------------------------------------------------------
+
+        /*
+        
+            // Waveguide multiplier
+            void setWaveguideMultiplier(unsigned int waveguide_multiplier_);
+            unsigned int getWaveguideMultiplier();
+
+        */
+            // Input Ports
+            void createOpticalInputPort(const String& name_, const WavelengthGroup& wavelengths_);
+            const Map<PortInfo*>* getOpticalInputs() const;
+            PortInfo* getOpticalInputPort(const String& name_);
+            const PortInfo* getOpticalInputPort(const String& name_) const;
+
+            // Output Ports
+            void createOpticalOutputPort(const String& name_, const WavelengthGroup& wavelengths_);
+            const Map<PortInfo*>* getOpticalOutputs() const;
+            PortInfo* getOpticalOutputPort(const String& name_);
+            const PortInfo* getOpticalOutputPort(const String& name_) const;
+
+            // Optical Waveguides
+            void createWaveguide(const String& name_, const WavelengthGroup& wavelengths_);
+            const Map<OpticalWaveguide*>* getWaveguides() const;
+            OpticalWaveguide* getWaveguide(const String& name_);
+
+            // Assign a waveguide to be downstream from another waveguide
+            void opticalAssign(const String& downstream_waveguide_name_, const String& upstream_waveguide_name_);
+            
+            // Connect a port (input or output) to some waveguide
+            void opticalPortConnect(OpticalModel* connect_model_, const String& connect_port_name_, const String& connect_waveguide_name_);
+            //-----------------------------------------------------------------
+
+            //-----------------------------------------------------------------
+            // Optical Graph Model Components
+            //-----------------------------------------------------------------
+            // Optical Laser Sources
+
+            void createLaser(const String& name_, const WavelengthGroup& wavelengths_);
+            const Map<OpticalLaser*>* getLasers() const;
+            OpticalLaser* getLaser(const String& name_);
+            // Optical Laser Sources
+            void createFilter(const String& name_, const WavelengthGroup& wavelengths_, bool drop_all_, const WavelengthGroup& drop_wavelengths_);
+            const Map<OpticalFilter*>* getFilters() const;
+            OpticalFilter* getFilter(const String& name_);            
+            // Optical Modulators
+            void createModulator(const String& name_, const WavelengthGroup& wavelengths_, bool opt_loss_, OpticalTransmitter* transmitter_);
+            const Map<OpticalModulator*>* getModulators() const;
+            OpticalModulator* getModulator(const String& name_);
+            // Optical Detectors
+            void createDetector(const String& name_, const WavelengthGroup& wavelengths_, OpticalReceiver* receiver_);
+            const Map<OpticalDetector*>* getDetectors() const;
+            OpticalDetector* getDetector(const String& name_);
+
+            //-----------------------------------------------------------------
+           
+        protected:
+            // In an OpticalModel, the complete optical port-to-port connectivity
+            // of all sub-instances must be specified. Addition/Removal optical
+            // ports or port-related nets cannot happen after this step
+            //virtual void constructModel() = 0;
+            // In an OpticalModel, updateModel MUST finish all necessary
+            // calculations such that loss and wavelength power can be calculated
+            //virtual void updateModel() = 0;
+            // In an OpticalModel, evaluateModel should calculate all wavelength
+            // power, updating power and energy events as necessary
+            //virtual void evaluateModel() = 0;
+            
+        private:
+            // Private copy constructor. Use clone to perform copy operation.
+            OpticalModel(const OpticalModel& model_);
+                    
+        private:
+            // Map of all input ports
+            Map<PortInfo*>* m_optical_input_ports_;
+            // Map of all output ports
+            Map<PortInfo*>* m_optical_output_ports_;
+            
+            // Optical graph model elements
+            // Map of all waveguides
+            Map<OpticalWaveguide*>* m_waveguides_;
+            // Map of all laser source elements
+            Map<OpticalLaser*>* m_lasers_;
+            // Map of all filter elements
+            Map<OpticalFilter*>* m_filters_;
+            // Map of all modulator elements
+            Map<OpticalModulator*>* m_modulators_;
+            // Map of all photodetector elements
+            Map<OpticalDetector*>* m_detectors_;
+
+    }; // class OpticalModel
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_OPTICALMODEL_H__
+
diff --git a/ext/dsent/model/PortInfo.cc b/ext/dsent/model/PortInfo.cc
new file mode 100644 (file)
index 0000000..fd859fc
--- /dev/null
@@ -0,0 +1,35 @@
+#include "model/PortInfo.h"
+
+namespace DSENT
+{
+    PortInfo::PortInfo(const String& port_name_, const NetIndex& net_index_)
+        : m_port_name_(port_name_), m_net_index_(net_index_), m_tran_info_(TransitionInfo())
+    {
+    }
+
+    PortInfo::~PortInfo()
+    {
+    }
+
+    const String& PortInfo::getPortName() const
+    {
+        return m_port_name_;
+    }
+
+    const NetIndex& PortInfo::getNetIndex() const
+    {
+        return m_net_index_;
+    }
+
+    void PortInfo::setTransitionInfo(const TransitionInfo& trans_info_)
+    {
+        m_tran_info_ = trans_info_;
+        return;
+    }
+
+    const TransitionInfo& PortInfo::getTransitionInfo() const
+    {
+        return m_tran_info_;
+    }
+} // namespace DSENT
+
diff --git a/ext/dsent/model/PortInfo.h b/ext/dsent/model/PortInfo.h
new file mode 100644 (file)
index 0000000..68cd5dc
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef __DSENT_MODEL_PORT_INFO_H__
+#define __DSENT_MODEL_PORT_INFO_H__
+
+#include "util/CommonType.h"
+#include "model/ElectricalModel.h"
+#include "model/TransitionInfo.h"
+
+namespace DSENT
+{
+    class PortInfo
+    {
+        public:
+            PortInfo(const String& port_name_, const NetIndex& net_index_ = NetIndex(0, 0));
+            ~PortInfo();
+
+        public:
+            // Get the port name
+            const String& getPortName() const;
+            // Get the net index
+            const NetIndex& getNetIndex() const;
+            // Set the transition information of this port
+            void setTransitionInfo(const TransitionInfo& trans_info_);
+            // Get the transition information of this port
+            const TransitionInfo& getTransitionInfo() const;
+
+        private:
+            // Name of this port
+            String m_port_name_;
+            // Net index of the input port
+            NetIndex m_net_index_;
+            // Store the transition information of this port
+            TransitionInfo m_tran_info_;
+    }; // class PortInfo
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_PORT_INFO_H__
+
diff --git a/ext/dsent/model/TransitionInfo.cc b/ext/dsent/model/TransitionInfo.cc
new file mode 100644 (file)
index 0000000..ac44020
--- /dev/null
@@ -0,0 +1,70 @@
+#include "model/TransitionInfo.h"
+
+namespace DSENT
+{
+    TransitionInfo::TransitionInfo()
+        : m_number_transitions_00_(0.25), m_number_transitions_01_(0.25), 
+        m_number_transitions_11_(0.25), m_frequency_multiplier_(1.0)
+    {
+        update();
+    }
+
+    TransitionInfo::TransitionInfo(double number_transitions_00_, double number_transitions_01_,
+            double number_transitions_11_)
+        : m_number_transitions_00_(number_transitions_00_), m_number_transitions_01_(number_transitions_01_),
+        m_number_transitions_11_(number_transitions_11_)
+    {
+        m_frequency_multiplier_ = m_number_transitions_00_ + 2.0 * m_number_transitions_01_ + m_number_transitions_11_;
+        update();
+    }
+
+    TransitionInfo::~TransitionInfo()
+    {}
+
+    void TransitionInfo::update()
+    {
+        ASSERT(m_number_transitions_00_ >= 0.0, "[Error] Number of 0->0 transitions (" + 
+                (String)m_number_transitions_00_ + ") must be >= 0.0!");
+        ASSERT(m_number_transitions_01_ >= 0.0, "[Error] Number of 0->1 transitions (" + 
+                (String)m_number_transitions_01_ + ") must be >= 0.0!");
+        ASSERT(m_number_transitions_11_ >= 0.0, "[Error] Number of 1->1 transitions (" + (String)m_number_transitions_11_ + ") must be >= 0.0!");
+
+        m_probability_1_ = (m_number_transitions_01_ + m_number_transitions_11_) / m_frequency_multiplier_;
+        m_probability_0_ = 1.0 - m_probability_1_;
+        return;
+    }
+
+    TransitionInfo TransitionInfo::scaleFrequencyMultiplier(double frequency_multiplier_) const
+    {
+        // A short cut if frequency_multiplier_ == m_frequency_multiplier_ to avoid excess calculations
+        if(frequency_multiplier_ == m_frequency_multiplier_)
+        {
+            return TransitionInfo(m_number_transitions_00_, m_number_transitions_01_, m_number_transitions_11_);
+        }
+        else if (frequency_multiplier_ > m_frequency_multiplier_)
+        {
+            double freq_ratio = frequency_multiplier_ / m_frequency_multiplier_;
+            double diff_num_trans_01 = m_number_transitions_01_ * (freq_ratio - 1.0);
+            double norm_num_trans_00 = m_number_transitions_00_ * freq_ratio + diff_num_trans_01;
+            double norm_num_trans_01 = m_number_transitions_01_;
+            double norm_num_trans_11 = m_number_transitions_11_ * freq_ratio + diff_num_trans_01;
+
+            return TransitionInfo(norm_num_trans_00, norm_num_trans_01, norm_num_trans_11);
+        }
+        else
+        {
+            ASSERT(false, "[Error] Cannot scale to frequency multiplier (" + (String) frequency_multiplier_ +
+                ") since current frequency multiplier (" + (String) m_frequency_multiplier_ + ") is bigger!");
+        }
+    }
+
+    void TransitionInfo::print(std::ostream& ost_) const
+    {
+        ost_ << "[" << m_number_transitions_00_ << ", " << m_number_transitions_01_ << ", " << m_number_transitions_11_ << "]";
+        ost_ << " [" << m_number_transitions_00_ / m_frequency_multiplier_;
+        ost_ << ", " << m_number_transitions_01_*2.0 / m_frequency_multiplier_;
+        ost_ << ", " << m_number_transitions_11_ / m_frequency_multiplier_ << "]" << endl;
+        return;
+    }
+} // namespace DSENT
+
diff --git a/ext/dsent/model/TransitionInfo.h b/ext/dsent/model/TransitionInfo.h
new file mode 100644 (file)
index 0000000..6f00cb8
--- /dev/null
@@ -0,0 +1,50 @@
+#ifndef __DSENT_MODEL_TRANSITION_INFO_H__
+#define __DSENT_MODEL_TRANSITION_INFO_H__
+
+#include "util/CommonType.h"
+
+namespace DSENT
+{
+    /**
+     * \brief This class contains the number of transitions and the frequency multiplier information
+     */
+    class TransitionInfo
+    {
+        public:
+            TransitionInfo();
+            TransitionInfo(double number_transitions_00_, double number_transitions_01_, double number_transitions_11_);
+            ~TransitionInfo();
+
+        public:
+            inline double getNumberTransitions00() const { return m_number_transitions_00_; }
+            inline double getNumberTransitions01() const { return m_number_transitions_01_; }
+            inline double getNumberTransitions11() const { return m_number_transitions_11_; }
+            inline double getFrequencyMultiplier() const { return m_frequency_multiplier_; }
+            inline double getProbability0() const { return m_probability_1_; }
+            inline double getProbability1() const { return m_probability_1_; }
+
+            inline void setNumberTransitions00(double value_) { m_number_transitions_00_ = value_; }
+            inline void setNumberTransitions01(double value_) { m_number_transitions_01_ = value_; }
+            inline void setNumberTransitions11(double value_) { m_number_transitions_11_ = value_; }
+            inline void setFrequencyMultiplier(double value_) { m_frequency_multiplier_ = value_; }
+
+            void update();
+            TransitionInfo scaleFrequencyMultiplier(double frequency_multiplier_) const;
+
+            void print(std::ostream& ost_) const;
+
+        private:
+            // m_number_transitions_xy_ defines number of transitions from x to y
+            double m_number_transitions_00_;
+            double m_number_transitions_01_;
+            double m_number_transitions_11_;
+            // The multiplier that defines the ratio of the transition frequency and the main core clock frequency
+            double m_frequency_multiplier_;
+            // Probability of being at state 0/1
+            double m_probability_0_;
+            double m_probability_1_;
+    }; // class TransitionInfo
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_TRANSITION_INFO_H__
+
diff --git a/ext/dsent/model/electrical/BarrelShifter.cc b/ext/dsent/model/electrical/BarrelShifter.cc
new file mode 100644 (file)
index 0000000..b951fc5
--- /dev/null
@@ -0,0 +1,241 @@
+#include "model/electrical/BarrelShifter.h"
+#include "model/electrical/Multiplexer.h"
+
+#include <cmath>
+
+#include "model/PortInfo.h"
+#include "model/TransitionInfo.h"
+#include "model/EventInfo.h"
+#include "model/timing_graph/ElectricalDriverMultiplier.h"
+#include "model/timing_graph/ElectricalNet.h"
+#include "model/std_cells/StdCell.h"
+#include "model/std_cells/StdCellLib.h"
+
+namespace DSENT
+{
+    BarrelShifter::BarrelShifter(const String& instance_name_, const TechModel* tech_model_)
+        : ElectricalModel(instance_name_, tech_model_)
+    {
+        initParameters();
+        initProperties();
+    }
+
+    BarrelShifter::~BarrelShifter()
+    {}
+
+    void BarrelShifter::initParameters()
+    {
+        addParameterName("NumberBits");
+        addParameterName("ShiftIndexMin");
+        addParameterName("ShiftIndexMax");
+        addParameterName("BitDuplicate", "TRUE");
+        return;
+    }
+
+    void BarrelShifter::initProperties()
+    {
+        return;
+    }
+
+    BarrelShifter* BarrelShifter::clone() const
+    {
+        return NULL;
+    }
+
+    void BarrelShifter::constructModel()
+    {
+        // Get parameters
+        unsigned int number_bits = getParameter("NumberBits");
+        unsigned int number_shift_bits = (unsigned int)ceil(log2((double) number_bits));
+        unsigned int shift_index_min = getParameter("ShiftIndexMin");
+        unsigned int shift_index_max = getParameter("ShiftIndexMax");
+        bool bit_duplicate = (bool) getParameter("BitDuplicate");
+        
+        ASSERT(number_bits > 0, "[Error] " + getInstanceName() + " -> Number of bits must be > 0!");
+        // No need to check these if there arent any shifts
+        if (number_shift_bits > 0)
+        {
+            ASSERT(shift_index_min <= number_shift_bits,
+                "[Error] " + getInstanceName() + " -> Min shift index must be >= 0 and <= " +
+                "the total number of shift bits!");
+            ASSERT(shift_index_max >= shift_index_min && shift_index_max <= number_shift_bits,
+                "[Error] " + getInstanceName() + " -> Max shift index must be >= minimum shift index and <= " +
+                "the total number of shift bits!");
+        }
+    
+        //Construct electrical ports
+        //Create each input port
+        createInputPort(    "In", makeNetIndex(0, number_bits-1));
+        //Create output
+        createOutputPort(   "Out", makeNetIndex(0, number_bits-1));
+        
+        //Create shift ports (which only exists if there is something to shift)
+        if (shift_index_min != number_shift_bits)
+            for (unsigned int i = shift_index_min; i <= shift_index_max; ++i)
+                createInputPort(    "Shift" + (String) i);
+
+        //Create energy, power, and area results
+        createElectricalResults();
+        createElectricalEventResult("BarrelShift");
+        //Set conditions during idle event
+        getEventInfo("Idle")->setStaticTransitionInfos();
+
+        //If the input is only 1-bit, connect input to output and be done
+        if (number_shift_bits == 0 || (shift_index_min == number_shift_bits))
+            assign("Out", "In");
+        else
+        {
+            for (unsigned int i = shift_index_min; i <= shift_index_max; ++i)
+            {
+                //Create internally buffered shift select signals
+                createNet("Shift_b" + (String) i);
+                createNet("Shift_i" + (String) i);
+            }                                
+        
+            // Create shift and shifted signals
+            for (unsigned int i = shift_index_min; i <= shift_index_max; ++i)
+            {
+                unsigned int current_shifts = (unsigned int)pow(2, i);
+                const String& n = (String) current_shifts;
+                //Instantiate and connect intermediate nets. In a barrel-shifter, the nets do
+                //all the "shifting" and the muxes just select which to take
+                createNet("R_" + n, makeNetIndex(0, number_bits-1));               //wire R_n[number_bits-1:0]
+                createNet("RS_" + n, makeNetIndex(0, number_bits-1));              //wire RS_n[number_bits-1:0]
+
+                //Implements the shifts
+                //assign RS_n[number_bits-1:number_bits-current_shifts] = R_n[current_shifts-1:0];
+                assign("RS_" + n, makeNetIndex(number_bits-current_shifts, number_bits-1),
+                        "R_" + n, makeNetIndex(0, current_shifts-1));
+                //assign RS_n[number_bits-current_shifts-1:0] = R_n[current_shifts:number_bits-1];
+                assign("RS_" + n, makeNetIndex(0, number_bits-current_shifts-1),
+                        "R_" + n, makeNetIndex(current_shifts, number_bits-1));                
+            }
+            
+            const String& n_max = (String) pow(2, shift_index_max+1);            
+            const String& n_min = (String) pow(2, shift_index_min);
+            // Create the R_(max) net
+            createNet("R_" + n_max, makeNetIndex(0, number_bits-1));            
+            // Set R_1 to be the input
+            assign("R_" + n_min, "In");
+            // Set R_(max) to be the output
+            assign("Out", "R_" + n_max, makeNetIndex(0, number_bits-1));
+
+            for (unsigned int i = shift_index_min; i <= shift_index_max; ++i)
+            {
+                unsigned int current_shifts = (unsigned int)pow(2, i);
+                const String& n = (String) current_shifts;
+                const String& n_next = (String) (current_shifts * 2);
+                
+                const String& buf_inv_0_name = "ShiftBufInv0_" + (String) n;
+                const String& buf_inv_1_name = "ShiftBufInv1_" + (String) n;
+                // Create shift buffer inverters
+                StdCell* buf_inv_0 = getTechModel()->getStdCellLib()->createStdCell("INV", buf_inv_0_name);
+                buf_inv_0->construct();
+                StdCell* buf_inv_1 = getTechModel()->getStdCellLib()->createStdCell("INV", buf_inv_1_name);
+                buf_inv_1->construct();
+                
+                // Connect up shift buffer inverters
+                portConnect(buf_inv_0, "A", "Shift" + (String) i);
+                portConnect(buf_inv_0, "Y", "Shift_b" + (String) i);
+                portConnect(buf_inv_1, "A", "Shift_b" + (String) i);
+                portConnect(buf_inv_1, "Y", "Shift_i" + (String) i);
+                
+                // Add area, power, and event results for inverters
+                addSubInstances(buf_inv_0, 1.0);
+                addSubInstances(buf_inv_1, 1.0);
+                addElectricalSubResults(buf_inv_0, 1.0);
+                addElectricalSubResults(buf_inv_1, 1.0);
+                getEventResult("BarrelShift")->addSubResult(buf_inv_0->getEventResult("INV"), buf_inv_0_name, 1.0);                
+                getEventResult("BarrelShift")->addSubResult(buf_inv_1->getEventResult("INV"), buf_inv_1_name, 1.0);                
+                
+                //Instantiate 2:1 multiplexers, one for each shift bit.
+                const String& mux_name = "SRL" + n;
+                Multiplexer* mux = new Multiplexer(mux_name, getTechModel());
+                mux->setParameter("NumberInputs", 2);
+                mux->setParameter("NumberBits", number_bits);
+                mux->setParameter("BitDuplicate", bit_duplicate);
+                mux->construct();
+                
+                //Just have to connect the In0 and In1 inputs of the mux to the
+                //non-shifted and shifted intermediate signals, respectively.                
+                portConnect(mux, "In0", "R_" + n);
+                portConnect(mux, "In1", "RS_" + n);
+                //Selector connects to the shift signal for that index
+                portConnect(mux, "Sel0", "Shift_i" + (String) i);
+                //Connect mux output
+                portConnect(mux, "Out", "R_" + n_next);
+                
+                //Add area, power, and event results for each mux
+                addSubInstances(mux, 1.0);
+                addElectricalSubResults(mux, 1.0);
+                getEventResult("BarrelShift")->addSubResult(mux->getEventResult("Mux"), mux_name, 1.0);                
+            }
+        }
+        return;
+    }
+    
+    void BarrelShifter::propagateTransitionInfo()
+    {
+        // The only thing can be updated are the input probabilities...so we will update them
+        unsigned int number_bits = (unsigned int) getParameter("NumberBits");
+        unsigned int number_shift_bits = (unsigned int) ceil(log2((double) number_bits));
+        unsigned int shift_index_min = getParameter("ShiftIndexMin");
+        unsigned int shift_index_max = getParameter("ShiftIndexMax");        
+        
+        // Keep track of the multiplexer of the last stage
+        ElectricalModel* last_mux = NULL;        
+        // We only need to update stuff if we are not shifting by exact multiples
+        // of number of input bits
+        if (shift_index_min < number_shift_bits)
+        {
+            for (unsigned int i = shift_index_min; i <= shift_index_max; ++i)
+            {        
+                unsigned int current_shifts = (unsigned int)pow(2, i);
+                String n = (String) current_shifts;
+
+                // Set the 
+                const String& buf_inv_0_name = "ShiftBufInv0_" + (String) n;
+                const String& buf_inv_1_name = "ShiftBufInv1_" + (String) n;
+                const String& mux_name = "SRL" + n;
+
+                // Set the transition infos for the inverter buffers
+                ElectricalModel* buf_inv_0 = (ElectricalModel*) getSubInstance(buf_inv_0_name);
+                propagatePortTransitionInfo(buf_inv_0, "A", "Shift" + (String) i);
+                buf_inv_0->use();
+
+                ElectricalModel* buf_inv_1 = (ElectricalModel*) getSubInstance(buf_inv_1_name);
+                propagatePortTransitionInfo(buf_inv_1, "A", buf_inv_0, "Y");
+                buf_inv_1->use();
+                
+                // Set the transition infos for the shift multiplexers
+                ElectricalModel* mux = (ElectricalModel*) getSubInstance(mux_name);
+                propagatePortTransitionInfo(mux, "Sel0", buf_inv_1, "Y");
+                if (last_mux == NULL)
+                {
+                    propagatePortTransitionInfo(mux, "In0", "In");
+                    propagatePortTransitionInfo(mux, "In1", "In");
+                }
+                else
+                {
+                    propagatePortTransitionInfo(mux, "In0", last_mux, "Out");
+                    propagatePortTransitionInfo(mux, "In1", last_mux, "Out");                    
+                }
+                mux->use();                
+                
+                // Set this to be the last mux visted
+                last_mux = mux;
+            }                        
+        }
+        
+        // If there isn't anything to shift
+        if (last_mux == NULL)
+            propagatePortTransitionInfo("Out", "In");
+        // Take the transition info of the last mux
+        else
+            propagatePortTransitionInfo("Out", last_mux, "Out");
+            
+        return;
+    }
+    
+} // namespace DSENT
+
diff --git a/ext/dsent/model/electrical/BarrelShifter.h b/ext/dsent/model/electrical/BarrelShifter.h
new file mode 100644 (file)
index 0000000..e26ca9e
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef __DSENT_MODEL_ELECTRICAL_BARRELSHIFTER_H__
+#define __DSENT_MODEL_ELECTRICAL_BARRELSHIFTER_H__
+
+#include "util/CommonType.h"
+#include "model/ElectricalModel.h"
+
+namespace DSENT
+{
+    // A model on N-bit barrel-shifter. Shifts to the right by X
+    class BarrelShifter : public ElectricalModel
+    {
+        public:
+            BarrelShifter(const String& instance_name_, const TechModel* tech_model_);
+            virtual ~BarrelShifter();
+
+        public:
+            // Set a list of properties' name needed to construct model
+            void initParameters();
+            // Set a list of properties' name needed to construct model
+            void initProperties();
+
+            // Clone and return a new instance
+            virtual BarrelShifter* clone() const;
+
+        protected:
+            // Build the model
+            virtual void constructModel();
+            virtual void propagateTransitionInfo();
+
+    }; // class BarrelShifter
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_ELECTRICAL_MULTIPLEXER_H__
+
diff --git a/ext/dsent/model/electrical/BroadcastHTree.cc b/ext/dsent/model/electrical/BroadcastHTree.cc
new file mode 100644 (file)
index 0000000..efac128
--- /dev/null
@@ -0,0 +1,400 @@
+#include "model/electrical/BroadcastHTree.h"
+
+#include <cmath>
+#include <vector>
+
+#include "model/PortInfo.h"
+#include "model/EventInfo.h"
+#include "model/TransitionInfo.h"
+#include "model/std_cells/StdCellLib.h"
+#include "model/std_cells/StdCell.h"
+#include "model/timing_graph/ElectricalLoad.h"
+#include "model/timing_graph/ElectricalDelay.h"
+#include "model/timing_graph/ElectricalDriver.h"
+#include "model/timing_graph/ElectricalTimingTree.h"
+#include "model/timing_graph/ElectricalNet.h"
+
+namespace DSENT
+{
+    using std::pow;
+    using std::vector;
+
+    BroadcastHTree::BroadcastHTree(const String& instance_name_, const TechModel* tech_model_)
+        : ElectricalModel(instance_name_, tech_model_)
+    {
+        initParameters();
+        initProperties();
+
+        m_leaf_load_ = NULL;
+        m_leaf_head_driver_ = NULL;
+        m_leaf_head_load_ = NULL;
+    }
+
+    BroadcastHTree::~BroadcastHTree()
+    {
+        clearPtrVector<StdCell>(&m_repeaters_);
+        clearPtrVector<ElectricalLoad>(&m_repeater_loads_);
+        clearPtrVector<ElectricalTimingTree>(&m_timing_trees_);
+        clearPtrVector<StdCell>(&m_leaf_drivers_);
+        delete m_leaf_load_;
+        delete m_leaf_head_driver_;
+        delete m_leaf_head_load_;
+    }
+
+    void BroadcastHTree::initParameters()
+    {
+        addParameterName("NumberLevels");
+        addParameterName("NumberBits");
+        addParameterName("WireLayer");
+        addParameterName("WireWidthMultiplier", 1.0);
+        addParameterName("WireSpacingMultiplier", 1.0);
+        return;
+    }
+
+    void BroadcastHTree::initProperties()
+    {
+        addPropertyName("SitePitch");
+        addPropertyName("TotalLoadCapPerBit");
+        return;
+    }
+
+    BroadcastHTree* BroadcastHTree::clone() const
+    {
+        // TODO
+        return NULL;
+    }
+
+    void BroadcastHTree::constructModel()
+    {
+        // Get parameters
+        unsigned int number_levels = getParameter("NumberLevels").toUInt();
+        unsigned int number_bits = getParameter("NumberBits").toUInt();
+        const String& wire_layer = getParameter("WireLayer");
+        double wire_width_multiplier = getParameter("WireWidthMultiplier").toDouble();
+        double wire_spacing_multiplier = getParameter("WireSpacingMultiplier").toDouble();
+
+        ASSERT(number_levels > 0, "[Error] " + getInstanceName() +
+                " -> Number of levels must be > 0!");
+        ASSERT(number_bits > 0, "[Error] " + getInstanceName() +
+                " -> Number of bits must be > 0!");
+        ASSERT(getTechModel()->isWireLayerExist(wire_layer), "[Error] " + getInstanceName() + 
+                " -> Wire layer does not exist!");
+        ASSERT(wire_width_multiplier >= 1.0, "[Error] " + getInstanceName() + 
+                " -> Wire width multiplier must be >= 1.0!");
+        ASSERT(wire_spacing_multiplier >= 1.0, "[Error] " + getInstanceName() + 
+                " -> Wire spacing multiplier must be >= 1.0!");
+
+        double wire_min_width = getTechModel()->get("Wire->" + wire_layer + "->MinWidth").toDouble();
+        double wire_min_spacing = getTechModel()->get("Wire->" + wire_layer + "->MinSpacing").toDouble();
+
+        double wire_width = wire_min_width * wire_width_multiplier;
+        double wire_spacing = wire_min_spacing * wire_spacing_multiplier;
+
+        double wire_cap_per_len = getTechModel()->calculateWireCapacitance(wire_layer, wire_width, wire_spacing, 1.0);
+        double wire_res_per_len = getTechModel()->calculateWireResistance(wire_layer, wire_width, 1.0);
+
+        getGenProperties()->set("WireWidth", wire_width);
+        getGenProperties()->set("WireSpacing", wire_spacing);
+        getGenProperties()->set("WireCapacitancePerLength", wire_cap_per_len);
+        getGenProperties()->set("WireResistancePerLength", wire_res_per_len);
+
+        // Create ports
+        createInputPort("In", makeNetIndex(0, number_bits-1));
+        createOutputPort("Out", makeNetIndex(0, number_bits-1));
+
+        // Create connections
+        createNet("InTmp");
+        createNet("OutTmp");
+        assignVirtualFanin("InTmp", "In");
+        assignVirtualFanout("Out", "OutTmp");
+
+        createLoad("In_Cap");
+        createDelay("In_to_Out_delay");
+
+        ElectricalLoad* in_cap = getLoad("In_Cap");
+        ElectricalDelay* in_to_out_delay = getDelay("In_to_Out_delay");
+
+        getNet("InTmp")->addDownstreamNode(in_cap);
+        in_cap->addDownstreamNode(in_to_out_delay);
+
+        // Init 
+        for(unsigned int i = 0; i < number_levels; ++i)
+        {
+            StdCell* repeater = getTechModel()->getStdCellLib()->createStdCell("INV", "Repeater" + (String)i);
+            ElectricalLoad* repeater_load = new ElectricalLoad("RepeaterIn_Cap" + (String)i, this);
+            ElectricalTimingTree* timing_tree = new ElectricalTimingTree("RepeatedLink" + (String)i, this);
+
+            repeater->construct();
+            repeater->getNet("Y")->addDownstreamNode(repeater_load);
+            m_repeaters_.push_back(repeater);
+            m_repeater_loads_.push_back(repeater_load);
+            m_timing_trees_.push_back(timing_tree);
+        }
+
+        // Create area, power, and event results
+        createElectricalAtomicResults();
+        createElectricalEventResult("Send");
+        addEventResult(new AtomicResult("DriveLoad"));
+        addEventResult(new AtomicResult("DriveTree"));
+
+        getEventResult("Send")->addSubResult(getEventResult("DriveLoad"), "Self", 1.0);
+        getEventResult("Send")->addSubResult(getEventResult("DriveTree"), "Self", 1.0);
+        return;
+    }
+
+    void BroadcastHTree::updateModel()
+    {
+        // Get properties
+        double site_pitch = getProperty("SitePitch").toDouble();
+        double total_load_cap_per_bit = getProperty("TotalLoadCapPerBit").toDouble();
+
+        ASSERT(site_pitch > 0, "[Error] " + getInstanceName() + 
+                " -> Site pitch must be > 0!");
+        ASSERT(total_load_cap_per_bit >= 0.0, "[Error] " + getInstanceName() + 
+                " -> Total load capacitance per bit must be >= 0!");
+
+        // Get parameters
+        unsigned int number_levels = getParameter("NumberLevels");
+        unsigned int number_bits = getParameter("NumberBits");
+
+        const String& wire_layer = getParameter("WireLayer");
+        double wire_width = getGenProperties()->get("WireWidth").toDouble();
+        double wire_spacing = getGenProperties()->get("WireSpacing").toDouble();
+        double wire_cap_per_len = getGenProperties()->get("WireCapacitancePerLength").toDouble();
+        double wire_res_per_len = getGenProperties()->get("WireResistancePerLength").toDouble();
+
+        double leaf_load_cap = total_load_cap_per_bit / pow(2.0, (double)(number_levels-1));
+
+        vector<double> wire_caps(number_levels, 0.0);
+        vector<double> wire_ress(number_levels, 0.0);
+        double wire_length = site_pitch / 2.0;
+        for(unsigned int i = 0; i < number_levels; ++i)
+        {
+            wire_caps[i] = wire_cap_per_len * wire_length;
+            wire_ress[i] = wire_res_per_len * wire_length;
+            wire_length /= 2.0;
+        }
+
+        // Start sizing each stage of repeaters for a transition times. TODO: Find a heuristic about
+        // how the transition time is done...place and route tools make this user-specified
+        double required_transition = 40e-12;
+        m_number_segments_.resize(number_levels, 1);
+        for(unsigned int i = 0; i < number_levels; ++i)
+        {
+            Log::printLine(getInstanceName() + " -> Beginning Repeater Insertion " + (String)i);
+
+            double transition;
+            unsigned int iteration = 0;
+            m_repeaters_[i]->setMinDrivingStrength();
+            m_repeaters_[i]->getNet("Y")->setDistributedCap(wire_caps[i] / m_number_segments_[i]);
+            m_repeaters_[i]->getNet("Y")->setDistributedRes(wire_ress[i] / m_number_segments_[i]);
+            m_repeater_loads_[i]->setLoadCap(m_repeaters_[i]->getNet("A")->getTotalDownstreamCap());
+            
+            transition = m_timing_trees_[i]->calculateNodeTransition(m_repeaters_[i]->getNet("Y"));
+
+            while(required_transition < transition)
+            {
+                Log::printLine(getInstanceName() + " -> Repeater Insertion Iteration " + (String)iteration + 
+                        ": Required transition = " + (String)required_transition + 
+                        ", Transition = " + (String)transition + 
+                        ", Slack = " + (String)(required_transition - transition) + 
+                        ", Number of repeaters = " + (String)m_number_segments_[i]);
+
+                // Size up if transition is not met
+                while(required_transition < transition)
+                {
+                    if(m_repeaters_[i]->hasMaxDrivingStrength())
+                    {
+                        break;
+                    }
+                    m_repeaters_[i]->increaseDrivingStrength();
+                    m_repeater_loads_[i]->setLoadCap(m_repeaters_[i]->getNet("A")->getTotalDownstreamCap());
+                    transition = m_timing_trees_[i]->calculateNodeTransition(m_repeaters_[i]->getNet("Y"));
+
+                    iteration++;
+                    Log::printLine(getInstanceName() + " -> Slack: " + (String)(required_transition - transition));
+                }
+                // Increase number of segments if thansition is not met
+                if(required_transition < transition)
+                {
+                    m_number_segments_[i]++;
+                    m_repeaters_[i]->setMinDrivingStrength();
+                    m_repeaters_[i]->getNet("Y")->setDistributedCap(wire_caps[i] / m_number_segments_[i]);
+                    m_repeaters_[i]->getNet("Y")->setDistributedRes(wire_ress[i] / m_number_segments_[i]);
+                    m_repeater_loads_[i]->setLoadCap(m_repeaters_[i]->getNet("A")->getTotalDownstreamCap());
+                    transition = m_timing_trees_[i]->calculateNodeTransition(m_repeaters_[i]->getNet("Y"));
+                }
+            }
+            Log::printLine(getInstanceName() + " -> Repeater Insertion " + (String)i + " Ended after Iteration: " + (String)iteration + 
+                    ": Required transition = " + (String)required_transition + 
+                    ", Transition = " + (String)transition + 
+                    ", Slack = " + (String)(required_transition - transition) + 
+                    ", Number of repeaters = " + (String)m_number_segments_[i]);
+        }
+
+        // Insert inverters to ensure the transition time at the leaf
+        int min_driving_strength_idx = m_repeaters_[number_levels-1]->getDrivingStrengthIdx();
+
+        // Remove everything and rebuild again
+        clearPtrVector<StdCell>(&m_leaf_drivers_);
+        delete m_leaf_load_;
+        delete m_leaf_head_driver_;
+        delete m_leaf_head_load_;
+
+        m_leaf_head_driver_ = getTechModel()->getStdCellLib()->createStdCell("INV", "LeafHeadDriver");
+        m_leaf_head_driver_->construct();
+        m_leaf_head_driver_->setDrivingStrengthIdx(min_driving_strength_idx);
+
+        m_leaf_head_load_ = new ElectricalLoad("LeafHead_Cap", this);
+        m_leaf_head_driver_->getNet("Y")->addDownstreamNode(m_leaf_head_load_);
+
+        m_leaf_load_ = new ElectricalLoad("Leaf_Cap", this);
+        m_leaf_load_->setLoadCap(leaf_load_cap);
+
+        StdCell* inv = getTechModel()->getStdCellLib()->createStdCell("INV", "LeafDriver0");
+        inv->construct();
+        inv->getNet("Y")->addDownstreamNode(m_leaf_load_);
+        inv->setDrivingStrengthIdx(min_driving_strength_idx);
+        m_leaf_drivers_.push_back(inv);
+
+        m_leaf_head_load_->setLoadCap(m_leaf_drivers_[0]->getNet("A")->getTotalDownstreamCap());
+
+        // Start inserting the buffers
+        ElectricalTimingTree t2("LeafHead", m_leaf_head_driver_);
+        int curr_driver = 0;
+        unsigned int iteration = 0;
+        while(true)
+        {
+            ElectricalTimingTree t("LeafDriver", m_leaf_drivers_[curr_driver]);
+            double transition = t.calculateNodeTransition(m_leaf_drivers_[curr_driver]->getNet("Y"));
+            Log::printLine(getInstanceName() + " -> Buffer Insertion : " + (String)iteration + 
+                    ": Required transition = " + (String)required_transition + 
+                    ", Transition = " + (String)transition + 
+                    ", Slack = " + (String)(required_transition - transition) + 
+                    ", Number of buffers = " + (String)(curr_driver+1));
+
+            // Size up the inverter at curr_driver so that it could drive the next stage
+            while(required_transition < transition)
+            {
+                if(m_leaf_drivers_[curr_driver]->hasMaxDrivingStrength())
+                {
+                    const String& warning_msg = "[Warning] " + getInstanceName() + " -> Transition not met" + 
+                        ": Required transition = " + (String)required_transition + 
+                        ", Transition = " + (String)transition + 
+                        ", Slack = " + (String)(required_transition - transition);
+                    Log::printLine(std::cerr, warning_msg);
+                    break;
+                }
+                m_leaf_drivers_[curr_driver]->increaseDrivingStrength();
+                transition = t.calculateNodeTransition(m_leaf_drivers_[curr_driver]->getNet("Y"));
+                iteration++;
+            }
+            // Add an additional inverter if the transition for the first stage does not meet the required transition
+            m_leaf_head_load_->setLoadCap(m_leaf_drivers_[curr_driver]->getNet("A")->getTotalDownstreamCap());
+            transition = t2.calculateNodeTransition(m_leaf_head_driver_->getNet("Y"));
+            if(required_transition < transition)
+            {
+                inv = getTechModel()->getStdCellLib()->createStdCell("INV", "LeafDriver" + (String)(curr_driver+1));
+                inv->construct();
+                inv->getNet("Y")->addDownstreamNode(m_leaf_drivers_[curr_driver]->getNet("A"));
+                inv->setDrivingStrengthIdx(min_driving_strength_idx);
+                m_leaf_drivers_.push_back(inv);
+                curr_driver++;
+            }
+            else
+            {
+                Log::printLine(getInstanceName() + " -> Buffer Insertion Ended after Iteration: " + (String)iteration + 
+                        ", Number of buffers = " + (String)(curr_driver+1));
+                break;
+            }
+        }
+
+
+        // Update electrical interfaces
+        getLoad("In_Cap")->setLoadCap(m_repeaters_[0]->getNet("A")->getTotalDownstreamCap());
+        // TODO
+        getDelay("In_to_Out_delay")->setDelay(0.0);
+
+        // Reset all the atomic results to 0 before start updating new results
+        resetElectricalAtomicResults();
+
+        // Update area, power results
+        double wire_area = 0.0;
+        wire_length = site_pitch / 2.0;
+        unsigned int number_branches = 1;
+        for(unsigned int i = 0; i < number_levels; ++i)
+        {
+            wire_area += wire_length * (wire_width + wire_spacing) * number_branches * number_bits;
+            addElecticalAtomicResultValues(m_repeaters_[i], m_number_segments_[i] * number_branches * number_bits);
+            wire_length /= 2.0;
+            number_branches *= 2;
+        }
+        number_branches = (unsigned int)pow(2.0, (double)number_levels-1);
+        addElecticalAtomicResultValues(m_leaf_head_driver_, number_branches * number_bits);
+        for(unsigned int i = 0; i < m_leaf_drivers_.size(); ++i)
+        {
+            addElecticalAtomicResultValues(m_leaf_drivers_[i], number_branches * number_bits);
+        }
+        addElecticalWireAtomicResultValue(wire_layer, wire_area);
+
+        return;
+    }
+
+    void BroadcastHTree::useModel()
+    {
+        unsigned int number_bits = getParameter("NumberBits").toUInt();
+        unsigned int number_levels = getParameter("NumberLevels").toUInt();
+
+        // Update the transition information for the modeled repeaters
+        // Since we only modeled one repeater. So the transition information for 0->0 and 1->1 
+        // is averaged out
+        const TransitionInfo& trans_In = getInputPort("In")->getTransitionInfo();
+        double average_static_transition = (trans_In.getNumberTransitions00() + trans_In.getNumberTransitions11()) / 2.0;
+        TransitionInfo mod_trans_In(average_static_transition, trans_In.getNumberTransitions01(), average_static_transition);
+
+        // Propagate the transition information
+        propagateTransitionInfo();
+
+        // Update leakage and event
+        double energy = 0.0;
+        double power = 0.0;
+        unsigned int number_branches = 1;
+        for(unsigned int i = 0; i < number_levels; ++i)
+        {
+            assignPortTransitionInfo(m_repeaters_[i], "A", mod_trans_In);
+            m_repeaters_[i]->use();
+            power += m_repeaters_[i]->getNddPowerResult("Leakage")->calculateSum() * m_number_segments_[i] * number_branches;
+            energy += m_repeaters_[i]->getEventResult("INV")->calculateSum() * m_number_segments_[i] * number_branches;
+            number_branches *= 2;
+        }
+        energy *= number_bits;
+        getEventResult("DriveTree")->setValue(energy);
+
+        energy = 0.0;
+        assignPortTransitionInfo(m_leaf_head_driver_, "A", mod_trans_In);
+        m_leaf_head_driver_->use();
+        number_branches = (unsigned int)pow(2.0, (double)number_levels-1);
+        power += m_leaf_head_driver_->getNddPowerResult("Leakage")->calculateSum() * number_branches;
+        energy += m_leaf_head_driver_->getEventResult("INV")->calculateSum() * number_branches;
+        for(unsigned int i = 0; i < m_leaf_drivers_.size(); ++i)
+        {
+            assignPortTransitionInfo(m_leaf_drivers_[i], "A", mod_trans_In);
+            m_leaf_drivers_[i]->use();
+            power += m_leaf_drivers_[i]->getNddPowerResult("Leakage")->calculateSum() * number_branches;
+            energy += m_leaf_drivers_[i]->getEventResult("INV")->calculateSum() * number_branches;
+        }
+        power *= number_bits;
+        energy *= number_bits;
+        getEventResult("DriveLoad")->setValue(energy);
+        getNddPowerResult("Leakage")->setValue(power);
+
+        return;
+    }
+
+    void BroadcastHTree::propagateTransitionInfo()
+    {
+        propagatePortTransitionInfo("Out", "In");
+        return;
+    }
+} // namespace DSENT
+
diff --git a/ext/dsent/model/electrical/BroadcastHTree.h b/ext/dsent/model/electrical/BroadcastHTree.h
new file mode 100644 (file)
index 0000000..f2c8d40
--- /dev/null
@@ -0,0 +1,54 @@
+#ifndef __DSENT_MODEL_ELECTRICAL_BROADCAST_HTREE_H__
+#define __DSENT_MODEL_ELECTRICAL_BROADCAST_HTREE_H__
+
+#include "util/CommonType.h"
+#include "model/ElectricalModel.h"
+
+#include <vector>
+
+namespace DSENT
+{
+    using std::vector;
+
+    class StdCell;
+    class ElectricalLoad;
+    class ElectricalTimingTree;
+
+    class BroadcastHTree : public ElectricalModel
+    {
+        public:
+            BroadcastHTree(const String& instance_name_, const TechModel* tech_model_);
+            virtual ~BroadcastHTree();
+
+        public:
+            // Set a list of properties' name needed to construct model
+            void initParameters();
+            // Set a list of properties' name needed to construct model
+            void initProperties();
+
+            // Clone and return a new instance
+            virtual BroadcastHTree* clone() const;
+
+        protected:
+            // Build the model
+            virtual void constructModel();
+            virtual void updateModel();
+            virtual void useModel();
+            virtual void propagateTransitionInfo();
+
+        private:
+            vector<StdCell*> m_repeaters_;
+            vector<ElectricalLoad*> m_repeater_loads_;
+            vector<ElectricalTimingTree*> m_timing_trees_;
+            vector<unsigned int> m_number_segments_;
+
+            vector<StdCell*> m_leaf_drivers_;
+            ElectricalLoad* m_leaf_load_;
+            StdCell* m_leaf_head_driver_;
+            ElectricalLoad* m_leaf_head_load_;
+
+    }; // class BroadcastHTree
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_ELECTRICAL_BROADCAST_HTREE_H__
+
diff --git a/ext/dsent/model/electrical/DFFRAM.cc b/ext/dsent/model/electrical/DFFRAM.cc
new file mode 100644 (file)
index 0000000..604aead
--- /dev/null
@@ -0,0 +1,321 @@
+#include "model/electrical/DFFRAM.h"
+
+#include <cmath>
+
+#include "model/PortInfo.h"
+#include "model/EventInfo.h"
+#include "model/TransitionInfo.h"
+#include "model/timing_graph/ElectricalDriverMultiplier.h"
+#include "model/timing_graph/ElectricalNet.h"
+#include "model/std_cells/StdCell.h"
+#include "model/std_cells/StdCellLib.h"
+#include "model/electrical/Decoder.h"
+#include "model/electrical/Multiplexer.h"
+
+namespace DSENT
+{
+    using std::ceil;
+
+    DFFRAM::DFFRAM(const String& instance_name_, const TechModel* tech_model_)
+        : ElectricalModel(instance_name_, tech_model_)
+    {
+        initParameters();
+        initProperties();
+    }
+
+    DFFRAM::~DFFRAM()
+    {}
+
+    void DFFRAM::initParameters()
+    {
+        addParameterName("NumberEntries");
+        addParameterName("NumberBits");
+        return;
+    }
+
+    void DFFRAM::initProperties()
+    {
+        return;
+    }
+
+    DFFRAM* DFFRAM::clone() const
+    {
+        // TODO
+        return NULL;
+    }
+
+    void DFFRAM::constructModel()
+    {
+        // Get parameters
+        unsigned int number_bits = getParameter("NumberBits").toUInt();
+        unsigned int number_entries = getParameter("NumberEntries").toUInt();
+
+        ASSERT(number_bits > 0, "[Error] " + getInstanceName() + 
+            " -> Number of bits must be > 0!");
+        ASSERT(number_entries > 0, "[Error] " + getInstanceName() + 
+            " -> Number of entries must be > 0!");
+
+        unsigned int number_addr_bits = (unsigned int)ceil(log2(number_entries));
+
+        // Create ports
+        createInputPort("In", makeNetIndex(0, number_bits-1));
+        for(unsigned int i = 0; i < number_addr_bits; ++i)
+        {
+            createInputPort("WRAddr" + (String)i);
+            createInputPort("RDAddr" + (String)i);
+        }
+        createInputPort("WE");
+        createInputPort("CK");
+        createOutputPort("Out", makeNetIndex(0, number_bits-1));
+
+        // Create energy, power, and area results
+        createElectricalResults();
+        getEventInfo("Idle")->setStaticTransitionInfos();
+        getEventInfo("Idle")->setTransitionInfo("CK", TransitionInfo(0.0, 1.0, 0.0));
+        getEventInfo("Idle")->setTransitionInfo("WE", TransitionInfo(1.0, 0.0, 0.0));
+
+        createElectricalEventResult("Read");
+        getEventInfo("Read")->setTransitionInfo("CK", TransitionInfo(0.0, 1.0, 0.0));
+        getEventInfo("Read")->setTransitionInfo("WE", TransitionInfo(1.0, 0.0, 0.0));
+        for(unsigned int i = 0; i < number_addr_bits; ++i)
+        {
+            getEventInfo("Read")->setTransitionInfo("WRAddr" + (String)i, TransitionInfo(0.5, 0.0, 0.5));
+        }
+        createElectricalEventResult("Write");
+        getEventInfo("Write")->setTransitionInfo("CK", TransitionInfo(0.0, 1.0, 0.0));
+        getEventInfo("Write")->setTransitionInfo("WE", TransitionInfo(0.0, 0.0, 1.0));
+        for(unsigned int i = 0; i < number_addr_bits; ++i)
+        {
+            getEventInfo("Write")->setTransitionInfo("RDAddr" + (String)i, TransitionInfo(0.5, 0.0, 0.5));
+        }
+
+        // Init components - DFF array, Dec, Mux
+        vector<String> dff_names(number_entries, "");
+        vector<StdCell*> dffs(number_entries, NULL);
+        for(unsigned int i = 0; i < number_entries; ++i)
+        {
+            dff_names[i] = "DFF_" + (String)i;
+            dffs[i] = getTechModel()->getStdCellLib()->createStdCell("DFFQ", dff_names[i]);
+            dffs[i]->construct();
+        }
+                    
+        const String& dec_name = "Dec";
+        Decoder* dec = new Decoder(dec_name, getTechModel());
+        dec->setParameter("NumberOutputs", number_entries);
+        dec->construct();
+
+        const String& mux_name = "Mux";
+        Multiplexer* mux = new Multiplexer(mux_name, getTechModel());
+        mux->setParameter("NumberInputs", number_entries);
+        mux->setParameter("NumberBits", 1);
+        mux->setParameter("BitDuplicate", "TRUE");
+        mux->construct();
+
+        // Init components - CK & WE
+        const String& nand2cg0_name = "NAND2_CKGate0";
+        StdCell* nand2cg0 = getTechModel()->getStdCellLib()->createStdCell("NAND2", nand2cg0_name);
+        nand2cg0->construct();
+        const String& invcg0_name = "INV_CKGate0";
+        StdCell* invcg0 = getTechModel()->getStdCellLib()->createStdCell("INV", invcg0_name);
+        invcg0->construct();
+
+        // Init components - (CK & WE) & DecOut[i]
+        vector<String> nand2cg1_names(number_entries, "");
+        vector<StdCell*> nand2cg1s(number_entries, NULL);
+        vector<String> invcg1_names(number_entries, "");
+        vector<StdCell*> invcg1s(number_entries, NULL);
+        for(unsigned int i = 0; i < number_entries; ++i)
+        {
+            nand2cg1_names[i] = "NAND2_CKGate1_" + (String)i;
+            nand2cg1s[i] = getTechModel()->getStdCellLib()->createStdCell("NAND2", nand2cg1_names[i]);
+            nand2cg1s[i]->construct();
+
+            invcg1_names[i] = "INV_CKGate1_" + (String)i;
+            invcg1s[i] = getTechModel()->getStdCellLib()->createStdCell("INV", invcg1_names[i]);
+            invcg1s[i]->construct();
+        }
+
+        // Connect Decoder
+        for(unsigned int i = 0; i < number_addr_bits; ++i)
+        {
+            portConnect(dec, "Addr" + (String)i, "WRAddr" + (String)i);
+        }
+        for(unsigned int i = 0; i < number_entries; ++i)
+        {
+            createNet("Dec_Out" + (String)i);
+            portConnect(dec, "Out" + (String)i, "Dec_Out" + (String)i);
+        }
+
+        // Connect CKGate0 - CK, WE
+        createNet("NAND2_CKGate0_Out");
+        createNet("CKGate0_Out");
+        portConnect(nand2cg0, "A", "CK");
+        portConnect(nand2cg0, "B", "WE");
+        portConnect(nand2cg0, "Y", "NAND2_CKGate0_Out");
+        portConnect(invcg0, "A", "NAND2_CKGate0_Out");
+        portConnect(invcg0, "Y", "CKGate0_Out");
+
+        // Connect CKGate1 - CKGate0, Dec_Out
+        for(unsigned int i = 0; i < number_entries; ++i)
+        {
+            createNet("NAND2_CKGate1_Outs" + (String)i);
+            createNet("CKGate1_Outs" + (String)i);
+            portConnect(nand2cg1s[i], "A", "CKGate0_Out");
+            portConnect(nand2cg1s[i], "B", "Dec_Out" + (String)i);
+            portConnect(nand2cg1s[i], "Y", "NAND2_CKGate1_Outs" + (String)i);
+            portConnect(invcg1s[i], "A", "NAND2_CKGate1_Outs" + (String)i);
+            portConnect(invcg1s[i], "Y", "CKGate1_Outs" + (String)i);
+        }
+
+        // Connect DFF array
+        for(unsigned int i = 0; i < number_entries; ++i)
+        {
+            createNet("DFF_Out" + (String)i);
+            for(unsigned int n = 0; n < number_bits; ++n)
+            {
+                portConnect(dffs[i], "D", "In", makeNetIndex(n));
+                portConnect(dffs[i], "CK", "CKGate1_Outs" + (String)i);
+            }
+            portConnect(dffs[i], "Q", "DFF_Out" + (String)i);
+        }
+
+        // Connect Multiplexer
+        createNet("Mux_Out");
+        for(unsigned int i = 0; i < number_entries; ++i)
+        {
+            portConnect(mux, "In" + (String)i, "DFF_Out" + (String)i);
+        }
+        for(unsigned int i = 0; i < number_addr_bits; ++i)
+        {
+            portConnect(mux, "Sel" + (String)i, "RDAddr" + (String)i);
+        }
+        portConnect(mux, "Out", "Mux_Out");
+
+        // Use driver multiplier to connect Mux_Out to Out
+        createDriverMultiplier("OutMult");
+        ElectricalDriverMultiplier* drive_mult = getDriverMultiplier("OutMult");
+        getNet("Mux_Out")->addDownstreamNode(drive_mult);
+        for(unsigned int n = 0; n < number_bits; ++n)
+        {
+            drive_mult->addDownstreamNode(getNet("Out", makeNetIndex(n)));
+        }
+
+        // Add area and power results
+        for(unsigned int i = 0; i < number_entries; ++i)
+        {
+            addSubInstances(dffs[i], number_bits);
+            addElectricalSubResults(dffs[i], number_bits);
+        }
+
+        addSubInstances(dec, 1.0);
+        addElectricalSubResults(dec, 1.0);
+
+        addSubInstances(mux, number_bits);
+        addElectricalSubResults(mux, number_bits);
+
+        addSubInstances(nand2cg0, 1.0);
+        addElectricalSubResults(nand2cg0, 1.0);
+
+        addSubInstances(invcg0, 1);
+        addElectricalSubResults(invcg0, 1.0);
+
+        for(unsigned int i = 0; i < number_entries; ++i)
+        {
+            addSubInstances(nand2cg1s[i], 1);
+            addElectricalSubResults(nand2cg1s[i], 1.0);
+
+            addSubInstances(invcg1s[i], 1);
+            addElectricalSubResults(invcg1s[i], 1.0);
+        }
+
+        // Add write event
+        Result* write_event = getEventResult("Write");
+        write_event->addSubResult(nand2cg0->getEventResult("NAND2"), nand2cg0_name, 1.0);
+        write_event->addSubResult(invcg0->getEventResult("INV"), invcg0_name, 1.0);
+        write_event->addSubResult(dec->getEventResult("Decode"), dec_name, 1.0);
+        for(unsigned int i = 0; i < number_entries; ++i)
+        {
+            write_event->addSubResult(nand2cg1s[i]->getEventResult("NAND2"), nand2cg1_names[i], 1.0);
+            write_event->addSubResult(invcg1s[i]->getEventResult("INV"), invcg1_names[i], 1.0);
+            write_event->addSubResult(dffs[i]->getEventResult("DFFD"), dff_names[i], number_bits);
+            write_event->addSubResult(dffs[i]->getEventResult("DFFQ"), dff_names[i], number_bits);
+            write_event->addSubResult(dffs[i]->getEventResult("CK"), dff_names[i], number_bits);
+        }
+
+        // Add read event
+        Result* read_event = getEventResult("Read");
+        //for(unsigned int i = 0; i < number_entries; ++i)
+        //{
+        //    read_event->addSubResult(dffs[i]->getEventResult("DFFQ"), dff_names[i], number_bits);
+        //}
+        read_event->addSubResult(mux->getEventResult("Mux"), mux_name, number_bits);
+
+        return;
+    }
+
+    void DFFRAM::propagateTransitionInfo()
+    {
+        // Update probability
+        unsigned int number_entries = (unsigned int)getParameter("NumberEntries");
+        unsigned int number_addr_bits = (unsigned int)ceil(log2(number_entries));
+
+        // Update decoder
+        ElectricalModel* dec = (ElectricalModel*)getSubInstance("Dec");
+        for(unsigned int i = 0; i < number_addr_bits; ++i)
+        {
+            propagatePortTransitionInfo(dec, "Addr" + (String)i, "WRAddr" + (String)i);
+        }
+        dec->use();
+
+        // Update CKGate0 nands + invs
+        ElectricalModel* nand2cg0 = (ElectricalModel*)getSubInstance("NAND2_CKGate0");
+        propagatePortTransitionInfo(nand2cg0, "A", "CK");
+        propagatePortTransitionInfo(nand2cg0, "B", "WE");
+        nand2cg0->use();
+        ElectricalModel* invcg0 = (ElectricalModel*)getSubInstance("INV_CKGate0");
+        propagatePortTransitionInfo(invcg0, "A", nand2cg0, "Y");
+        invcg0->use();
+
+        // Update CKGate1 nands + invs
+        vector<ElectricalModel*> nand2cg1s(number_entries, NULL);
+        vector<ElectricalModel*> invcg1s(number_entries, NULL);
+        for(unsigned int i = 0; i < number_entries; ++i)
+        {
+            nand2cg1s[i] = (ElectricalModel*)getSubInstance("NAND2_CKGate1_" + (String)i);
+            propagatePortTransitionInfo(nand2cg1s[i], "A", invcg0, "Y");
+            propagatePortTransitionInfo(nand2cg1s[i], "B", dec, "Out" + (String)i);
+            nand2cg1s[i]->use();
+
+            invcg1s[i] = (ElectricalModel*)getSubInstance("INV_CKGate1_" + (String)i);
+            propagatePortTransitionInfo(invcg1s[i], "A", nand2cg1s[i], "Y");
+            invcg1s[i]->use();
+        }
+
+        // Update DFF
+        vector<ElectricalModel*> dffs(number_entries, NULL);
+        for(unsigned int i = 0; i < number_entries; ++i)
+        {
+            dffs[i] = (ElectricalModel*)getSubInstance("DFF_" + (String)i);
+            propagatePortTransitionInfo(dffs[i], "D", "In");
+            propagatePortTransitionInfo(dffs[i], "CK", invcg1s[i], "Y");
+            dffs[i]->use();
+        }
+
+        // Update Mux
+        ElectricalModel* mux = (ElectricalModel*)getSubInstance("Mux");
+        for(unsigned int i = 0; i < number_entries; ++i)
+        {
+            propagatePortTransitionInfo(mux, "In" + (String)i, dffs[i], "Q");
+        }
+        for(unsigned int i = 0; i < number_addr_bits; ++i)
+        {
+            propagatePortTransitionInfo(mux, "Sel" + (String)i, "RDAddr" + (String)i);
+        }
+        mux->use();
+
+        // Set output probability
+        getOutputPort("Out")->setTransitionInfo(mux->getOutputPort("Out")->getTransitionInfo());
+        return;
+    }
+} // namespace DSENT
+
diff --git a/ext/dsent/model/electrical/DFFRAM.h b/ext/dsent/model/electrical/DFFRAM.h
new file mode 100644 (file)
index 0000000..0e7626e
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef __DSENT_MODEL_ELECTRICAL_DFFRAM_H__
+#define __DSENT_MODEL_ELECTRICAL_DFFRAM_H__
+
+#include "util/CommonType.h"
+#include "model/ElectricalModel.h"
+
+namespace DSENT
+{
+    class DFFRAM : public ElectricalModel
+    {
+        public:
+            DFFRAM(const String& instance_name_, const TechModel* tech_model_);
+            virtual ~DFFRAM();
+
+        public:
+            // Set a list of properties' name needed to construct model
+            void initParameters();
+            // Set a list of properties' name needed to construct model
+            void initProperties();
+
+            // Clone and return a new instance
+            virtual DFFRAM* clone() const;
+
+        protected:
+            // Build the model
+            virtual void constructModel();
+            virtual void propagateTransitionInfo();
+
+    }; // class DFFRAM
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_ELECTRICAL_BUFFER_H__
+
diff --git a/ext/dsent/model/electrical/Decoder.cc b/ext/dsent/model/electrical/Decoder.cc
new file mode 100644 (file)
index 0000000..7629bf8
--- /dev/null
@@ -0,0 +1,235 @@
+#include "model/electrical/Decoder.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/StdCell.h"
+
+namespace DSENT
+{
+    using std::ceil;
+
+    Decoder::Decoder(const String& instance_name_, const TechModel* tech_model_)
+        : ElectricalModel(instance_name_, tech_model_)
+    {
+        initParameters();
+        initProperties();
+    }
+
+    Decoder::~Decoder()
+    {}
+
+    void Decoder::initParameters()
+    {
+        addParameterName("NumberOutputs");
+    }
+
+    void Decoder::initProperties()
+    {
+        return;
+    }
+
+    Decoder* Decoder::clone() const
+    {
+        // TODO
+        return NULL;
+    }
+
+    void Decoder::constructModel()
+    {
+        // Get parameters
+        unsigned int number_outputs = getParameter("NumberOutputs").toUInt();
+
+        ASSERT(number_outputs > 0, "[Error] " + getInstanceName() + " -> Number of outputs must be > 0!");
+
+        unsigned int number_addr_bits = (unsigned int)ceil(log2(number_outputs));
+
+        // Create ports
+        for(unsigned int i = 0; i < number_addr_bits; ++i)
+        {
+            createInputPort("Addr" + (String)i);
+        }
+        for(unsigned int i = 0; i < number_outputs; ++i)
+        {
+            createOutputPort("Out" + (String)i);
+        }
+
+        // Create energy, power, and area results
+        createElectricalResults();
+        createElectricalEventResult("Decode");
+        Result* decode_event = getEventResult("Decode");
+
+        getEventInfo("Idle")->setStaticTransitionInfos();
+
+        if(number_addr_bits == 0)
+        {
+            // Do not need a decoder
+        }
+        else if(number_addr_bits == 1)
+        {
+            const String& inv0_name = "Inv0";
+
+            StdCell* inv0 = getTechModel()->getStdCellLib()->createStdCell("INV", inv0_name);
+            inv0->construct();
+
+            // Connect inputs and outputs
+            portConnect(inv0, "A", "Addr0");
+            portConnect(inv0, "Y", "Out0");
+            assign("Out1", "Addr0");
+
+            // Add area, power, and event results
+            addSubInstances(inv0, 1.0);
+            addElectricalSubResults(inv0, 1.0);
+            decode_event->addSubResult(inv0->getEventResult("INV"), inv0_name, 1.0);
+        }
+        else
+        {
+            unsigned int number_addr_bits_0 = (unsigned int)ceil((double)number_addr_bits / 2.0);
+            unsigned int number_addr_bits_1 = (unsigned int)floor((double)number_addr_bits / 2.0);
+
+            unsigned int number_outputs_0 = (unsigned int)pow(2.0, number_addr_bits_0);
+            unsigned int number_outputs_1 = (unsigned int)ceil((double)number_outputs / (double)number_outputs_0);
+
+            const String& dec0_name = "Dec_way0";
+            const String& dec1_name = "Dec_way1";
+            vector<String> nand2_names(number_outputs, "");
+            vector<String> inv_names(number_outputs, "");
+            for(unsigned int i = 0; i < number_outputs; ++i)
+            {
+                nand2_names[i] = "NAND2_" + (String)i;
+                inv_names[i] = "INV_" + (String)i;
+            }
+
+            Decoder* dec0 = new Decoder(dec0_name, getTechModel());
+            dec0->setParameter("NumberOutputs", number_outputs_0);
+            dec0->construct();
+
+            Decoder* dec1 = new Decoder(dec1_name, getTechModel());
+            dec1->setParameter("NumberOutputs", number_outputs_1);
+            dec1->construct();
+
+            vector<StdCell*> nand2s(number_outputs, NULL);
+            vector<StdCell*> invs(number_outputs, NULL);
+            for(unsigned int i = 0; i < number_outputs; ++i)
+            {
+                nand2s[i] = getTechModel()->getStdCellLib()->createStdCell("NAND2", nand2_names[i]);
+                nand2s[i]->construct();
+                invs[i] = getTechModel()->getStdCellLib()->createStdCell("INV", inv_names[i]);
+                invs[i]->construct();
+            }
+
+            // Connect inputs and outputs
+            for(unsigned int i = 0; i < number_addr_bits_0; ++i)
+            {
+                portConnect(dec0, "Addr" + (String)i, "Addr" + (String)i);
+            }
+            for(unsigned int i = 0; i < number_addr_bits_1; ++i)
+            {
+                portConnect(dec1, "Addr" + (String)i, "Addr" + (String)(i + number_addr_bits_0));
+            }
+            for(unsigned int i = 0; i < number_outputs_0; ++i)
+            {
+                createNet("way0Out" + (String)i);
+                portConnect(dec0, "Out" + (String)i, "way0Out" + (String)i);
+            }
+            for(unsigned int i = 0; i < number_outputs_1; ++i)
+            {
+                createNet("way1Out" + (String)i);
+                portConnect(dec1, "Out" + (String)i, "way1Out" + (String)i);
+            }
+
+            for(unsigned int i = 0; i < number_outputs; ++i)
+            {
+                createNet("nand" + (String)i + "Out");
+                portConnect(nand2s[i], "A", "way0Out" + (String)(i%number_outputs_0));
+                portConnect(nand2s[i], "B", "way1Out" + (String)((unsigned int)floor(i/number_outputs_0)));
+                portConnect(nand2s[i], "Y", "nand" + (String)i + "Out");
+                portConnect(invs[i], "A", "nand" + (String)i + "Out");
+                portConnect(invs[i], "Y", "Out" + (String)i);
+            }
+
+            // Add area, power, and event results
+            addSubInstances(dec0, 1.0);
+            addElectricalSubResults(dec0, 1.0);
+            decode_event->addSubResult(dec0->getEventResult("Decode"), dec0_name, 1.0);
+            addSubInstances(dec1, 1.0);
+            addElectricalSubResults(dec1, 1.0);
+            decode_event->addSubResult(dec1->getEventResult("Decode"), dec1_name, 1.0);
+            for(unsigned int i = 0; i < number_outputs; ++i)
+            {
+                addSubInstances(nand2s[i], 1.0);
+                addElectricalSubResults(nand2s[i], 1.0);
+                decode_event->addSubResult(nand2s[i]->getEventResult("NAND2"), nand2_names[i], 1.0);
+
+                addSubInstances(invs[i], 1.0);
+                addElectricalSubResults(invs[i], 1.0);
+                decode_event->addSubResult(invs[i]->getEventResult("INV"), inv_names[i], 1.0);
+            }
+        }
+        return;
+    }
+
+    void Decoder::propagateTransitionInfo()
+    {
+        // The only thing can be updated are the input probabilities
+        unsigned int number_outputs = getParameter("NumberOutputs").toUInt();
+
+        unsigned int number_addr_bits = (unsigned int)ceil(log2(number_outputs));
+        
+        if(number_addr_bits == 0)
+        {
+            // Do not need a decoder
+        }
+        else if(number_addr_bits == 1)
+        {
+            ElectricalModel* inv0 = (ElectricalModel*)getSubInstance("Inv0");
+            propagatePortTransitionInfo(inv0, "A", "Addr0");
+            inv0->use();
+
+            // Since # addr bits is 1, the output 0 is directly connected
+            propagatePortTransitionInfo("Out0", inv0, "Y");
+            propagatePortTransitionInfo("Out1", "Addr0");
+        }
+        else
+        {
+            unsigned int number_addr_bits_0 = (unsigned int)ceil((double)number_addr_bits / 2.0);
+            unsigned int number_addr_bits_1 = (unsigned int)floor((double)number_addr_bits / 2.0);
+
+            unsigned int number_outputs_0 = (unsigned int)pow(2.0, number_addr_bits_0);
+
+            // Update decoders with probabilities
+            ElectricalModel* dec0 = (ElectricalModel*)getSubInstance("Dec_way0");
+            for(unsigned int i = 0; i < number_addr_bits_0; ++i)
+            {
+                propagatePortTransitionInfo(dec0, "Addr" + (String)i, "Addr" + (String)i);
+            }
+            dec0->use();
+            ElectricalModel* dec1 = (ElectricalModel*)getSubInstance("Dec_way1");
+            for(unsigned int i = 0; i < number_addr_bits_1; ++i)
+            {
+                propagatePortTransitionInfo(dec1, "Addr" + (String)i, "Addr" + (String)(i + number_addr_bits_0));
+            }
+            dec1->use();
+
+            for(unsigned int i = 0; i < number_outputs; ++i)
+            {
+                ElectricalModel* nand2 = (ElectricalModel*)getSubInstance("NAND2_" + (String)i);
+                propagatePortTransitionInfo(nand2, "A", dec0, "Out" + (String)(i%number_outputs_0));
+                propagatePortTransitionInfo(nand2, "B", dec1, "Out" + (String)((unsigned int)floor(i/number_outputs_0)));
+                nand2->use();
+
+                ElectricalModel* inv = (ElectricalModel*)getSubInstance("INV_" + (String)i);
+                propagatePortTransitionInfo(inv, "A", nand2, "Y");
+                inv->use();
+
+                propagatePortTransitionInfo("Out" + (String)i, inv, "Y");
+            }
+        }
+        return;
+    }
+
+} // namespace DSENT
+
diff --git a/ext/dsent/model/electrical/Decoder.h b/ext/dsent/model/electrical/Decoder.h
new file mode 100644 (file)
index 0000000..3c09fc4
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef __DSENT_MODEL_ELECTRICAL_DECODER_H__
+#define __DSENT_MODEL_ELECTRICAL_DECODER_H__
+
+#include "util/CommonType.h"
+#include "model/ElectricalModel.h"
+
+namespace DSENT
+{
+    class Decoder : public ElectricalModel
+    {
+        public:
+            Decoder(const String& instance_name_, const TechModel* tech_model_);
+            virtual ~Decoder();
+
+        public:
+            // Set a list of properties' name needed to construct model
+            void initParameters();
+            // Set a list of properties' name needed to construct model
+            void initProperties();
+
+            // Clone and return a new instance
+            virtual Decoder* clone() const;
+
+        protected:
+            // Build the model
+            virtual void constructModel();
+            virtual void propagateTransitionInfo();
+
+    }; // class Decoder
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_ELECTRICAL_DECODER_H__
+
diff --git a/ext/dsent/model/electrical/DemuxTreeDeserializer.cc b/ext/dsent/model/electrical/DemuxTreeDeserializer.cc
new file mode 100644 (file)
index 0000000..4d74e8d
--- /dev/null
@@ -0,0 +1,378 @@
+#include "model/electrical/DemuxTreeDeserializer.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/StdCell.h"
+#include "model/electrical/Multiplexer.h"
+#include "model/timing_graph/ElectricalNet.h"
+
+namespace DSENT
+{
+    using std::ceil;
+
+    DemuxTreeDeserializer::DemuxTreeDeserializer(const String& instance_name_, const TechModel* tech_model_)
+        : ElectricalModel(instance_name_, tech_model_)
+    {
+        initParameters();
+        initProperties();
+    }
+
+    DemuxTreeDeserializer::~DemuxTreeDeserializer()
+    {}
+
+    void DemuxTreeDeserializer::initParameters()
+    {
+        addParameterName("InDataRate");
+        addParameterName("OutDataRate");
+        addParameterName("OutBits");              //Output width will just be output width / serialization ratio
+        addParameterName("BitDuplicate", "TRUE");
+        return;
+    }
+
+    void DemuxTreeDeserializer::initProperties()
+    {
+        return;
+    }
+
+    DemuxTreeDeserializer* DemuxTreeDeserializer::clone() const
+    {
+        // TODO
+        return NULL;
+    }
+
+    void DemuxTreeDeserializer::constructModel()
+    {
+
+        // Get parameters
+        double in_data_rate = getParameter("InDataRate");
+        double out_data_rate = getParameter("OutDataRate");
+        unsigned int out_bits = getParameter("OutBits");
+        bool bit_duplicate = getParameter("BitDuplicate");                        
+        
+        // Calculate deserialization ratio
+        unsigned int deserialization_ratio = (unsigned int) floor(in_data_rate / out_data_rate);    
+        ASSERT(deserialization_ratio == in_data_rate / out_data_rate,
+            "[Error] " + getInstanceName() + " -> Cannot have non-integer deserialization ratios!");
+        ASSERT((deserialization_ratio & (deserialization_ratio - 1)) == 0,
+            "[Error] " + getInstanceName() + " -> Deserialization ratio must be a power of 2");
+        
+        // Calculate output width
+        unsigned int input_bits = out_bits / deserialization_ratio;
+        ASSERT(out_bits >= deserialization_ratio, "[Error] " + getInstanceName() + 
+            " -> Output width must be >= deserialization ratio!");
+        ASSERT(floor((double) out_bits / deserialization_ratio) == input_bits,
+            "[Error] " + getInstanceName() + " -> Output width must be a multiple of the serialization ratio!");
+                
+        // Store calculated numbers
+        getGenProperties()->set("DeserializationRatio", deserialization_ratio);
+        getGenProperties()->set("InputBits", input_bits);
+        
+        // Create ports
+        createInputPort("In", makeNetIndex(0, input_bits-1));
+        createInputPort("InCK");
+        createOutputPort("Out", makeNetIndex(0, out_bits-1));        
+        
+        //Create energy, power, and area results
+        createElectricalResults();
+        createElectricalEventResult("Deserialize");
+        getEventInfo("Deserialize")->setTransitionInfo("InCK", TransitionInfo(0.0, (double) deserialization_ratio / 2.0, 0.0));
+        // Set conditions during idle state
+        getEventInfo("Idle")->setStaticTransitionInfos();
+        getEventInfo("Idle")->setTransitionInfo("InCK", TransitionInfo(0.0, (double) deserialization_ratio / 2.0, 0.0));
+
+        // Mark InCK as a false path (since timing tool will do strange stuff due to all the clock divides and stuff)
+        getNet("InCK")->setFalsePath(true);
+        
+        // Create deserializer
+        if (deserialization_ratio == 1)
+        {
+            // No need to do anything, hohoho
+            assign("Out", "In");
+        }
+        else if (input_bits == 1)
+        {
+            //-----------------------------------------------------------------
+            // Create 2:1 demux deserializer
+            //-----------------------------------------------------------------
+            const String& des_dff_way0_name = "DesDFFWay0";
+            const String& des_dff_way1_name = "DesDFFWay1";                
+            const String& des_latch_name = "DesLatch";
+            const String& ck_dff_name = "CKDFF";
+            const String& ck_inv_name = "CKINV";            
+            const String& out_way0_name = "OutWay0";
+            const String& out_way1_name = "OutWay1";
+            const String& mid_way0_name = "MidWay0";
+            const String& ck_div2_name = "CK_div2";
+            const String& ck_div2_b_name = "CK_div2_b";
+            
+            // Create nets
+            createNet(out_way0_name);
+            createNet(out_way1_name);
+            createNet(mid_way0_name);
+            createNet(ck_div2_name);
+            createNet(ck_div2_b_name);
+            
+            // Create the dffs and latch needed on both ways
+            StdCell* des_dff_way0 = getTechModel()->getStdCellLib()->createStdCell("DFFQ", des_dff_way0_name);
+            des_dff_way0->construct();
+            StdCell* des_dff_way1 = getTechModel()->getStdCellLib()->createStdCell("DFFQ", des_dff_way1_name);
+            des_dff_way1->construct();
+            StdCell* des_latch = getTechModel()->getStdCellLib()->createStdCell("LATQ", des_latch_name);
+            des_latch->construct();
+            
+            // Create clk divide circuit
+            StdCell* ck_dff = getTechModel()->getStdCellLib()->createStdCell("DFFQ", ck_dff_name);
+            ck_dff->construct();            
+            StdCell* ck_inv = getTechModel()->getStdCellLib()->createStdCell("INV", ck_inv_name);
+            ck_inv->construct();
+            
+            // Connect ports
+            portConnect(des_dff_way0, "CK", "InCK");
+            portConnect(des_dff_way0, "D", mid_way0_name);
+            portConnect(des_dff_way0, "Q", out_way0_name);
+            portConnect(des_latch, "G", "InCK");
+            portConnect(des_latch, "D", "In");
+            portConnect(des_latch, "Q", mid_way0_name);
+            portConnect(des_dff_way1, "CK", "InCK");
+            portConnect(des_dff_way1, "D", "In");
+            portConnect(des_dff_way1, "Q", out_way1_name);
+            portConnect(ck_dff, "CK", "InCK");
+            portConnect(ck_dff, "D", ck_div2_b_name);
+            portConnect(ck_dff, "Q", ck_div2_name);
+            portConnect(ck_inv, "A", ck_div2_name);
+            portConnect(ck_inv, "Y", ck_div2_b_name);
+            
+            // Add sub instances
+            addSubInstances(des_dff_way0, 1.0);
+            addElectricalSubResults(des_dff_way0, 1.0);
+            addSubInstances(des_dff_way1, 1.0);
+            addElectricalSubResults(des_dff_way1, 1.0);
+            addSubInstances(des_latch, 1.0);
+            addElectricalSubResults(des_latch, 1.0);
+            addSubInstances(ck_dff, 1.0);
+            addElectricalSubResults(ck_dff, 1.0);
+            addSubInstances(ck_inv, 1.0);
+            addElectricalSubResults(ck_inv, 1.0);
+
+            Result* deserialize = getEventResult("Deserialize");
+            deserialize->addSubResult(des_dff_way0->getEventResult("CK"), des_dff_way0_name, 1.0);
+            deserialize->addSubResult(des_dff_way0->getEventResult("DFFD"), des_dff_way0_name, 1.0);
+            deserialize->addSubResult(des_dff_way0->getEventResult("DFFQ"), des_dff_way0_name, 1.0);
+            deserialize->addSubResult(des_dff_way1->getEventResult("CK"), des_dff_way1_name, 1.0);
+            deserialize->addSubResult(des_dff_way1->getEventResult("DFFD"), des_dff_way1_name, 1.0);
+            deserialize->addSubResult(des_dff_way1->getEventResult("DFFQ"), des_dff_way1_name, 1.0);
+            deserialize->addSubResult(des_latch->getEventResult("G"), des_latch_name, 1.0);
+            deserialize->addSubResult(des_latch->getEventResult("LATD"), des_latch_name, 1.0);
+            deserialize->addSubResult(des_latch->getEventResult("LATQ"), des_latch_name, 1.0);
+            deserialize->addSubResult(ck_dff->getEventResult("CK"), ck_dff_name, 1.0);
+            deserialize->addSubResult(ck_dff->getEventResult("DFFD"), ck_dff_name, 1.0);
+            deserialize->addSubResult(ck_dff->getEventResult("DFFQ"), ck_dff_name, 1.0);
+            deserialize->addSubResult(ck_inv->getEventResult("INV"), ck_inv_name, 1.0);
+            //-----------------------------------------------------------------
+            
+            //-----------------------------------------------------------------
+            // Create Sub-deserializers
+            //-----------------------------------------------------------------
+            // Create sub-deserializers
+            const String& demux_way0_name = "DemuxTree_way0_" + (String) deserialization_ratio + "_to_1";
+            const String& demux_way1_name = "DemuxTree_way1_" + (String) deserialization_ratio + "_to_1";
+            
+            DemuxTreeDeserializer* demux_way0 = new DemuxTreeDeserializer(demux_way0_name, getTechModel());
+            demux_way0->setParameter("InDataRate", in_data_rate / 2.0);
+            demux_way0->setParameter("OutDataRate", out_data_rate);
+            demux_way0->setParameter("OutBits", out_bits / 2);
+            demux_way0->setParameter("BitDuplicate", "TRUE");
+            demux_way0->construct();            
+            
+            DemuxTreeDeserializer* demux_way1 = new DemuxTreeDeserializer(demux_way1_name, getTechModel());
+            demux_way1->setParameter("InDataRate", in_data_rate / 2.0);
+            demux_way1->setParameter("OutDataRate", out_data_rate);
+            demux_way1->setParameter("OutBits", out_bits / 2);
+            demux_way1->setParameter("BitDuplicate", "TRUE");
+            demux_way1->construct();
+            
+            // Connect ports
+            portConnect(demux_way0, "In", out_way0_name);
+            portConnect(demux_way0, "InCK", ck_div2_name);
+            portConnect(demux_way0, "Out", "Out", makeNetIndex(0, out_bits/2-1));
+            
+            portConnect(demux_way1, "In", out_way1_name);
+            portConnect(demux_way1, "InCK", ck_div2_name);
+            portConnect(demux_way1, "Out", "Out", makeNetIndex(out_bits/2, out_bits-1));
+            
+            // Add subinstances and area results
+            addSubInstances(demux_way0, 1.0);
+            addElectricalSubResults(demux_way0, 1.0);
+            addSubInstances(demux_way1, 1.0);
+            addElectricalSubResults(demux_way1, 1.0);
+
+            deserialize->addSubResult(demux_way0->getEventResult("Deserialize"), demux_way0_name, 1.0);
+            deserialize->addSubResult(demux_way1->getEventResult("Deserialize"), demux_way1_name, 1.0);
+            //-----------------------------------------------------------------
+            
+        }
+        else if (bit_duplicate)
+        {
+            const String& demux_name = "DemuxTree_" + (String) deserialization_ratio + "_to_1";
+
+            DemuxTreeDeserializer* des_bit = new DemuxTreeDeserializer(demux_name, getTechModel());
+            des_bit->setParameter("InDataRate", in_data_rate);
+            des_bit->setParameter("OutDataRate", out_data_rate);
+            des_bit->setParameter("OutBits", deserialization_ratio);
+            des_bit->setParameter("BitDuplicate", "TRUE");
+            des_bit->construct();
+            
+            // Create VFI and VFO nets
+            createNet("InVFI");
+            createNet("OutVFO", makeNetIndex(0, deserialization_ratio-1));
+            
+            // Connect ports
+            portConnect(des_bit, "In", "InVFI");
+            portConnect(des_bit, "Out", "OutVFO");
+                
+            // Do VFI and VFO
+            assignVirtualFanin("InVFI", "In");
+            for (unsigned int i = 0; i < input_bits; ++i)
+            {
+                portConnect(des_bit, "InCK", "InCK");                        
+                for (unsigned int j = 0; j < deserialization_ratio; ++j)
+                    assignVirtualFanout("Out", makeNetIndex(i*deserialization_ratio + j), "OutVFO", makeNetIndex(j));
+            }
+            // Add subinstances and area results
+            addSubInstances(des_bit, input_bits);
+            addElectricalSubResults(des_bit, input_bits);
+            getEventResult("Deserialize")->addSubResult(des_bit->getEventResult("Deserialize"), demux_name, input_bits);            
+        }
+        else
+        {
+            //Instantiate a bunch of 1 input bit deserializers
+            for (unsigned int i = 0; i < input_bits; ++i)
+            {
+                const String& demux_name = "DemuxTree_" + (String) deserialization_ratio + "_to_1_bit" + (String) i;
+                
+                DemuxTreeDeserializer* des_bit = new DemuxTreeDeserializer(demux_name, getTechModel());
+                des_bit->setParameter("InDataRate", in_data_rate);
+                des_bit->setParameter("OutDataRate", out_data_rate);
+                des_bit->setParameter("OutBits", deserialization_ratio);
+                des_bit->setParameter("BitDuplicate", "TRUE");
+                des_bit->construct();
+                
+                portConnect(des_bit, "In", "In", makeNetIndex(i));
+                portConnect(des_bit, "InCK", "InCK");
+                portConnect(des_bit, "Out", "Out", makeNetIndex(i*deserialization_ratio, (i+1)*deserialization_ratio-1));
+                
+                addSubInstances(des_bit, 1.0);
+                addElectricalSubResults(des_bit, 1.0);
+                getEventResult("Deserialize")->addSubResult(des_bit->getEventResult("Deserialize"), demux_name, 1.0);
+            }
+        }
+
+        return;
+    }
+
+    void DemuxTreeDeserializer::propagateTransitionInfo()
+    {
+        // Get parameters
+        bool bit_duplicate = getParameter("BitDuplicate");                        
+        // Get generated properties
+        unsigned int deserialization_ratio = getGenProperties()->get("DeserializationRatio");
+        unsigned int input_bits = getGenProperties()->get("InputBits");
+                
+        // Calculate output transitions and activities
+        if (deserialization_ratio == 1)
+        {
+            // If no deserialization, then just propagate input transition info to output port
+            propagatePortTransitionInfo("Out", "In");
+        }
+        else if (input_bits == 1)
+        {            
+            const String& des_dff_way0_name = "DesDFFWay0";
+            const String& des_dff_way1_name = "DesDFFWay1";                
+            const String& des_latch_name = "DesLatch";
+            const String& ck_dff_name = "CKDFF";
+            const String& ck_inv_name = "CKINV";            
+
+            // Sub-deserializer names
+            const String& demux_way0_name = "DemuxTree_way0_" + (String) deserialization_ratio + "_to_1";
+            const String& demux_way1_name = "DemuxTree_way1_" + (String) deserialization_ratio + "_to_1";
+
+            // Update transition info for deserialization registers/latches
+            ElectricalModel* des_latch = (ElectricalModel*) getSubInstance(des_latch_name);
+            propagatePortTransitionInfo(des_latch, "G", "InCK");
+            propagatePortTransitionInfo(des_latch, "D", "In");
+            des_latch->use();
+
+            ElectricalModel* des_dff_way0 = (ElectricalModel*) getSubInstance(des_dff_way0_name);
+            propagatePortTransitionInfo(des_dff_way0, "CK", "InCK");
+            propagatePortTransitionInfo(des_dff_way0, "D", des_latch, "Q");
+            des_dff_way0->use();
+
+            ElectricalModel* des_dff_way1 = (ElectricalModel*) getSubInstance(des_dff_way1_name);
+            propagatePortTransitionInfo(des_dff_way1, "CK", "InCK");
+            propagatePortTransitionInfo(des_dff_way1, "D", "In");
+            des_dff_way1->use();
+
+            // Get input transitions of input clock
+            double P01_CK = getInputPort("InCK")->getTransitionInfo().getNumberTransitions01();
+            // Update transition info for clk division DFF
+            ElectricalModel* ck_dff = (ElectricalModel*) getSubInstance(ck_dff_name);
+            propagatePortTransitionInfo(ck_dff, "CK", "InCK");
+            // Since it is a clock divider, P01 is D and Q are simply half the P01 of D and Q of
+            // the input clock
+            if (P01_CK != 0) ck_dff->getInputPort("D")->setTransitionInfo(TransitionInfo(0.0, P01_CK * 0.5, 0.0));
+            else ck_dff->getInputPort("D")->setTransitionInfo(TransitionInfo(0.5, 0.0, 0.5));
+
+            ck_dff->use();
+            // Update transition info of clk divided inverter
+            ElectricalModel* ck_inv = (ElectricalModel*) getSubInstance(ck_inv_name);
+            propagatePortTransitionInfo(ck_inv, "A", ck_dff, "Q");
+            ck_inv->use();
+            
+            // Update transition info for next demux stages
+            ElectricalModel* demux_way0 = (ElectricalModel*) getSubInstance(demux_way0_name);
+            propagatePortTransitionInfo(demux_way0, "In", des_dff_way0, "Q");
+            propagatePortTransitionInfo(demux_way0, "InCK", ck_dff, "Q");
+            demux_way0->use();
+            ElectricalModel* demux_way1 = (ElectricalModel*) getSubInstance(demux_way1_name);
+            propagatePortTransitionInfo(demux_way1, "In", des_dff_way1, "Q");
+            propagatePortTransitionInfo(demux_way1, "InCK", ck_dff, "Q");
+            demux_way1->use();
+            
+            propagatePortTransitionInfo("Out", demux_way0, "Out");            
+        }
+        else if (bit_duplicate)
+        {
+            // Propagate transition info
+            const String& demux_name = "DemuxTree_" + (String) deserialization_ratio + "_to_1";
+            ElectricalModel* demux = (ElectricalModel*) getSubInstance(demux_name);
+            propagatePortTransitionInfo(demux, "In", "In");
+            propagatePortTransitionInfo(demux, "InCK", "InCK");
+            demux->use();
+
+            propagatePortTransitionInfo("Out", demux, "Out");            
+        }
+        else
+        {
+            // Set output probability to be average that of probabilties of each output bit
+            // Update all 1 bit deserializers
+            for (unsigned int i = 0; i < input_bits; ++i)
+            {
+                const String& demux_name = "DemuxTree_" + (String) deserialization_ratio + "_to_1_bit" + (String) i;
+                ElectricalModel* demux_bit = (ElectricalModel*) getSubInstance(demux_name);
+                propagatePortTransitionInfo(demux_bit, "In", "In");
+                propagatePortTransitionInfo(demux_bit, "InCK", "InCK");
+                demux_bit->use();
+
+                propagatePortTransitionInfo("Out", demux_bit, "Out");
+            }
+        }
+        
+        return;
+    }
+
+} // namespace DSENT
+
diff --git a/ext/dsent/model/electrical/DemuxTreeDeserializer.h b/ext/dsent/model/electrical/DemuxTreeDeserializer.h
new file mode 100644 (file)
index 0000000..2166141
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef __DSENT_MODEL_ELECTRICAL_MULTIPHASEDESERIALIZER_H__
+#define __DSENT_MODEL_ELECTRICAL_MULTIPHASEDESERIALIZER_H__
+
+#include "util/CommonType.h"
+#include "model/ElectricalModel.h"
+
+namespace DSENT
+{
+    class DemuxTreeDeserializer : public ElectricalModel
+    {
+        public:
+            DemuxTreeDeserializer(const String& instance_name_, const TechModel* tech_model_);
+            virtual ~DemuxTreeDeserializer();
+
+        public:
+            // Set a list of properties' name needed to construct model
+            void initParameters();
+            // Set a list of properties' name needed to construct model
+            void initProperties();
+
+            // Clone and return a new instance
+            virtual DemuxTreeDeserializer* clone() const;
+
+        protected:
+            // Build the model
+            virtual void constructModel();
+            virtual void propagateTransitionInfo();
+
+    }; // class DemuxTreeDeserializer
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_ELECTRICAL_MULTIPHASEDESERIALIZER_H__
+
diff --git a/ext/dsent/model/electrical/MatrixArbiter.cc b/ext/dsent/model/electrical/MatrixArbiter.cc
new file mode 100644 (file)
index 0000000..7f72abd
--- /dev/null
@@ -0,0 +1,434 @@
+#include "model/electrical/MatrixArbiter.h"
+
+#include <cmath>
+#include <vector>
+
+#include "model/PortInfo.h"
+#include "model/EventInfo.h"
+#include "model/TransitionInfo.h"
+#include "model/ModelGen.h"
+#include "model/std_cells/StdCell.h"
+#include "model/std_cells/StdCellLib.h"
+
+namespace DSENT
+{
+    using std::abs;
+    using std::vector;
+
+    MatrixArbiter::MatrixArbiter(const String& instance_name_, const TechModel* tech_model_)
+        : ElectricalModel(instance_name_, tech_model_)
+    {
+        initParameters();
+        initProperties();
+    }
+
+    MatrixArbiter::~MatrixArbiter()
+    {}
+
+    void MatrixArbiter::initParameters()
+    {
+        addParameterName("NumberRequests");
+        return;
+    }
+
+    void MatrixArbiter::initProperties()
+    {
+        return;
+    }
+
+    MatrixArbiter* MatrixArbiter::clone() const
+    {
+        // TODO
+        return NULL;
+    }
+
+    void MatrixArbiter::constructModel()
+    {
+        // Get parameters
+        unsigned int number_requests = getParameter("NumberRequests").toUInt();
+
+        ASSERT(number_requests > 0, "[Error] " + getInstanceName() +
+                " -> Number of requests must be > 0!");
+
+        // Connect ports
+        createInputPort("CK");
+        for(unsigned int i = 0; i < number_requests; ++i)
+        {
+            createInputPort("Request" + (String)i);
+            createOutputPort("Grant" + (String)i);
+        }
+
+        // Create area, power, event results
+        createElectricalResults();
+        getEventInfo("Idle")->setStaticTransitionInfos();
+        getEventInfo("Idle")->setTransitionInfo("CK", TransitionInfo(0.0, 1.0, 0.0));
+//        for(unsigned int i = 0; i <= number_requests; ++i)
+//        {
+//            // Create arbitrate event with i requests
+//            createElectricalEventResult("Arbitrate" + (String)i);
+//            EventInfo* event_info = getEventInfo("Arbitrate" + (String)i);
+//            event_info->setTransitionInfo("CK", TransitionInfo(0.0, 1.0, 0.0));
+//
+//            for(unsigned int j = 0; j < i; ++j)
+//            {
+//                event_info->setTransitionInfo("Request" + (String)j, TransitionInfo(0.0, 0.0, 1.0));
+//            }
+//            for(unsigned int j = i; j < number_requests; ++j)
+//            {
+//                event_info->setTransitionInfo("Request" + (String)j, TransitionInfo(1.0, 0.0, 0.0));
+//            
+//            }
+//            //double P_0 = (double)(number_requests - i) / (double)(number_requests);
+//            //double P_1 = (double)(i) / (double)(number_requests);
+//            //TransitionInfo trans(P_0 * P_0, P_0 * P_1, P_1 * P_1);
+//
+//            //for(unsigned int j = 0; j < number_requests; ++j)
+//            //{
+//            //    event_info->setTransitionInfo("Request" + (String)j, trans);
+//            //}
+//        }
+        createElectricalEventResult("Arbitrate");
+        getEventInfo("Arbitrate")->setTransitionInfo("CK", TransitionInfo(0.0, 1.0, 0.0));
+        for(unsigned int i = 0; i < number_requests; ++i)
+        {
+            getEventInfo("Arbitrate")->setTransitionInfo("Request" + (String)i, TransitionInfo(0.25, 0.25, 0.25));
+        }
+
+        if(number_requests == 1)
+        {
+            assign("Grant0", "Request0");
+        }
+        else
+        {
+            // Init components
+            vector<String> g_inv_names(number_requests, "");
+            vector<StdCell*> g_invs(number_requests, NULL);
+            vector<String> g_and2_names(number_requests, "");
+            vector<StdCell*> g_and2s(number_requests, NULL);
+            for(unsigned int i = 0; i < number_requests; ++i)
+            {
+                g_inv_names[i] = "G_INV" + (String)i;
+                g_and2_names[i] = "G_AND2" + (String)i;
+                g_invs[i] = getTechModel()->getStdCellLib()->createStdCell("INV", g_inv_names[i]);
+                g_invs[i]->construct();
+                g_and2s[i] = getTechModel()->getStdCellLib()->createStdCell("AND2", g_and2_names[i]);
+                g_and2s[i]->construct();
+            }
+
+            unsigned int number_states = (number_requests - 1) * number_requests / 2;
+
+            vector<String> w_or2_names(number_states, "");
+            vector<StdCell*> w_or2s(number_states, NULL);
+            vector<String> w_and2_names(number_states, "");
+            vector<StdCell*> w_and2s(number_states, NULL);
+            vector<String> w_inv_names(number_states, "");
+            vector<StdCell*> w_invs(number_states, NULL);
+            vector<String> w_dff_names(number_states, "");
+            vector<StdCell*> w_dffs(number_states, NULL);
+            vector<String> dis_and2_names(number_states * 2, "");
+            vector<StdCell*> dis_and2s(number_states * 2, NULL);
+            vector<String> dis_inv_names(number_states, "");
+            vector<StdCell*> dis_invs(number_states, NULL);
+            unsigned int state_count = 0;
+            for(unsigned int i = 0; i < number_requests; ++i)
+            {
+                for(unsigned int j = i + 1; j < number_requests; ++j)
+                {
+                    w_or2_names[state_count] = String::format("W_OR2_%d_%d", i, j);
+                    w_and2_names[state_count] = String::format("W_AND2_%d_%d", i, j);
+                    w_inv_names[state_count] = String::format("W_INV_%d_%d", i, j);
+                    w_dff_names[state_count] = String::format("W_DFF_%d_%d", i, j);
+                    w_or2s[state_count] = getTechModel()->getStdCellLib()->createStdCell("OR2", w_or2_names[state_count]);
+                    w_or2s[state_count]->construct();
+                    w_and2s[state_count] = getTechModel()->getStdCellLib()->createStdCell("AND2", w_and2_names[state_count]);
+                    w_and2s[state_count]->construct();
+                    w_invs[state_count] = getTechModel()->getStdCellLib()->createStdCell("INV", w_inv_names[state_count]);
+                    w_invs[state_count]->construct();
+                    w_dffs[state_count] = getTechModel()->getStdCellLib()->createStdCell("DFFQ", w_dff_names[state_count]);
+                    w_dffs[state_count]->construct();
+
+                    dis_inv_names[state_count] = String::format("Dis_INV_%d_%d", i, j);
+                    dis_and2_names[state_count] = String::format("Dis_AND2_%d_%d", i, j);
+                    dis_and2_names[state_count + number_states] = String::format("Dis_AND2_%d_%d", j, i);
+                    dis_invs[state_count] = getTechModel()->getStdCellLib()->createStdCell("INV", dis_inv_names[state_count]);
+                    dis_invs[state_count]->construct();
+                    dis_and2s[state_count] = getTechModel()->getStdCellLib()->createStdCell("AND2", dis_and2_names[state_count]);
+                    dis_and2s[state_count]->construct();
+                    dis_and2s[state_count + number_states] = getTechModel()->getStdCellLib()->createStdCell("AND2", dis_and2_names[state_count + number_states]);
+                    dis_and2s[state_count + number_states]->construct();
+                    state_count++;
+                }
+            }
+
+            vector<String> dis_or_names(number_requests, "");
+            vector<ElectricalModel*> dis_ors(number_requests, NULL);
+            for(unsigned int i = 0; i < number_requests; ++i)
+            {
+                dis_or_names[i] = "Dis_OR" + (String)i;
+                dis_ors[i] = (ElectricalModel*)ModelGen::createModel("OR", dis_or_names[i], getTechModel());
+                dis_ors[i]->setParameter("NumberInputs", number_requests-1);
+                dis_ors[i]->setParameter("NumberBits", 1);
+                dis_ors[i]->construct();
+            }
+
+            state_count = 0;
+            for(unsigned int i = 0; i < number_requests; ++i)
+            {
+                createNet("Dis_OR_Out" + (String)i);
+                createNet("G_INV_Out" + (String)i);
+                portConnect(g_invs[i], "A", "Dis_OR_Out" + (String)i);
+                portConnect(g_invs[i], "Y", "G_INV_Out" + (String)i);
+                portConnect(g_and2s[i], "A", "Request" + (String)i);
+                portConnect(g_and2s[i], "B", "G_INV_Out" + (String)i);
+                portConnect(g_and2s[i], "Y", "Grant" + (String)i);
+
+                for(unsigned int j = i + 1; j < number_requests; ++j)
+                {
+                    createNet(String::format("W_INV_Out_%d_%d", i, j));
+                    createNet(String::format("W_OR2_Out_%d_%d", i, j));
+                    createNet(String::format("W_AND2_Out_%d_%d", i, j));
+                    createNet(String::format("W_DFF_Out_%d_%d", i, j));
+                    portConnect(w_invs[state_count], "A", "Grant" + (String)i);
+                    portConnect(w_invs[state_count], "Y", String::format("W_INV_Out_%d_%d", i, j));
+                    portConnect(w_or2s[state_count], "A", String::format("W_DFF_Out_%d_%d", i, j));
+                    portConnect(w_or2s[state_count], "B", "Grant" + (String)j);
+                    portConnect(w_or2s[state_count], "Y", String::format("W_OR2_Out_%d_%d", i, j));
+                    portConnect(w_and2s[state_count], "A", String::format("W_OR2_Out_%d_%d", i, j));
+                    portConnect(w_and2s[state_count], "B", String::format("W_INV_Out_%d_%d", i, j));
+                    portConnect(w_and2s[state_count], "Y", String::format("W_AND2_Out_%d_%d", i, j));
+                    portConnect(w_dffs[state_count], "D", String::format("W_AND2_Out_%d_%d", i, j));
+                    portConnect(w_dffs[state_count], "CK", "CK");
+                    portConnect(w_dffs[state_count], "Q", String::format("W_DFF_Out_%d_%d", i, j));
+
+                    createNet(String::format("Dis_AND2_Out_%d_%d", i, j));
+                    createNet(String::format("Dis_AND2_Out_%d_%d", j, i));
+                    createNet(String::format("Dis_INV_Out_%d_%d", j, i));
+                    portConnect(dis_and2s[state_count], "A", "Request" + (String)i);
+                    portConnect(dis_and2s[state_count], "B", String::format("W_DFF_Out_%d_%d", i, j));
+                    portConnect(dis_and2s[state_count], "Y", String::format("Dis_AND2_Out_%d_%d", i, j));
+
+                    portConnect(dis_invs[state_count], "A", String::format("W_DFF_Out_%d_%d", i, j));
+                    portConnect(dis_invs[state_count], "Y", String::format("Dis_INV_Out_%d_%d", j, i));
+                    portConnect(dis_and2s[state_count + number_states], "A", "Request" + (String)j);
+                    portConnect(dis_and2s[state_count + number_states], "B", String::format("Dis_INV_Out_%d_%d", j, i));
+                    portConnect(dis_and2s[state_count + number_states], "Y", String::format("Dis_AND2_Out_%d_%d", j, i));
+
+                    state_count++;
+                }
+            }
+            for(unsigned int i = 0; i < number_requests; ++i)
+            {
+                unsigned int k = 0;
+                for(unsigned int j = 0; j < number_requests; ++j)
+                {
+                    if(i != j)
+                    {
+                        portConnect(dis_ors[i], "In" + (String)k, String::format("Dis_AND2_Out_%d_%d", j, i));
+                        k++;
+                    }
+                }
+                portConnect(dis_ors[i], "Out", "Dis_OR_Out" + (String)i);
+            }
+
+            // Add instances
+            for(unsigned int i = 0; i < number_requests; ++i)
+            {
+                addSubInstances(g_invs[i], 1.0);
+                addElectricalSubResults(g_invs[i], 1.0);
+                addSubInstances(g_and2s[i], 1.0);
+                addElectricalSubResults(g_and2s[i], 1.0);
+                addSubInstances(dis_ors[i], 1.0);
+                addElectricalSubResults(dis_ors[i], 1.0);
+            }
+            for(unsigned int i = 0; i < number_states; ++i)
+            {
+                addSubInstances(w_or2s[i], 1.0);
+                addElectricalSubResults(w_or2s[i], 1.0);
+                addSubInstances(w_and2s[i], 1.0);
+                addElectricalSubResults(w_and2s[i], 1.0);
+                addSubInstances(w_invs[i], 1.0);
+                addElectricalSubResults(w_invs[i], 1.0);
+                addSubInstances(w_dffs[i], 1.0);
+                addElectricalSubResults(w_dffs[i], 1.0);
+                addSubInstances(dis_and2s[i], 1.0);
+                addElectricalSubResults(dis_and2s[i], 1.0);
+                addSubInstances(dis_and2s[i + number_states], 1.0);
+                addElectricalSubResults(dis_and2s[i + number_states], 1.0);
+                addSubInstances(dis_invs[i], 1.0);
+                addElectricalSubResults(dis_invs[i], 1.0);
+            }
+
+            // Update event
+            //for(unsigned int i = 0; i <= number_requests; ++i)
+            //{
+            //Result* arb_event = getEventResult("Arbitrate" + (String)i);
+            Result* arb_event = getEventResult("Arbitrate");
+            for(unsigned int j = 0; j < number_requests; ++j)
+            {
+                arb_event->addSubResult(g_invs[j]->getEventResult("INV"), g_inv_names[j], 1.0);
+                arb_event->addSubResult(g_and2s[j]->getEventResult("AND2"), g_and2_names[j], 1.0);
+                arb_event->addSubResult(dis_ors[j]->getEventResult("OR"), dis_or_names[j], 1.0);
+            }
+            for(unsigned int j = 0; j < number_states; ++j)
+            {
+                arb_event->addSubResult(w_or2s[j]->getEventResult("OR2"), w_or2_names[j], 1.0);
+                arb_event->addSubResult(w_and2s[j]->getEventResult("AND2"), w_and2_names[j], 1.0);
+                arb_event->addSubResult(w_invs[j]->getEventResult("INV"), w_inv_names[j], 1.0);
+                arb_event->addSubResult(w_dffs[j]->getEventResult("DFFD"), w_dff_names[j], 1.0);
+                arb_event->addSubResult(w_dffs[j]->getEventResult("DFFQ"), w_dff_names[j], 1.0);
+                arb_event->addSubResult(w_dffs[j]->getEventResult("CK"), w_dff_names[j], 1.0);
+                arb_event->addSubResult(dis_and2s[j]->getEventResult("AND2"), dis_and2_names[j], 1.0);
+                arb_event->addSubResult(dis_and2s[j + number_states]->getEventResult("AND2"), dis_and2_names[j + number_states], 1.0);
+                arb_event->addSubResult(dis_invs[j]->getEventResult("INV"), dis_inv_names[j], 1.0);
+            }
+            //}
+        }
+        return;
+    }
+
+    void MatrixArbiter::propagateTransitionInfo()
+    {
+        // Get parameters
+        unsigned int number_requests = getParameter("NumberRequests").toUInt();
+
+        if(number_requests == 1)
+        {
+            propagatePortTransitionInfo("Grant0", "Request0");
+        }
+        else
+        {
+            unsigned int number_states = (number_requests - 1) * number_requests / 2;
+
+            vector<ElectricalModel*> g_and2s(number_requests, NULL);
+            vector<ElectricalModel*> g_invs(number_requests, NULL);
+            vector<ElectricalModel*> w_invs(number_states, NULL);
+            vector<ElectricalModel*> w_or2s(number_states, NULL);
+            vector<ElectricalModel*> w_and2s(number_states, NULL);
+            vector<ElectricalModel*> w_dffs(number_states, NULL);
+            vector<ElectricalModel*> dis_invs(number_states, NULL);
+            vector<ElectricalModel*> dis_and2s(number_requests * number_requests, NULL);
+            vector<ElectricalModel*> dis_ors(number_requests, NULL);
+            for(unsigned int i = 0; i < number_requests; ++i)
+            {
+                g_and2s[i] = (ElectricalModel*)getSubInstance("G_AND2" + (String)i);
+                g_invs[i] = (ElectricalModel*)getSubInstance("G_INV" + (String)i);
+                dis_ors[i] = (ElectricalModel*)getSubInstance("Dis_OR" + (String)i);
+            }
+            unsigned int state_count = 0;
+            for(unsigned int i = 0; i < number_requests; ++i)
+            {
+                for(unsigned int j = i + 1; j < number_requests; ++j)
+                {
+                    w_invs[state_count] = (ElectricalModel*)getSubInstance(String::format("W_INV_%d_%d", i, j));
+                    w_or2s[state_count] = (ElectricalModel*)getSubInstance(String::format("W_OR2_%d_%d", i, j));
+                    w_and2s[state_count] = (ElectricalModel*)getSubInstance(String::format("W_AND2_%d_%d", i, j));
+                    w_dffs[state_count] = (ElectricalModel*)getSubInstance(String::format("W_DFF_%d_%d", i, j));
+                    dis_invs[state_count] = (ElectricalModel*)getSubInstance(String::format("Dis_INV_%d_%d", i, j));
+                    dis_and2s[i * number_requests + j] = (ElectricalModel*)getSubInstance(String::format("Dis_AND2_%d_%d", i, j));
+                    dis_and2s[j * number_requests + i] = (ElectricalModel*)getSubInstance(String::format("Dis_AND2_%d_%d", j, i));
+
+                    w_dffs[state_count]->getInputPort("D")->setTransitionInfo(TransitionInfo(0.5, 0.0, 0.5));
+                    propagatePortTransitionInfo(w_dffs[state_count], "CK", "CK");
+                    w_dffs[state_count]->use();
+
+                    state_count++;
+                }
+            }
+
+            unsigned int iteration = 1;
+            unsigned int max_number_iterations = 10;
+            //vector<TransitionInfo> trans_vector(number_states, TransitionInfo(0.0, 0.0, 1.0));
+            //vector<double> total_P_vector(number_states, 0.0);
+            while(iteration < max_number_iterations)
+            {
+//                for(unsigned int i = 0; i < number_states; ++i)
+//                {
+//                    w_dffs[i]->getInputPort("D")->setTransitionInfo(trans_vector[i]);
+//                    propagatePortTransitionInfo(w_dffs[i], "CK", "CK");
+//                    w_dffs[i]->use();
+//                }
+                state_count = 0;
+                for(unsigned int i = 0; i < number_requests; ++i)
+                {
+                    for(unsigned int j = i + 1; j < number_requests; ++j)
+                    {
+                        propagatePortTransitionInfo(dis_and2s[i * number_requests + j], "A", "Request" + (String)i);
+                        propagatePortTransitionInfo(dis_and2s[i * number_requests + j], "B", w_dffs[state_count], "Q");
+                        dis_and2s[i * number_requests + j]->use();
+                        propagatePortTransitionInfo(dis_invs[state_count], "A", w_dffs[state_count], "Q");
+                        dis_invs[state_count]->use();
+                        propagatePortTransitionInfo(dis_and2s[j * number_requests + i], "A", "Request" + (String)j);
+                        propagatePortTransitionInfo(dis_and2s[j * number_requests + i], "B", dis_invs[state_count], "Y");
+                        dis_and2s[j * number_requests + i]->use();
+
+                        state_count++;
+                    }
+                }
+                for(unsigned int i = 0; i < number_requests; ++i)
+                {
+                    unsigned int k = 0;
+                    for(unsigned int j = 0; j < number_requests; ++j)
+                    {
+                        if(i != j)
+                        {
+                            propagatePortTransitionInfo(dis_ors[i], "In" + (String)k, dis_and2s[j * number_requests + i], "Y");
+                            k++;
+                        }
+                    }
+                    dis_ors[i]->use();
+                }
+                for(unsigned int i = 0; i < number_requests; ++i)
+                {
+                    propagatePortTransitionInfo(g_invs[i], "A", dis_ors[i], "Out");
+                    g_invs[i]->use();
+                    propagatePortTransitionInfo(g_and2s[i], "A", "Request" + (String)i);
+                    propagatePortTransitionInfo(g_and2s[i], "B", g_invs[i], "Y");
+                    g_and2s[i]->use();
+                }
+                state_count = 0;
+                for(unsigned int i = 0; i < number_requests; ++i)
+                {
+                    for(unsigned int j = i + 1; j < number_requests; ++j)
+                    {
+                        propagatePortTransitionInfo(w_invs[state_count], "A", g_and2s[i], "Y");
+                        w_invs[state_count]->use();
+                        propagatePortTransitionInfo(w_or2s[state_count], "A", w_dffs[state_count], "Q");
+                        propagatePortTransitionInfo(w_or2s[state_count], "B", g_and2s[j], "Y");
+                        w_or2s[state_count]->use();
+                        propagatePortTransitionInfo(w_and2s[state_count], "A", w_or2s[state_count], "Y");
+                        propagatePortTransitionInfo(w_and2s[state_count], "B", w_invs[state_count], "Y");
+                        w_and2s[state_count]->use();
+                        propagatePortTransitionInfo(w_dffs[state_count], "D", w_and2s[state_count], "Y");
+                        propagatePortTransitionInfo(w_dffs[state_count], "CK", "CK");
+                        w_dffs[state_count]->use();
+                        state_count++;
+                    }
+                }
+
+//                for(unsigned int i = 0; i < number_states; ++i)
+//                {
+//                    const TransitionInfo& new_trans = w_dffs[i]->getOutputPort("Q")->getTransitionInfo();
+//                    total_P_vector[i] += new_trans.getProbability1();
+//                    trans_vector[i] = TransitionInfo((1.0 - total_P_vector[i] / iteration) * (1.0 - total_P_vector[i] / iteration), 
+//                            (1.0 - total_P_vector[i] / iteration) * (total_P_vector[i] / iteration), 
+//                            (total_P_vector[i] / iteration) * (total_P_vector[i] / iteration));
+//                }
+//
+//                for(unsigned int i = 0; i < number_requests; ++i)
+//                {
+//                    g_and2s[i]->getOutputPort("Y")->getTransitionInfo().print(cout);
+//                }
+//                cout << endl;
+                iteration++;
+            }
+
+            for(unsigned int i = 0; i < number_requests; ++i)
+            {
+                propagatePortTransitionInfo("Grant" + (String)i, g_and2s[i], "Y");
+            }
+        }
+
+        return;
+    }
+} // namespace DSENT
+
diff --git a/ext/dsent/model/electrical/MatrixArbiter.h b/ext/dsent/model/electrical/MatrixArbiter.h
new file mode 100644 (file)
index 0000000..59a6786
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef __DSENT_MODEL_ELECTRICAL_MATRIX_ARBITER_H__
+#define __DSENT_MODEL_ELECTRICAL_MATRIX_ARBITER_H__
+
+#include "util/CommonType.h"
+#include "model/ElectricalModel.h"
+
+namespace DSENT
+{
+    class MatrixArbiter : public ElectricalModel
+    {
+        public:
+            MatrixArbiter(const String& instance_name_, const TechModel* tech_model_);
+            virtual ~MatrixArbiter();
+
+        public:
+            // Set a list of properties' name needed to construct model
+            void initParameters();
+            // Set a list of properties' name needed to construct model
+            void initProperties();
+
+            // Clone and return a new instance
+            virtual MatrixArbiter* clone() const;
+
+        protected:
+            // Build the model
+            virtual void constructModel();
+            virtual void propagateTransitionInfo();
+
+    }; // class MatrixArbiter
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_ELECTRICAL_MATRIX_ARBITER_H__
+
diff --git a/ext/dsent/model/electrical/Multiplexer.cc b/ext/dsent/model/electrical/Multiplexer.cc
new file mode 100644 (file)
index 0000000..f51f43b
--- /dev/null
@@ -0,0 +1,347 @@
+#include "model/electrical/Multiplexer.h"
+
+#include <cmath>
+
+#include "model/PortInfo.h"
+#include "model/TransitionInfo.h"
+#include "model/EventInfo.h"
+#include "model/timing_graph/ElectricalDriverMultiplier.h"
+#include "model/timing_graph/ElectricalNet.h"
+#include "model/std_cells/StdCell.h"
+#include "model/std_cells/StdCellLib.h"
+
+namespace DSENT
+{
+    Multiplexer::Multiplexer(const String& instance_name_, const TechModel* tech_model_)
+        : ElectricalModel(instance_name_, tech_model_)
+    {
+        initParameters();
+        initProperties();
+    }
+
+    Multiplexer::~Multiplexer()
+    {}
+
+    void Multiplexer::initParameters()
+    {
+        addParameterName("NumberInputs");
+        addParameterName("NumberBits");
+        addParameterName("BitDuplicate", "TRUE");
+        addParameterName("IsTopLevel", "TRUE");
+        return;
+    }
+
+    void Multiplexer::initProperties()
+    {
+        return;
+    }
+
+    Multiplexer* Multiplexer::clone() const
+    {
+        return NULL;
+    }
+
+    void Multiplexer::constructModel()
+    {
+        // Get parameters
+        unsigned int number_bits = (unsigned int) getParameter("NumberBits");
+        unsigned int number_inputs = (unsigned int) getParameter("NumberInputs");
+        unsigned int number_selects = (unsigned int) ceil(log2((double) number_inputs));
+        bool bit_duplicate = (bool) getParameter("BitDuplicate");
+        bool is_top_level = getParameter("IsTopLevel").toBool();
+        
+        ASSERT(number_inputs > 0, "[Error] " + getInstanceName() + " -> Number of inputs must be > 0!");
+        ASSERT(number_bits > 0, "[Error] " + getInstanceName() + " -> Number of bits must be > 0!");
+    
+        //Construct electrical ports and nets
+        //Create each input port
+        for(unsigned int i = 0; i < number_inputs; ++i)
+            createInputPort(    "In" + (String) i, makeNetIndex(0, number_bits-1));
+        //Create select signals
+        for(unsigned int i = 0; i < number_selects; ++i)
+        {
+            createInputPort(    "Sel" + (String)i);
+        }
+        //Create output
+        createOutputPort(   "Out", makeNetIndex(0, number_bits-1));
+        
+        //Create energy, power, and area results
+        createElectricalResults();
+        getEventInfo("Idle")->setStaticTransitionInfos();
+        createElectricalEventResult("Mux");
+                    
+        //Number of inputs on the 0 side
+        unsigned int inputs_0 = (unsigned int) ceil((double) number_inputs / 2.0);
+        unsigned int selects_0 = (unsigned int) ceil(log2((double) inputs_0));
+        //Number of inputs on the 1 side
+        unsigned int inputs_1 = (unsigned int) floor((double) number_inputs / 2.0);
+        unsigned int selects_1 = (unsigned int) ceil(log2((double) inputs_1));
+        
+        //Depending on whether we want to create a 1-bit instance and have it multiplied
+        //up by number of bits or actually instantiate number_bits of 1-bit instances.
+        //Recursively instantiates smaller multiplexers
+        if (bit_duplicate || number_bits == 1)
+        {
+            //If it is just a 1-input multiplexer, just connect output to input and be done
+            if (number_inputs == 1)
+            {
+                assign("Out", "In0");
+            }
+            else
+            {
+                //If it is more than 1 input, instantiate two sub multiplexers (Mux_way0 and Mux_way1)
+                //and create a final 2:1 mux (muxf) to select between them
+                String mux0_name = "Mux_way0";
+                String mux1_name = "Mux_way1";
+                String muxf_name = "Mux2_i" + (String)number_inputs;
+
+                Multiplexer* mux0 = new Multiplexer(mux0_name, getTechModel());
+                mux0->setParameter("NumberInputs", inputs_0);
+                mux0->setParameter("NumberBits", 1);
+                mux0->setParameter("BitDuplicate", "TRUE");
+                mux0->setParameter("IsTopLevel", "FALSE");
+                mux0->construct();
+            
+                Multiplexer* mux1 = new Multiplexer(mux1_name, getTechModel());
+                mux1->setParameter("NumberInputs", inputs_1);
+                mux1->setParameter("NumberBits", 1);
+                mux1->setParameter("BitDuplicate", "TRUE");                                    
+                mux1->setParameter("IsTopLevel", "FALSE");
+                mux1->construct();
+                
+                StdCell* muxf = getTechModel()->getStdCellLib()->createStdCell("MUX2", muxf_name);
+                muxf->construct();
+
+                // TODO hack 
+                // create selector driver at the top level
+                if(is_top_level)
+                {
+                    for(unsigned int i = 0; i < number_selects; ++i)
+                    {
+                        StdCell* selinv0 = getTechModel()->getStdCellLib()->createStdCell("INV", String::format("Sel%dInv0", i));
+                        StdCell* selinv1 = getTechModel()->getStdCellLib()->createStdCell("INV", String::format("Sel%dInv1", i));
+                        selinv0->construct();
+                        selinv1->construct();
+
+                        addSubInstances(selinv0, 1.0);
+                        addElectricalSubResults(selinv0, 1.0);
+                        addSubInstances(selinv1, 1.0);
+                        addElectricalSubResults(selinv1, 1.0);
+                        getEventResult("Mux")->addSubResult(selinv0->getEventResult("INV"), String::format("Sel%dInv0", i), 1.0);                
+                        getEventResult("Mux")->addSubResult(selinv1->getEventResult("INV"), String::format("Sel%dInv1", i), 1.0);                
+                    }
+                }
+
+                //Create outputs of way0 and way1 multiplexers with final mux
+                createNet("way0Out");
+                createNet("way1Out");
+                portConnect(mux0, "Out", "way0Out");
+                portConnect(mux1, "Out", "way1Out");
+                portConnect(muxf, "A", "way0Out");
+                portConnect(muxf, "B", "way1Out");
+
+                // TODO hack 
+                // Connect selector bits
+                if(is_top_level)
+                {
+                    for(unsigned int i = 0; i < number_selects; ++i)
+                    {
+                        ElectricalModel* selinv0 = (ElectricalModel*)getSubInstance(String::format("Sel%dInv0", i));
+                        ElectricalModel* selinv1 = (ElectricalModel*)getSubInstance(String::format("Sel%dInv1", i));
+                        createNet("SelInv" + (String)i);
+                        createNet("SelBuf" + (String)i);
+                        portConnect(selinv0, "A", "Sel" + (String)i);
+                        portConnect(selinv0, "Y", "SelInv" + (String)i);
+                        portConnect(selinv1, "A", "SelInv" + (String)i);
+                        portConnect(selinv1, "Y", "SelBuf" + (String)i);
+                    }
+                }
+                //Connect inputs to the sub multiplexers.
+                //Note that multiple inputs are connected to the mux0 and mux1 input and the
+                //selector signals are connected multiple times. This is just so that everything
+                //is loaded appropriately since bit duplication is applied
+                for (unsigned int n = 0; n < number_bits; ++n)
+                {
+                    //Connect inputs
+                    for (unsigned int i = 0; i < inputs_0; ++i)
+                        portConnect(mux0, "In" + (String) i, "In" + (String) i, makeNetIndex(n));
+                    for (unsigned int i = 0; i < inputs_1; ++i)
+                        portConnect(mux1, "In" + (String) i, "In" + (String) (i + inputs_0), makeNetIndex(n));                    
+                    // TODO hack 
+                    if(is_top_level)
+                    {
+                        //Connect selector bits
+                        for (unsigned int i = 0; i < selects_0; ++i)
+                            portConnect(mux0, "Sel" + (String)i, "SelBuf" + (String)i);
+                        for (unsigned int i = 0; i < selects_1; ++i)
+                            portConnect(mux1, "Sel" + (String)i, "SelBuf" + (String)i);
+                        portConnect(muxf, "S0", "SelBuf" + (String)(number_selects - 1));
+                    }
+                    else
+                    {
+                        //Connect selector bits
+                        for (unsigned int i = 0; i < selects_0; ++i)
+                            portConnect(mux0, "Sel" + (String)i, "Sel" + (String)i);
+                        for (unsigned int i = 0; i < selects_1; ++i)
+                            portConnect(mux1, "Sel" + (String)i, "Sel" + (String)i);
+                        portConnect(muxf, "S0", "Sel" + (String)(number_selects - 1));
+                    }
+                }
+
+                //Connect final mux to outputs
+                //Because we use bit duplication and so there is only only one multiplexer
+                //instance, we must use driver multiplier to drive each output appropriately
+                if (number_bits == 1)
+                    portConnect(muxf, "Y", "Out");
+                else
+                {
+                    createNet("OutTemp");
+                    createDriverMultiplier("OutMult");
+                    ElectricalDriverMultiplier* drive_mult = getDriverMultiplier("OutMult");
+                    portConnect(muxf, "Y", "OutTemp");
+                    getNet("OutTemp")->addDownstreamNode(drive_mult);
+                    for (unsigned int n = 0; n < number_bits; ++n)
+                        drive_mult->addDownstreamNode(getNet("Out", makeNetIndex(n)));
+                }
+
+                //Add area, power, and event results for each mux
+                addSubInstances(mux0, number_bits);
+                addElectricalSubResults(mux0, number_bits);
+                addSubInstances(mux1, number_bits);
+                addElectricalSubResults(mux1, number_bits);
+                addSubInstances(muxf, number_bits);
+                addElectricalSubResults(muxf, number_bits);
+                getEventResult("Mux")->addSubResult(mux0->getEventResult("Mux"), mux0_name, number_bits);                
+                getEventResult("Mux")->addSubResult(mux1->getEventResult("Mux"), mux1_name, number_bits);                
+                getEventResult("Mux")->addSubResult(muxf->getEventResult("MUX2"), muxf_name, number_bits);                
+
+            }
+
+        }
+        else
+        {
+            //Instantiate a bunch of 1-bit multiplexers
+            for (unsigned int n = 0; n < number_bits; ++n)
+            {
+                String mux_name = "Mux_bit" + (String) n;
+
+                Multiplexer* mux = new Multiplexer(mux_name, getTechModel());
+                mux->setParameter("NumberInputs", number_inputs);
+                mux->setParameter("NumberBits", 1);
+                mux->setParameter("BitDuplicate", "TRUE");            
+                mux->construct();
+
+                // Connect inputs
+                for (unsigned int i = 0; i < number_inputs; ++i)
+                    portConnect(mux, "In" + (String) i, "In" + (String) i, makeNetIndex(n));
+                for(unsigned int i = 0; i < number_selects; ++i)
+                    portConnect(mux, "Sel" + (String)i, "Sel" + (String)i);
+                portConnect(mux, "Out", "Out", makeNetIndex(n));
+
+                //Add area, power, and event results for each mux
+                addSubInstances(mux, 1.0);
+                addElectricalSubResults(mux, 1.0);
+                getEventResult("Mux")->addSubResult(mux->getEventResult("Mux"), mux_name, 1.0);
+            }
+        }
+
+        return;
+    }
+
+    void Multiplexer::propagateTransitionInfo()
+    {
+        // The only thing can be updated are the input probabilities...so we will update them
+        unsigned int number_bits = (unsigned int) getParameter("NumberBits");
+        unsigned int number_inputs = (unsigned int) getParameter("NumberInputs");
+        unsigned int number_selects = (unsigned int) ceil(log2((double) number_inputs));
+        bool bit_duplicate = (bool) getParameter("BitDuplicate");
+        bool is_top_level = getParameter("IsTopLevel").toBool();
+
+        //Number of inputs on the 0 side
+        unsigned int inputs_0 = (unsigned int) ceil((double) number_inputs / 2.0);
+        unsigned int selects_0 = (unsigned int) ceil(log2((double) inputs_0));
+
+        //Number of inputs on the 1 side
+        unsigned int inputs_1 = (unsigned int) floor((double) number_inputs / 2.0);
+        unsigned int selects_1 = (unsigned int) ceil(log2((double) inputs_1));
+
+        if (bit_duplicate || number_bits == 1)
+        {
+            if (number_inputs == 1)
+            {
+                //If theres only 1 input, output transition = input transition
+                propagatePortTransitionInfo("Out", "In0");
+            }
+            else
+            { 
+                // Update sub muxes with appropriate probabilities
+                ElectricalModel* mux0 = (ElectricalModel*)getSubInstance("Mux_way0");
+                for(unsigned int i = 0; i < inputs_0; ++i)
+                {
+                    propagatePortTransitionInfo(mux0, "In" + (String)i, "In" + (String)i);
+                }
+                for(unsigned int i = 0; i < selects_0; ++i)
+                {
+                    propagatePortTransitionInfo(mux0, "Sel" + (String)i, "Sel" + (String)i);
+                }
+                mux0->use();                
+                ElectricalModel* mux1 = (ElectricalModel*)getSubInstance("Mux_way1");
+                for(unsigned int i = 0; i < inputs_1; ++i)
+                {
+                    propagatePortTransitionInfo(mux1, "In" + (String)i, "In" + (String)(i + inputs_0));
+                }
+                for(unsigned int i = 0; i < selects_1; ++i)
+                {
+                    propagatePortTransitionInfo(mux1, "Sel" + (String)i, "Sel" + (String)i);
+                }
+                mux1->use();                
+                ElectricalModel* muxf = (ElectricalModel*)getSubInstance("Mux2_i" + (String)number_inputs);
+                propagatePortTransitionInfo(muxf, "A", mux0, "Out");
+                propagatePortTransitionInfo(muxf, "B", mux1, "Out");
+                propagatePortTransitionInfo(muxf, "S0", "Sel" + (String)(number_selects-1));
+                muxf->use();
+
+                // TODO hack
+                if(is_top_level)
+                {
+                    for(unsigned int i = 0; i < number_selects; ++i)
+                    {
+                        ElectricalModel* selinv0 = (ElectricalModel*)getSubInstance(String::format("Sel%dInv0", i));
+                        ElectricalModel* selinv1 = (ElectricalModel*)getSubInstance(String::format("Sel%dInv1", i));
+                        propagatePortTransitionInfo(selinv0, "A", "Sel" + (String)i);
+                        selinv0->use();
+                        propagatePortTransitionInfo(selinv1, "A", selinv0, "Y");
+                        selinv1->use();
+                    }
+                }
+
+                // Set output transition
+                propagatePortTransitionInfo("Out", muxf, "Y");
+            }
+        }
+        else
+        {
+            // Go through each bit and set the appropriate probability
+            for (unsigned int n = 0; n < number_bits; ++n)
+            {
+                ElectricalModel* mux_bit = (ElectricalModel*)getSubInstance("Mux_bit" + (String) n);
+                for(unsigned int i = 0; i < number_inputs; ++i)
+                {
+                    propagatePortTransitionInfo(mux_bit, "In" + (String)i, "In" + (String)i);
+                }
+                for(unsigned int i = 0; i < number_selects; ++i)
+                {
+                    propagatePortTransitionInfo(mux_bit, "Sel" + (String)i, "Sel" + (String)i);
+                }
+                mux_bit->use();
+            }            
+
+            // Set output probability to be average that of probabilties of each output bit
+            ElectricalModel* mux_bit = (ElectricalModel*)getSubInstance("Mux_bit0");
+            propagatePortTransitionInfo("Out", mux_bit, "Out");
+        }        
+        return;
+    }
+
+} // namespace DSENT
+
diff --git a/ext/dsent/model/electrical/Multiplexer.h b/ext/dsent/model/electrical/Multiplexer.h
new file mode 100644 (file)
index 0000000..845798b
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef __DSENT_MODEL_ELECTRICAL_MULTIPLEXER_H__
+#define __DSENT_MODEL_ELECTRICAL_MULTIPLEXER_H__
+
+#include "util/CommonType.h"
+#include "model/ElectricalModel.h"
+
+namespace DSENT
+{
+    // A model of an N-to-1 multiplexer
+    class Multiplexer : public ElectricalModel
+    {
+        public:
+            Multiplexer(const String& instance_name_, const TechModel* tech_model_);
+            virtual ~Multiplexer();
+
+        public:
+            // Set a list of properties' name needed to construct model
+            void initParameters();
+            // Set a list of properties' name needed to construct model
+            void initProperties();
+
+            // Clone and return a new instance
+            virtual Multiplexer* clone() const;
+
+        protected:
+            // Build the model
+            virtual void constructModel();
+            virtual void propagateTransitionInfo();
+
+    }; // class Multiplexer
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_ELECTRICAL_MULTIPLEXER_H__
+
diff --git a/ext/dsent/model/electrical/MultiplexerCrossbar.cc b/ext/dsent/model/electrical/MultiplexerCrossbar.cc
new file mode 100644 (file)
index 0000000..7400d5e
--- /dev/null
@@ -0,0 +1,214 @@
+#include "model/electrical/MultiplexerCrossbar.h"
+
+#include <vector>
+#include <cmath>
+
+#include "model/PortInfo.h"
+#include "model/EventInfo.h"
+#include "model/TransitionInfo.h"
+#include "model/timing_graph/ElectricalNet.h"
+#include "model/electrical/Multiplexer.h"
+
+namespace DSENT
+{
+    using std::ceil;
+    using std::vector;
+
+    MultiplexerCrossbar::MultiplexerCrossbar(const String& instance_name_, const TechModel* tech_model_)
+        : ElectricalModel(instance_name_, tech_model_)
+    {
+        initParameters();
+        initProperties();
+    }
+
+    MultiplexerCrossbar::~MultiplexerCrossbar()
+    {}
+
+    void MultiplexerCrossbar::initParameters()
+    {
+        addParameterName("NumberInputs");
+        addParameterName("NumberOutputs");
+        addParameterName("NumberBits");
+        addParameterName("BitDuplicate", "TRUE");
+        return;
+    }
+
+    void MultiplexerCrossbar::initProperties()
+    {
+        return;
+    }
+
+    MultiplexerCrossbar* MultiplexerCrossbar::clone() const
+    {
+        // TODO
+        return NULL;
+    }
+
+    void MultiplexerCrossbar::constructModel()
+    {
+        // Get Parameters
+        unsigned int number_inputs = getParameter("NumberInputs").toUInt();
+        unsigned int number_outputs = getParameter("NumberOutputs").toUInt();
+        unsigned int number_bits = getParameter("NumberBits").toUInt();
+        bool bit_duplicate = getParameter("BitDuplicate").toBool();
+
+        ASSERT(number_inputs > 0, "[Error] " + getInstanceName() + " -> Number of inputs must be > 0!");
+        ASSERT(number_outputs > 0, "[Error] " + getInstanceName() + " -> Number of outputs must be > 0!");
+        ASSERT(number_bits > 0, "[Error] " + getInstanceName() + " -> Number of bits must be > 0!");
+
+        unsigned int number_selects = (unsigned int)ceil(log2((double)number_inputs));
+        getGenProperties()->set("NumberSelectsPerPort", number_selects);
+
+        // Construct electrical ports and nets
+        // Create input ports
+        for(unsigned int i = 0; i < number_inputs; ++i)
+        {
+            createInputPort("In" + (String)i, makeNetIndex(0, number_bits-1));
+        }
+        // Create select signals
+        for(unsigned int i = 0; i < number_outputs; ++i)
+        {
+            for(unsigned int j = 0; j < number_selects; ++j)
+            {
+                createInputPort(String::format("Sel%d_%d", i, j));
+            }
+        }
+        // Create output ports
+        for(unsigned int i = 0; i < number_outputs; ++i)
+        {
+            createOutputPort("Out" + (String)i, makeNetIndex(0, number_bits-1));
+        }
+
+        // Create energy, power, and area results
+        addAreaResult(new AtomicResult("CrossbarWire"));
+        addAreaResult(new AtomicResult("CrossbarFill"));
+        createElectricalResults();
+        getEventInfo("Idle")->setStaticTransitionInfos();
+        createElectricalEventResult("Multicast0");
+        getEventInfo("Multicast0")->setStaticTransitionInfos();
+        for(unsigned int i = 1; i <= number_outputs; ++i)
+        {
+            createElectricalEventResult("Multicast" + (String)i);
+            EventInfo* event_info = getEventInfo("Multicast" + (String)i);
+            // Assuming that In0 is sending to Out0, Out1, ..., Outi
+            // and other input ports are static
+            for(unsigned int j = 1; j < number_inputs; ++j)
+            {
+                event_info->setStaticTransitionInfo("In" + (String)j);
+            }
+            for(unsigned int j = i; j < number_outputs; ++j)
+            {
+                for(unsigned int k = 0; k < number_selects; ++k)
+                {
+                    event_info->setStaticTransitionInfo(String::format("Sel%d_%d", j, k));
+                }
+            }
+        }
+        createElectricalEventResult("Crossbar");
+
+        // Initiate multiplexers
+        vector<String> mux_names(number_outputs, "");
+        vector<Multiplexer*> muxs(number_outputs, NULL);
+        for(unsigned int i = 0; i < number_outputs; ++i)
+        {
+            mux_names[i] = "Mux" + (String)i;
+            muxs[i] = new Multiplexer(mux_names[i], getTechModel());
+            muxs[i]->setParameter("NumberInputs", number_inputs);
+            muxs[i]->setParameter("NumberBits", number_bits);
+            muxs[i]->setParameter("BitDuplicate", bit_duplicate);
+            muxs[i]->construct();
+        }
+
+        // Connect inputs and outputs to multiplexers
+        for(unsigned int i = 0; i < number_outputs; ++i)
+        {
+            // Connect inputs
+            for(unsigned int j = 0; j < number_inputs; ++j)
+            {
+                portConnect(muxs[i], "In" + (String)j, "In" + (String)j, makeNetIndex(0, number_bits-1));
+            }
+
+            // Connect select signals
+            for(unsigned int j = 0; j < number_selects; ++j)
+            {
+                portConnect(muxs[i], "Sel" + (String)j, String::format("Sel%d_%d", i, j));
+            }
+
+            // Connect outputs
+            portConnect(muxs[i], "Out", "Out" + (String)i, makeNetIndex(0, number_bits-1));
+        }
+
+        // Add area, power, and event results for each mux
+        for(unsigned int i = 0; i < number_outputs; ++i)
+        {
+            addSubInstances(muxs[i], 1.0);
+            addElectricalSubResults(muxs[i], 1.0);
+            for(unsigned int j = 0; j <= number_outputs; ++j)
+            {
+                getEventResult("Multicast" + (String)j)->addSubResult(muxs[i]->getEventResult("Mux"), mux_names[i], 1.0);
+            }
+            getEventResult("Crossbar")->addSubResult(muxs[i]->getEventResult("Mux"), mux_names[i], 1.0);
+        }
+
+        // Estimate wiring area
+        const String& crossbar_wire_layer = "Intermediate";
+        addElectricalWireSubResult(crossbar_wire_layer, getAreaResult("CrossbarWire"), "Self", 1.0);
+        double wire_width = getTechModel()->get("Wire->" + crossbar_wire_layer + "->MinWidth").toDouble();
+        double wire_spacing = getTechModel()->get("Wire->" + crossbar_wire_layer + "->MinSpacing").toDouble();
+        double wire_pitch = wire_width + wire_spacing;
+        double wire_area = (number_bits * number_inputs * wire_pitch) * (number_bits * number_outputs * wire_pitch);
+        getAreaResult("CrossbarWire")->setValue(wire_area);
+
+        // Add filler area
+        getAreaResult("Active")->addSubResult(getAreaResult("CrossbarFill"), "Self", 1.0);
+        return;
+    }
+
+    void MultiplexerCrossbar::updateModel()
+    {
+        // Update all sub instances
+        Model::updateModel();
+
+        // Update filler area
+        // Total Active area = max(stdcell active area, wiring area);
+        double wire_area = getAreaResult("CrossbarWire")->calculateSum();
+        double active_area = getAreaResult("Active")->calculateSum();
+        double fill_area = 0.0;
+        if(active_area < wire_area)
+        {
+            fill_area = wire_area - active_area;
+        }
+        getAreaResult("CrossbarFill")->setValue(fill_area);
+        return;
+    }
+
+    void MultiplexerCrossbar::propagateTransitionInfo()
+    {
+        // The only thing can be updated are the input probabilities
+        const unsigned int number_inputs = getParameter("NumberInputs").toUInt();
+        const unsigned int number_outputs = getParameter("NumberOutputs").toUInt();
+
+        const unsigned int number_selects = getGenProperties()->get("NumberSelectsPerPort").toUInt();
+
+        for(unsigned int i = 0; i < number_outputs; ++i)
+        {
+            ElectricalModel* muxi = (ElectricalModel*)getSubInstance("Mux" + (String)i);
+            for(unsigned int j = 0; j < number_inputs; ++j)
+            {
+                propagatePortTransitionInfo(muxi, "In" + (String)j, "In" + (String)j);
+            }
+            for(unsigned int j = 0; j < number_selects; ++j)
+            {
+                propagatePortTransitionInfo(muxi, "Sel" + (String)j, String::format("Sel%d_%d", i, j));
+            }
+            muxi->use();
+
+            // Set output probability
+            propagatePortTransitionInfo("Out" + (String)i, muxi, "Out");
+        }
+
+        return;
+    }
+
+} // namespace DSENT
+
diff --git a/ext/dsent/model/electrical/MultiplexerCrossbar.h b/ext/dsent/model/electrical/MultiplexerCrossbar.h
new file mode 100644 (file)
index 0000000..e7f0920
--- /dev/null
@@ -0,0 +1,38 @@
+#ifndef __DSENT_MODEL_ELECTRICAL_MULTIPLEXER_CROSSBAR_H__
+#define __DSENT_MODEL_ELECTRICAL_MULTIPLEXER_CROSSBAR_H__
+
+#include "util/CommonType.h"
+#include "model/ElectricalModel.h"
+
+namespace DSENT
+{
+    // A model for a NxM W-bit multiplexer-based crossbar
+    class MultiplexerCrossbar : public ElectricalModel
+    {
+        public:
+            MultiplexerCrossbar(const String& instance_name_, const TechModel* tech_model_);
+            virtual ~MultiplexerCrossbar();
+
+        public:
+            // Set a list of paramerters' name needed to construct model 
+            void initParameters();
+            // Set a list of peroperties' name needed to construct model
+            void initProperties();
+
+            // Clone and return a new instance
+            virtual MultiplexerCrossbar* clone() const;
+
+        protected:
+            // Build the model
+            virtual void constructModel();
+            virtual void updateModel();
+            virtual void propagateTransitionInfo();
+
+        private:
+            // Disable copy constructor
+            MultiplexerCrossbar(const MultiplexerCrossbar& crossbar_);
+    }; // class MultiplexerCrossbar
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_ELECTRICAL_MULTIPLEXER_CROSSBAR_H__
+
diff --git a/ext/dsent/model/electrical/MuxTreeSerializer.cc b/ext/dsent/model/electrical/MuxTreeSerializer.cc
new file mode 100644 (file)
index 0000000..8f3b921
--- /dev/null
@@ -0,0 +1,226 @@
+#include "model/electrical/MuxTreeSerializer.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/StdCell.h"
+#include "model/electrical/Multiplexer.h"
+#include "model/timing_graph/ElectricalNet.h"
+
+namespace DSENT
+{
+    using std::ceil;
+
+    MuxTreeSerializer::MuxTreeSerializer(const String& instance_name_, const TechModel* tech_model_)
+        : ElectricalModel(instance_name_, tech_model_)
+    {
+        initParameters();
+        initProperties();
+    }
+
+    MuxTreeSerializer::~MuxTreeSerializer()
+    {}
+
+    void MuxTreeSerializer::initParameters()
+    {
+        addParameterName("InDataRate");
+        addParameterName("OutDataRate");
+        addParameterName("InBits");              //Output width will just be input width / serialization ratio
+    }
+
+    void MuxTreeSerializer::initProperties()
+    {
+        return;
+    }
+
+    MuxTreeSerializer* MuxTreeSerializer::clone() const
+    {
+        // TODO
+        return NULL;
+    }
+
+    void MuxTreeSerializer::constructModel()
+    {
+        // Get parameters
+        double in_data_rate = getParameter("InDataRate").toDouble();
+        double out_data_rate = getParameter("OutDataRate").toDouble();
+        unsigned int in_bits = getParameter("InBits").toUInt();
+        
+        // Calculate serialization ratio
+        unsigned int serialization_ratio = (unsigned int) floor(out_data_rate / in_data_rate);    
+        ASSERT(serialization_ratio == out_data_rate / in_data_rate,
+            "[Error] " + getInstanceName() + " -> Cannot have non-integer serialization ratios " +
+            "(" + (String) (in_data_rate / out_data_rate) + ")!");
+                
+        // Calculate output width
+        ASSERT(floor((double) in_bits / serialization_ratio) == (double) in_bits / serialization_ratio,
+            "[Error] " + getInstanceName() + " -> Input width (" + (String) in_bits + ") " +
+            "must be a multiple of the serialization ratio (" + (String) serialization_ratio + ")!");
+        unsigned int output_bits = in_bits / serialization_ratio;
+        
+        // Calculate the number of multiplexer stages
+        unsigned int number_stages = (unsigned int)ceil(log2((double) serialization_ratio));                    
+            
+        // Store calculated values
+        getGenProperties()->set("SerializationRatio", serialization_ratio);
+        getGenProperties()->set("OutputBits", output_bits);
+        getGenProperties()->set("NumberStages", number_stages);
+                
+        // Create ports
+        createInputPort("In", makeNetIndex(0, in_bits-1));
+        createInputPort("OutCK");
+        createOutputPort("Out", makeNetIndex(0, output_bits-1));
+
+        //Create energy, power, and area results
+        createElectricalResults();
+        createElectricalEventResult("Serialize");
+        getEventInfo("Serialize")->setTransitionInfo("OutCK", TransitionInfo(0.0, (double) serialization_ratio / 2.0, 0.0));
+        //Set conditions during idle state
+        getEventInfo("Idle")->setStaticTransitionInfos();
+        getEventInfo("Idle")->setTransitionInfo("OutCK", TransitionInfo(0.0, (double) serialization_ratio / 2.0, 0.0));
+        
+        // Mark OutCK as a false path (since timing tool will do strange stuff due to all the clock divides and stuff)
+        getNet("OutCK")->setFalsePath(true);
+        
+        // Create mux-tree instance
+        if (serialization_ratio == 1)
+        {
+            // No need to do anything, hohoho
+            assign("Out", "In");
+        }
+        else
+        {
+            // Create multiplexer
+            String mux_tree_name = "MuxTree";        
+            ElectricalModel* mux_tree = new Multiplexer(mux_tree_name, getTechModel());
+            mux_tree->setParameter("NumberInputs", serialization_ratio);
+            mux_tree->setParameter("NumberBits", output_bits);
+            mux_tree->setParameter("BitDuplicate", "TRUE");
+            mux_tree->construct();
+            // Create nets
+            if (number_stages > 1)
+                createNet("MuxSel_b", makeNetIndex(0, number_stages-2));
+            createNet("MuxSel", makeNetIndex(0, number_stages-1));
+            assign("MuxSel", makeNetIndex(number_stages-1), "OutCK");
+            // Create reindexed net (to help out with indexing)
+            createNet("InTmp", makeNetIndex(0, in_bits-1));            
+            for (unsigned int i = 0; i < serialization_ratio; ++i)
+                for (unsigned int j = 0; j < output_bits; ++j)
+                    assign("InTmp", makeNetIndex(i*output_bits+j), "In", makeNetIndex(j*serialization_ratio+i));
+
+            // Connect ports
+            for (unsigned int i = 0; i < serialization_ratio; ++i)
+                portConnect(mux_tree, "In" + (String) i, "InTmp", makeNetIndex(i*output_bits, (i+1)*output_bits-1));
+            
+            for (unsigned int i = 0; i < number_stages; ++i)
+                portConnect(mux_tree, "Sel" + (String) i, "MuxSel", makeNetIndex(i));
+            portConnect(mux_tree, "Out", "Out");
+
+            // Add subinstance and events
+            addSubInstances(mux_tree, 1.0);
+            addElectricalSubResults(mux_tree, 1.0);
+            // Add serialize event/power
+            getEventResult("Serialize")->addSubResult(mux_tree->getEventResult("Mux"), mux_tree_name, 1.0);
+
+            // Create clock dividers (assumes power of 2...), don't need divider for fastest output stage
+            for (unsigned int i = 0; i < number_stages - 1; ++i)
+            {
+                // Clk dividing registers
+                const String& clk_div_dff_name = "ClkDivDFF_" + (String) i;
+                StdCell* clk_div_dff = getTechModel()->getStdCellLib()->createStdCell("DFFQ", clk_div_dff_name);                
+                clk_div_dff->construct();
+                portConnect(clk_div_dff, "D", "MuxSel_b", makeNetIndex(i));
+                portConnect(clk_div_dff, "Q", "MuxSel", makeNetIndex(i));
+                portConnect(clk_div_dff, "CK", "MuxSel", makeNetIndex(i+1));
+                addSubInstances(clk_div_dff, 1.0);
+                addElectricalSubResults(clk_div_dff, 1.0);
+                
+                // Inversions
+                const String& clk_div_inv_name = "ClkDivINV_" + (String) i;
+                StdCell* clk_div_inv = getTechModel()->getStdCellLib()->createStdCell("INV", clk_div_inv_name);
+                clk_div_inv->construct();
+                portConnect(clk_div_inv, "A", "MuxSel", makeNetIndex(i));
+                portConnect(clk_div_inv, "Y", "MuxSel_b", makeNetIndex(i));
+                addSubInstances(clk_div_inv, 1.0);
+                addElectricalSubResults(clk_div_inv, 1.0);
+                            
+                getEventResult("Serialize")->addSubResult(clk_div_dff->getEventResult("CK"), clk_div_dff_name, 1.0); 
+                getEventResult("Serialize")->addSubResult(clk_div_dff->getEventResult("DFFD"), clk_div_dff_name, 1.0); 
+                getEventResult("Serialize")->addSubResult(clk_div_dff->getEventResult("DFFQ"), clk_div_dff_name, 1.0); 
+                getEventResult("Serialize")->addSubResult(clk_div_inv->getEventResult("INV"), clk_div_inv_name, 1.0);
+            }
+        }
+
+        return;
+    }
+
+    void MuxTreeSerializer::propagateTransitionInfo()
+    {
+        // Get some generated properties
+        const unsigned int serialization_ratio = getGenProperties()->get("SerializationRatio");
+        const unsigned int number_stages = getGenProperties()->get("NumberStages");
+        
+        // Set transition info of the mux tree and clock divide DFF
+        if (serialization_ratio == 1)
+        {
+            // If no serialization, then just propagate input transition info to output port
+            propagatePortTransitionInfo("Out", "In");
+        }
+        else
+        {
+
+            // Propagate transition probabilities to the mux tree
+            ElectricalModel* mux_tree = (ElectricalModel*) getSubInstance("MuxTree");
+            // All input ports of the mux have the same probability
+            for (unsigned int i = 0; i < serialization_ratio; ++i)
+                propagatePortTransitionInfo(mux_tree, "In" + (String) i, "In");
+            // Connect last stage of the mux
+            propagatePortTransitionInfo(mux_tree, "Sel" + (String) (number_stages - 1), "OutCK");                
+            // Keep track of the last clock divider
+            ElectricalModel* last_clk_div_dff = NULL;
+            // Find P01 of OutCK
+            double last_P01_CK = getInputPort("OutCK")->getTransitionInfo().getNumberTransitions01();
+            // Start from the last stage (since it is the stage with no clock division)
+            for (unsigned int i = 0; i < number_stages - 1; ++i)
+            {
+                const String& clk_div_dff_name = "ClkDivDFF_" + (String) (number_stages - i - 2);
+                const String& clk_div_inv_name = "ClkDivINV_" + (String) (number_stages - i - 2);
+                
+                ElectricalModel* clk_div_dff = (ElectricalModel*) getSubInstance(clk_div_dff_name);
+                if (last_clk_div_dff == NULL)
+                    propagatePortTransitionInfo(clk_div_dff, "CK", "OutCK");
+                else
+                    propagatePortTransitionInfo(clk_div_dff, "CK", last_clk_div_dff, "Q");
+                // Since it is a clock divider, P01 is D and Q are simply half the P01 of D and Q of
+                // the input clock
+                if (last_P01_CK != 0) clk_div_dff->getInputPort("D")->setTransitionInfo(TransitionInfo(0.0, last_P01_CK * 0.5, 0.0));
+                else clk_div_dff->getInputPort("D")->setTransitionInfo(TransitionInfo(0.5, 0.0, 0.5));
+
+                clk_div_dff->use();
+
+                ElectricalModel* clk_div_inv = (ElectricalModel*) getSubInstance(clk_div_inv_name);
+                propagatePortTransitionInfo(clk_div_inv, "A", clk_div_dff, "Q");
+                clk_div_inv->use();
+                
+                // Connect select port of the mux
+                propagatePortTransitionInfo(mux_tree, "Sel" + (String) (number_stages - i - 2), clk_div_dff, "Q");
+                
+                // Clk divide by 2;
+                last_P01_CK = last_P01_CK * 0.5;
+                // Remember the last clk div DFF
+                last_clk_div_dff = clk_div_dff;
+            }
+            
+            mux_tree->use();
+            // Set output transition info to be the output transition info of the mux tree
+            propagatePortTransitionInfo("Out", mux_tree, "Out");            
+        }
+
+        return;
+    }
+
+} // namespace DSENT
+
diff --git a/ext/dsent/model/electrical/MuxTreeSerializer.h b/ext/dsent/model/electrical/MuxTreeSerializer.h
new file mode 100644 (file)
index 0000000..f56cccc
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef __DSENT_MODEL_ELECTRICAL_MUXTREESERIALIZER_H__
+#define __DSENT_MODEL_ELECTRICAL_MUXTREESERIALIZER_H__
+
+#include "util/CommonType.h"
+#include "model/ElectricalModel.h"
+
+namespace DSENT
+{
+    class MuxTreeSerializer : public ElectricalModel
+    {
+        public:
+            MuxTreeSerializer(const String& instance_name_, const TechModel* tech_model_);
+            virtual ~MuxTreeSerializer();
+
+        public:
+            // Set a list of properties' name needed to construct model
+            void initParameters();
+            // Set a list of properties' name needed to construct model
+            void initProperties();
+
+            // Clone and return a new instance
+            virtual MuxTreeSerializer* clone() const;
+
+        protected:
+            // Build the model
+            virtual void constructModel();
+            virtual void propagateTransitionInfo();
+
+    }; // class MuxTreeSerializer
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_ELECTRICAL_MUXTREESERIALIZER_H__
+
diff --git a/ext/dsent/model/electrical/OR.cc b/ext/dsent/model/electrical/OR.cc
new file mode 100644 (file)
index 0000000..d948ff0
--- /dev/null
@@ -0,0 +1,239 @@
+#include "model/electrical/OR.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/StdCell.h"
+#include "model/timing_graph/ElectricalNet.h"
+
+namespace DSENT
+{
+    using std::ceil;
+    using std::floor;
+
+    OR::OR(const String& instance_name_, const TechModel* tech_model_)
+        : ElectricalModel(instance_name_, tech_model_)
+    {
+        initParameters();
+        initProperties();
+    }
+
+    OR::~OR()
+    {}
+
+    void OR::initParameters()
+    {
+        addParameterName("NumberInputs");
+        addParameterName("NumberBits");
+        addParameterName("BitDuplicate", "TRUE");
+        return;
+    }
+
+    void OR::initProperties()
+    {
+        return;
+    }
+
+    OR* OR::clone() const
+    {
+        // TODO
+        return NULL;
+    }
+
+    void OR::constructModel()
+    {
+        // Get parameter
+        unsigned int number_inputs = getParameter("NumberInputs").toUInt();
+        unsigned int number_bits = getParameter("NumberBits").toUInt();
+        bool bit_duplicate = getParameter("BitDuplicate").toBool();
+
+        ASSERT(number_inputs > 0, "[Error] " + getInstanceName() +
+                " -> Number of inputs must be > 0!");
+        ASSERT(number_bits > 0, "[Error] " + getInstanceName() + 
+                " -> Number of bits must be > 0!");
+
+
+        // Init ports
+        for(unsigned int i = 0; i < number_inputs; ++i)
+        {
+            createInputPort("In" + (String)i, makeNetIndex(0, number_bits-1));
+        }
+        createOutputPort("Out", makeNetIndex(0, number_bits-1));
+
+        // Number of inputs on the 0 side
+        unsigned int or0_number_inputs = (unsigned int)ceil((double)number_inputs / 2.0);
+        // Number of inputs on the 1 side
+        unsigned int or1_number_inputs = (unsigned int)floor((double)number_inputs / 2.0);
+
+        // Create area, power, and event results
+        createElectricalResults();
+        createElectricalEventResult("OR");
+
+        getEventInfo("Idle")->setStaticTransitionInfos();
+
+        //Depending on whether we want to create a 1-bit instance and have it multiplied
+        //up by number of bits or actually instantiate number_bits of 1-bit instances.
+        //Recursively instantiates smaller ors
+        if(bit_duplicate || number_bits == 1)
+        {
+            // If it is just a 1-input or, just connect output to input
+            if(number_inputs == 1)
+            {
+                assign("Out", "In0");
+            }
+            else
+            {
+                // If it is more than 1 input, instantiate two sub ors (OR_way0 and OR_way1)
+                // and create a final OR2 to OR them
+                const String& or0_name = "OR_way0";
+                const String& or1_name = "OR_way1";
+                const String& orf_name = "OR2_i" + (String)number_inputs;
+
+                OR* or0 = new OR(or0_name, getTechModel());
+                or0->setParameter("NumberInputs", or0_number_inputs);
+                or0->setParameter("NumberBits", 1);
+                or0->setParameter("BitDuplicate", "TRUE");
+                or0->construct();
+
+                OR* or1 = new OR(or1_name, getTechModel());
+                or1->setParameter("NumberInputs", or1_number_inputs);
+                or1->setParameter("NumberBits", 1);
+                or1->setParameter("BitDuplicate", "TRUE");
+                or1->construct();
+
+                StdCell* orf = getTechModel()->getStdCellLib()->createStdCell("OR2", orf_name);
+                orf->construct();
+
+                // Create outputs of way0 and way1 ors with final or
+                createNet("way0_Out");
+                createNet("way1_Out");
+                portConnect(or0, "Out", "way0_Out");
+                portConnect(or1, "Out", "way1_Out");
+                portConnect(orf, "A", "way0_Out");
+                portConnect(orf, "B", "way1_Out");
+
+                // Connect inputs to the sub ors.
+                for(unsigned int i = 0; i < or0_number_inputs; ++i)
+                {
+                    createNet("way0_In" + (String)i);
+                    portConnect(or0, "In" + (String)i, "way0_In" + (String)i);
+                    assignVirtualFanin("way0_In" + (String)i, "In" + (String)i);
+                }
+                for(unsigned int i = 0; i < or1_number_inputs; ++i)
+                {
+                    createNet("way1_In" + (String)i);
+                    portConnect(or1, "In" + (String)i, "way1_In" + (String)i);
+                    assignVirtualFanin("way1_In" + (String)i, "In" + (String)(i + or0_number_inputs));
+                }
+
+                // Connect outputs
+                createNet("OR2_Out");
+                portConnect(orf, "Y", "OR2_Out");
+                assignVirtualFanout("Out", "OR2_Out");
+
+                addSubInstances(or0, number_bits);
+                addElectricalSubResults(or0, number_bits);
+                addSubInstances(or1, number_bits);
+                addElectricalSubResults(or1, number_bits);
+                addSubInstances(orf, number_bits);
+                addElectricalSubResults(orf, number_bits);
+
+                Result* or_event = getEventResult("OR");
+                or_event->addSubResult(or0->getEventResult("OR"), or0_name, number_bits);
+                or_event->addSubResult(or1->getEventResult("OR"), or1_name, number_bits);
+                or_event->addSubResult(orf->getEventResult("OR2"), orf_name, number_bits);
+
+            }
+        }
+        else
+        {
+            // Init a bunch of 1-bit ors
+            Result* or_event = getEventResult("OR");
+            for(unsigned int n = 0; n < number_bits; ++n)
+            {
+                const String& or_name = "OR_bit" + (String)n;
+
+                OR* ors = new OR(or_name, getTechModel());
+                ors->setParameter("NumberInputs", number_inputs);
+                ors->setParameter("NumberBits", 1);
+                ors->setParameter("BitDuplicate", "TRUE");
+                ors->construct();
+
+                for(unsigned int i = 0; i < number_inputs; ++i)
+                {
+                    portConnect(ors, "In" + (String)i, "In" + (String)i, makeNetIndex(n));
+                }
+                portConnect(ors, "Out", "Out", makeNetIndex(n));
+
+                addSubInstances(ors, 1.0);
+                addElectricalSubResults(ors, 1.0);
+                or_event->addSubResult(ors->getEventResult("OR"), or_name, 1.0);
+            }
+        }
+        return;
+    }
+
+    void OR::propagateTransitionInfo()
+    {
+        // Get parameters
+        unsigned int number_inputs = getParameter("NumberInputs").toUInt();
+        unsigned int number_bits = getParameter("NumberBits").toUInt();
+        bool bit_duplicate = getParameter("BitDuplicate").toBool();
+
+        // Number of inputs on 0 side
+        unsigned int or0_number_inputs = (unsigned int)ceil((double)number_inputs / 2.0);
+        unsigned int or1_number_inputs = (unsigned int)floor((double)number_inputs / 2.0);
+
+        if(bit_duplicate || number_bits == 1)
+        {
+            if(number_inputs == 1)
+            {
+                propagatePortTransitionInfo("Out", "In0");
+            }
+            else
+            {
+                ElectricalModel* or0 = (ElectricalModel*)getSubInstance("OR_way0");
+                for(unsigned int i = 0; i < or0_number_inputs; ++i)
+                {
+                    propagatePortTransitionInfo(or0, "In" + (String)i, "In" + (String)i);
+                }
+                or0->use();
+
+                ElectricalModel* or1 = (ElectricalModel*)getSubInstance("OR_way1");
+                for(unsigned int i = 0; i < or1_number_inputs; ++i)
+                {
+                    propagatePortTransitionInfo(or1, "In" + (String)i, "In" + (String)i);
+                }
+                or1->use();
+
+                ElectricalModel* orf = (ElectricalModel*)getSubInstance("OR2_i" + (String)number_inputs);
+                propagatePortTransitionInfo(orf, "A", or0, "Out");
+                propagatePortTransitionInfo(orf, "B", or1, "Out");
+                orf->use();
+
+                // Set output probability
+                propagatePortTransitionInfo("Out", orf, "Y");
+            }
+        }
+        else
+        {
+            for(unsigned int n = 0; n < number_bits; ++n)
+            {
+                ElectricalModel* or_bit = (ElectricalModel*)getSubInstance("OR_bit" + (String)n);
+                for(unsigned int i = 0; i < number_inputs; ++i)
+                {
+                    propagatePortTransitionInfo(or_bit, "In" + (String)i, "In" + (String)i);
+                }
+                or_bit->use();
+            }
+
+            ElectricalModel* or_bit = (ElectricalModel*)getSubInstance("OR_bit0");
+            propagatePortTransitionInfo("Out", or_bit, "Out");
+        }
+        return;
+    }
+} // namespace DSENT
+
diff --git a/ext/dsent/model/electrical/OR.h b/ext/dsent/model/electrical/OR.h
new file mode 100644 (file)
index 0000000..b830479
--- /dev/null
@@ -0,0 +1,36 @@
+#ifndef __DSENT_MODEL_ELECTRICAL_OR_H__
+#define __DSENT_MODEL_ELECTRICAL_OR_H__
+
+#include "util/CommonType.h"
+#include "model/ElectricalModel.h"
+
+namespace DSENT
+{
+    /**
+     * \brief A class that implements a n-input OR gate
+     */
+    class OR : public ElectricalModel
+    {
+        public:
+            OR(const String& instance_name_, const TechModel* tech_model_);
+            virtual ~OR();
+
+        public:
+            // Set a list of properties' name needed to construct model
+            void initParameters();
+            // Set a list of properties' name needed to construct model
+            void initProperties();
+
+            // Clone and return a new instance
+            virtual OR* clone() const;
+
+        protected:
+            // Build the model
+            virtual void constructModel();
+            virtual void propagateTransitionInfo();
+
+    }; // class OR
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_ELECTRICAL_OR_H__
+
diff --git a/ext/dsent/model/electrical/RepeatedLink.cc b/ext/dsent/model/electrical/RepeatedLink.cc
new file mode 100644 (file)
index 0000000..08a40e4
--- /dev/null
@@ -0,0 +1,305 @@
+#include "model/electrical/RepeatedLink.h"
+
+#include "model/PortInfo.h"
+#include "model/EventInfo.h"
+#include "model/TransitionInfo.h"
+#include "model/std_cells/StdCellLib.h"
+#include "model/std_cells/StdCell.h"
+#include "model/timing_graph/ElectricalTimingTree.h"
+#include "model/timing_graph/ElectricalTimingNode.h"
+#include "model/timing_graph/ElectricalNet.h"
+#include "model/timing_graph/ElectricalDriver.h"
+#include "model/timing_graph/ElectricalDelay.h"
+#include "model/timing_graph/ElectricalLoad.h"
+
+namespace DSENT
+{
+    RepeatedLink::RepeatedLink(const String& instance_name_, const TechModel* tech_model_)
+        : ElectricalModel(instance_name_, tech_model_)
+    {
+        m_repeater_ = NULL;
+        m_repeater_load_ = NULL;
+        m_timing_tree_ = NULL;
+
+        initParameters();
+        initProperties();
+    }
+
+    RepeatedLink::~RepeatedLink()
+    {
+        delete m_repeater_;
+        delete m_repeater_load_;
+        delete m_timing_tree_;
+    }
+
+    void RepeatedLink::initParameters()
+    {
+        addParameterName("NumberBits");
+        addParameterName("WireLayer");
+        addParameterName("WireWidthMultiplier", 1.0);
+        addParameterName("WireSpacingMultiplier", 1.0);
+        return;
+    }
+
+    void RepeatedLink::initProperties()
+    {
+        addPropertyName("WireLength");
+        addPropertyName("Delay");
+        addPropertyName("IsKeepParity", "TRUE");
+        return;
+    }
+
+    RepeatedLink* RepeatedLink::clone() const
+    {
+        // TODO
+        return NULL;
+    }
+
+    void RepeatedLink::constructModel()
+    {
+        // Get parameters
+        unsigned int number_bits = getParameter("NumberBits").toUInt();
+        const String& wire_layer = getParameter("WireLayer");
+        double wire_width_multiplier = getParameter("WireWidthMultiplier").toDouble();
+        double wire_spacing_multiplier = getParameter("WireSpacingMultiplier").toDouble();
+
+        ASSERT(number_bits > 0, "[Error] " + getInstanceName() + 
+                " -> Number of bits must be > 0!");
+        ASSERT(getTechModel()->isWireLayerExist(wire_layer), "[Error] " + getInstanceName() + 
+                " -> Wire layer does not exist!");
+        ASSERT(wire_width_multiplier >= 1.0, "[Error] " + getInstanceName() + 
+                " -> Wire width multiplier must be >= 1.0!");
+        ASSERT(wire_spacing_multiplier >= 1.0, "[Error] " + getInstanceName() +
+                " -> Wire spacing multiplier must be >= 1.0!");
+
+        double wire_min_width = getTechModel()->get("Wire->" + wire_layer + "->MinWidth").toDouble();
+        double wire_min_spacing = getTechModel()->get("Wire->" + wire_layer + "->MinSpacing").toDouble();
+
+        double wire_width = wire_min_width * wire_width_multiplier;
+        double wire_spacing = wire_min_spacing * wire_spacing_multiplier;
+
+        double wire_cap_per_len = getTechModel()->calculateWireCapacitance(wire_layer, wire_width, wire_spacing, 1.0);
+        double wire_res_per_len = getTechModel()->calculateWireResistance(wire_layer, wire_width, 1.0);
+
+        getGenProperties()->set("WireWidth", wire_width);
+        getGenProperties()->set("WireSpacing", wire_spacing);
+        getGenProperties()->set("WireCapacitancePerLength", wire_cap_per_len);
+        getGenProperties()->set("WireResistancePerLength", wire_res_per_len);
+
+        // Create ports
+        createInputPort("In", makeNetIndex(0, number_bits-1));
+        createOutputPort("Out", makeNetIndex(0, number_bits-1));
+
+        // Create area, power, and event results
+        createElectricalAtomicResults();        
+        createElectricalEventAtomicResult("Send");
+
+        // Create connections
+        // Since the length is not set yet, we only to virtual fan-in and virtual fan-out
+        createNet("InTmp");
+        createNet("OutTmp");
+        assignVirtualFanin("InTmp", "In");
+        assignVirtualFanout("Out", "OutTmp");
+
+        // Build Electrical Connectivity
+        createLoad("In_Cap");
+        createDelay("In_to_Out_delay");
+        createDriver("Out_Ron", false); // Indicate this driver is not sizable
+
+        ElectricalLoad* in_cap = getLoad("In_Cap");
+        ElectricalDelay* in_to_out_delay = getDelay("In_to_Out_delay");
+        ElectricalDriver* out_ron = getDriver("Out_Ron");
+
+        getNet("InTmp")->addDownstreamNode(in_cap);
+        in_cap->addDownstreamNode(in_to_out_delay);
+        in_to_out_delay->addDownstreamNode(out_ron);
+        out_ron->addDownstreamNode(getNet("OutTmp"));
+
+        // Init a repeater and a load to mimic a segment of a repeated link
+        m_repeater_ = getTechModel()->getStdCellLib()->createStdCell("INV", "Repeater");
+        m_repeater_->construct();
+        m_repeater_load_ = new ElectricalLoad("RepeaterIn_Cap", this);
+        // Make path repeater_ -> repeater_load_
+        // to catch the repeater's input/output cap and ensure only one inverter delay
+        // is added
+        m_repeater_->getNet("Y")->addDownstreamNode(m_repeater_load_);
+        // Init a timing object to calculate delay
+        m_timing_tree_ = new ElectricalTimingTree("RepeatedLink", this);
+        m_timing_tree_->performCritPathExtract(m_repeater_->getNet("A"));
+        return;
+    }
+
+    void RepeatedLink::updateModel()
+    {
+        unsigned int number_bits = getParameter("NumberBits").toUInt();
+
+        // Get properties
+        double wire_length = getProperty("WireLength").toDouble();
+        double required_delay = getProperty("Delay").toDouble();
+        bool isKeepParity = getProperty("IsKeepParity").toBool();
+
+        ASSERT(wire_length >= 0, "[Error] " + getInstanceName() +
+                " -> Wire length must be >= 0!");
+        ASSERT(required_delay >= 0, "[Error] " + getInstanceName() + 
+                " -> Required delay must be >= 0!");
+
+        const String& wire_layer = getParameter("WireLayer");
+        double wire_width = getGenProperties()->get("WireWidth").toDouble();
+        double wire_spacing = getGenProperties()->get("WireSpacing").toDouble();
+
+        // Calculate the total wire cap and total wire res
+        double wire_cap_per_len = getGenProperties()->get("WireCapacitancePerLength").toDouble();
+        double wire_res_per_len = getGenProperties()->get("WireResistancePerLength").toDouble();
+        double total_wire_cap = wire_cap_per_len * wire_length;
+        double total_wire_res = wire_res_per_len * wire_length;
+
+        m_repeater_->update();
+
+        unsigned int increment_segments = (isKeepParity)? 2:1;
+        unsigned int number_segments = increment_segments;
+        double delay;
+        m_repeater_->setMinDrivingStrength();
+        m_repeater_->getNet("Y")->setDistributedCap(total_wire_cap / number_segments);
+        m_repeater_->getNet("Y")->setDistributedRes(total_wire_res / number_segments);
+        m_repeater_load_->setLoadCap(m_repeater_->getNet("A")->getTotalDownstreamCap());
+        m_timing_tree_->performCritPathExtract(m_repeater_->getNet("A"));
+        delay = m_timing_tree_->calculateCritPathDelay(m_repeater_->getNet("A")) * number_segments;
+
+        // If everything is 0, use number_segments min-sized repeater
+        if(wire_length != 0)
+        {
+            // Set the initial number of segments based on isKeepParity
+            double last_min_size_delay = 0;
+            unsigned int iteration = 0;
+
+            // First set the repeater to the minimum driving strength
+            last_min_size_delay = delay;
+
+            Log::printLine(getInstanceName() + " -> Beginning Repeater Insertion");
+
+            while(required_delay < delay)
+            {
+                Log::printLine(getInstanceName() + " -> Repeater Insertion Iteration " + (String)iteration + 
+                        ": Required delay = " + (String)required_delay + 
+                        ", Delay = " + (String)delay + 
+                        ", Slack = " + (String)(required_delay - delay) + 
+                        ", Number of repeaters = " + (String)number_segments);
+
+                // Size up if timing is not met
+                while(required_delay < delay)
+                {
+                    if(m_repeater_->hasMaxDrivingStrength())
+                    {
+                        break;
+                    }
+                    m_repeater_->increaseDrivingStrength();
+                    m_repeater_load_->setLoadCap(m_repeater_->getNet("A")->getTotalDownstreamCap());
+                    m_timing_tree_->performCritPathExtract(m_repeater_->getNet("A"));
+                    delay = m_timing_tree_->calculateCritPathDelay(m_repeater_->getNet("A")) * number_segments;
+
+                    iteration++;
+                    Log::printLine(getInstanceName() + " -> Slack: " + (String)(required_delay - delay));
+                }
+                // Increase number of segments if timing is not met
+                if(required_delay < delay)
+                {
+                    number_segments += increment_segments;
+                    m_repeater_->setMinDrivingStrength();
+                    m_repeater_->getNet("Y")->setDistributedCap(total_wire_cap / number_segments);
+                    m_repeater_->getNet("Y")->setDistributedRes(total_wire_res / number_segments);
+                    m_repeater_load_->setLoadCap(m_repeater_->getNet("A")->getTotalDownstreamCap());
+                    m_timing_tree_->performCritPathExtract(m_repeater_->getNet("A"));
+                    delay = m_timing_tree_->calculateCritPathDelay(m_repeater_->getNet("A")) * number_segments;
+
+                    // Abort if adding more min sized repeaters does not decrease the delay
+                    if(delay > last_min_size_delay)
+                    {
+                        break;
+                    }
+                    last_min_size_delay = delay;
+                }
+            }
+            Log::printLine(getInstanceName() + " -> Repeater Insertion Ended after Iteration: " + (String)iteration + 
+                    ": Required delay = " + (String)required_delay + 
+                    ", Delay = " + (String)delay + 
+                    ", Slack = " + (String)(required_delay - delay) + 
+                    ", Number of repeaters = " + (String)number_segments);
+
+            // Print a warning if the timing is not met
+            if(required_delay < delay)
+            {
+                const String& warning_msg = "[Warning] " + getInstanceName() + " -> Timing not met" + 
+                    ": Required delay = " + (String)required_delay + 
+                    ", Delay = " + (String)delay + 
+                    ", Slack = " + (String)(required_delay - delay) +
+                    ", Number of repeaters = " + (String)number_segments;
+                Log::printLine(std::cerr, warning_msg);
+            }
+        }
+
+        // Update electrical interfaces
+        getLoad("In_Cap")->setLoadCap(m_repeater_->getNet("A")->getTotalDownstreamCap());
+        getDelay("In_to_Out_delay")->setDelay(delay);
+        getDriver("Out_Ron")->setOutputRes(m_repeater_->getDriver("Y_Ron")->getOutputRes() + (total_wire_res / number_segments));
+
+        getGenProperties()->set("NumberSegments", number_segments);
+
+        // Update area, power results
+        resetElectricalAtomicResults();
+        addElecticalAtomicResultValues(m_repeater_, number_segments * number_bits);
+        double wire_area = wire_length * (wire_width + wire_spacing) * number_bits;
+        addElecticalWireAtomicResultValue(wire_layer, wire_area);
+
+        return;
+    }
+
+    void RepeatedLink::useModel()
+    {
+        // Update the transition information for the modeled repeater
+        // Since we only modeled one repeater. So the transition information for 0->0 and 1->1 
+        // is averaged out
+        const TransitionInfo& trans_In = getInputPort("In")->getTransitionInfo();
+        double average_static_transition = (trans_In.getNumberTransitions00() + trans_In.getNumberTransitions11()) / 2.0;
+        TransitionInfo mod_trans_In(average_static_transition, trans_In.getNumberTransitions01(), average_static_transition);
+        m_repeater_->getInputPort("A")->setTransitionInfo(mod_trans_In);
+        m_repeater_->use();
+
+        // Get parameters
+        unsigned int number_bits = getParameter("NumberBits").toUInt();
+        unsigned int number_segments = getGenProperties()->get("NumberSegments").toUInt();
+
+        // Propagate the transition information
+        propagateTransitionInfo();
+
+        // Update leakage power
+        double power = 0.0;
+        power += m_repeater_->getNddPowerResult("Leakage")->calculateSum() * number_segments * number_bits;
+        getNddPowerResult("Leakage")->setValue(power);
+
+        // Update event result
+        double energy = 0.0;
+        energy += m_repeater_->getEventResult("INV")->calculateSum() * number_segments * number_bits;
+        getEventResult("Send")->setValue(energy);
+
+        return;
+    }
+
+    void RepeatedLink::propagateTransitionInfo()
+    {
+        unsigned int number_segments = getGenProperties()->get("NumberSegments");
+
+        if((number_segments % 2) == 0)
+        {
+            propagatePortTransitionInfo("Out", "In");
+        }
+        else
+        {
+            const TransitionInfo& trans_In = getInputPort("In")->getTransitionInfo();
+            TransitionInfo trans_Out(trans_In.getNumberTransitions11(), trans_In.getNumberTransitions01(), trans_In.getNumberTransitions00());
+            getOutputPort("Out")->setTransitionInfo(trans_Out);
+        }
+        return;
+    }
+
+} // namespace DSENT
+
diff --git a/ext/dsent/model/electrical/RepeatedLink.h b/ext/dsent/model/electrical/RepeatedLink.h
new file mode 100644 (file)
index 0000000..1cd8e34
--- /dev/null
@@ -0,0 +1,44 @@
+#ifndef __DSENT_MODEL_ELECTRICAL_REPEATED_LINK_H__
+#define __DSENT_MODEL_ELECTRICAL_REPEATED_LINK_H__
+
+#include "util/CommonType.h"
+#include "model/ElectricalModel.h"
+
+namespace DSENT
+{
+    class StdCell;
+    class ElectricalLoad;
+    class ElectricalTimingTree;
+
+    class RepeatedLink : public ElectricalModel
+    {
+        public:
+            RepeatedLink(const String& instance_name_, const TechModel* tech_model_);
+            virtual ~RepeatedLink();
+
+        public:
+            // Set a list of properties' name needed to construct model
+            void initParameters();
+            // Set a list of properties' name needed to construct model
+            void initProperties();
+
+            // Clone and return a new instance
+            virtual RepeatedLink* clone() const;
+
+        protected:
+            // Build the model
+            virtual void constructModel();
+            virtual void updateModel();
+            virtual void useModel();
+            virtual void propagateTransitionInfo();
+
+        private:
+            // Use a repeater and a load to mimic a segment of the repeated link
+            StdCell* m_repeater_;
+            ElectricalLoad* m_repeater_load_;
+            ElectricalTimingTree* m_timing_tree_;
+    }; // class RepeatedLink
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_ELECTRICAL_REPEATED_LINK_H__
+
diff --git a/ext/dsent/model/electrical/RippleAdder.cc b/ext/dsent/model/electrical/RippleAdder.cc
new file mode 100644 (file)
index 0000000..779cd47
--- /dev/null
@@ -0,0 +1,106 @@
+#include "model/electrical/RippleAdder.h"
+
+#include <cmath>
+
+#include "model/PortInfo.h"
+#include "model/TransitionInfo.h"
+#include "model/EventInfo.h"
+#include "model/std_cells/StdCell.h"
+#include "model/std_cells/StdCellLib.h"
+
+namespace DSENT
+{
+    RippleAdder::RippleAdder(const String& instance_name_, const TechModel* tech_model_)
+        : ElectricalModel(instance_name_, tech_model_)
+    {
+        initParameters();
+        initProperties();
+    }
+
+    RippleAdder::~RippleAdder()
+    {}
+
+    void RippleAdder::initParameters()
+    {
+        addParameterName("NumberBits");
+        return;
+    }
+
+    void RippleAdder::initProperties()
+    {
+        return;
+    }
+
+    void RippleAdder::constructModel()
+    {
+        // Get properties
+        unsigned int number_bits = (unsigned int) getParameter("NumberBits");
+
+        //Construct electrical ports and nets
+        createInputPort("CI");
+        createOutputPort("CO");
+        for(unsigned int i = 0; i < number_bits; ++i)
+        {
+            createInputPort("A" + String(i));
+            createInputPort("B" + String(i));
+            createOutputPort("S" + String(i));
+            createNet("C" + String(i));
+        }
+        createNet("C" + String(number_bits));
+
+        //Create energy, power, and area results
+        createElectricalResults();
+        getEventInfo("Idle")->setStaticTransitionInfos();
+        createElectricalEventResult("Add");
+        Result* add_event = getEventResult("Add");
+
+        // Connect all nets 
+        assign("C0", "CI");
+        assign("CO", "C" + String(number_bits));
+        for (unsigned int i = 0; i < number_bits; ++i)
+        {
+            String n = (String) i;            
+            StdCell* adder = getTechModel()->getStdCellLib()->createStdCell("ADDF", "ADDF_" + n);
+            adder->construct();
+
+            //Build electrical connectivity
+            portConnect(adder, "A", "A" + String(i));
+            portConnect(adder, "B", "B" + String(i));
+            portConnect(adder, "CI", "C" + String(i));
+            portConnect(adder, "S", "S" + String(i));
+            portConnect(adder, "CO", "C" + String(i + 1));
+
+            //Add ADDF instance, leakage power, energy, and add event results
+            addSubInstances(adder, 1.0);                        
+            addElectricalSubResults(adder, 1.0);
+            add_event->addSubResult(adder->getEventResult("ADDF"), "ADDF_" + n, 1.0);
+        }
+
+        return;
+    }
+
+    void RippleAdder::propagateTransitionInfo()
+    {
+        unsigned int number_bits = getParameter("NumberBits").toUInt();
+
+        TransitionInfo current_trans_CI = getInputPort("CI")->getTransitionInfo();
+        for(unsigned int i = 0; i < number_bits; ++i)
+        {
+            ElectricalModel* adder = (ElectricalModel*)getSubInstance("ADDF_" + String(i));
+
+            // Propagate input transition info
+            propagatePortTransitionInfo(adder, "A", "A" + String(i));
+            propagatePortTransitionInfo(adder, "B", "B" + String(i));
+            assignPortTransitionInfo(adder, "CI", current_trans_CI);
+            adder->use();
+
+            // Assign output transition info
+            propagatePortTransitionInfo("S" + String(i), adder, "S");
+            current_trans_CI = adder->getOutputPort("CO")->getTransitionInfo();
+        }
+        getOutputPort("CO")->setTransitionInfo(current_trans_CI);
+        return;
+    }
+
+} // namespace DSENT
+
diff --git a/ext/dsent/model/electrical/RippleAdder.h b/ext/dsent/model/electrical/RippleAdder.h
new file mode 100644 (file)
index 0000000..6f5f710
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef __DSENT_MODEL_ELECTRICAL_RIPPLE_ADDER_H__
+#define __DSENT_MODEL_ELECTRICAL_RIPPLE_ADDER_H__
+
+#include "util/CommonType.h"
+#include "model/ElectricalModel.h"
+
+namespace DSENT
+{
+    class RippleAdder : public ElectricalModel
+    {
+        public:
+            RippleAdder(const String& instance_name_, const TechModel* tech_model_);
+            virtual ~RippleAdder();
+
+        public:
+            // Set a list of properties' name needed to construct model
+            void initParameters();
+            // Set a list of properties' name needed to construct model
+            void initProperties();
+
+        protected:
+            // Build the model
+            virtual void constructModel();
+            virtual void propagateTransitionInfo();
+
+    }; // class RippleAdder
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_ELECTRICAL_TESTMODEL_H__
+
diff --git a/ext/dsent/model/electrical/SeparableAllocator.cc b/ext/dsent/model/electrical/SeparableAllocator.cc
new file mode 100644 (file)
index 0000000..e0965cb
--- /dev/null
@@ -0,0 +1,270 @@
+#include "model/electrical/SeparableAllocator.h"
+
+#include "model/ModelGen.h"
+#include "model/timing_graph/ElectricalNet.h"
+
+namespace DSENT
+{
+    SeparableAllocator::SeparableAllocator(const String& instance_name_, const TechModel* tech_model_)
+        : ElectricalModel(instance_name_, tech_model_)
+    {
+        initParameters();
+        initProperties();
+    }
+
+    SeparableAllocator::~SeparableAllocator()
+    {}
+
+    void SeparableAllocator::initParameters()
+    {
+        addParameterName("NumberRequesters");
+        addParameterName("NumberResources");
+        addParameterName("IsRequesterFirst", true);
+        addParameterName("Stage1->ArbiterModel");
+        addParameterName("Stage2->ArbiterModel");
+        return;
+    }
+
+    void SeparableAllocator::initProperties()
+    {
+        addPropertyName("P(Request)");
+        addPropertyName("Act(Request)");
+        addPropertyName("P(CK)");
+        addPropertyName("Act(CK)");
+        return;
+    }
+
+    SeparableAllocator* SeparableAllocator::clone() const
+    {
+        // TODO
+        return NULL;
+    }
+
+    void SeparableAllocator::constructModel()
+    {
+        // Get parameters
+        unsigned int number_requesters = getParameter("NumberRequesters").toUInt();
+        unsigned int number_resources = getParameter("NumberResources").toUInt();
+        bool is_requester_first = getParameter("IsRequesterFirst").toBool();
+        const String& stage1_arbiter_model = getParameter("Stage1->ArbiterModel");
+        const String& stage2_arbiter_model = getParameter("Stage2->ArbiterModel");
+
+        ASSERT(number_requesters > 0, "[Error] " + getInstanceName() + 
+                " -> Number of requesters must be > 0!");
+        ASSERT(number_resources > 0, "[Error] " + getInstanceName() +
+                " -> Number of resources must be > 0!");
+
+        // Create area, power, and event results
+        createElectricalResults();
+        addEventResult(new Result("Allocate"));
+
+        // Create ports
+        createInputPort("CK");
+        for(unsigned int i = 0; i < number_requesters; ++i)
+        {
+            createInputPort("Request" + (String)i, makeNetIndex(0, number_resources-1));
+            createOutputPort("Grant" + (String)i, makeNetIndex(0, number_resources-1));
+        }
+
+        // If is_requester_first is set, requests from the same requester will be arbitrate 
+        // on stage 1
+        if(is_requester_first)
+        {
+            // Init stage 1 arbiters
+            for(unsigned int i = 0; i < number_requesters; ++i)
+            {
+                ElectricalModel* arb = (ElectricalModel*)ModelGen::createModel(stage1_arbiter_model, "Stage1Arb" + (String)i, getTechModel());
+                arb->setParameter("NumberRequests", number_resources);
+                arb->construct();
+
+                addSubInstances(arb, 1.0);
+                addElectricalSubResults(arb, 1.0);
+
+                getEventResult("Allocate")->addSubResult(arb->getEventResult("Arbitrate"), arb->getInstanceName(), 1.0);
+
+                createNet("Stage1Arb_In" + (String)i, makeNetIndex(0, number_resources-1));
+                createNet("Stage1Arb_Out" + (String)i, makeNetIndex(0, number_resources-1));
+
+                portConnect(arb, "CK", "CK");
+                assign("Stage1Arb_In" + (String)i, "Request" + (String)i);
+                for(unsigned int j = 0; j < number_resources; ++j)
+                {
+                    portConnect(arb, "Request" + (String)j, "Stage1Arb_In" + (String)i, makeNetIndex(j));
+                    portConnect(arb, "Grant" + (String)j, "Stage1Arb_Out" + (String)i, makeNetIndex(j));
+                }
+            }
+
+            // Init stage 2 arbiters
+            for(unsigned int i = 0; i < number_resources; ++i)
+            {
+                ElectricalModel* arb = (ElectricalModel*)ModelGen::createModel(stage2_arbiter_model, "Stage2Arb" + (String)i, getTechModel());
+                arb->setParameter("NumberRequests", number_requesters);
+                arb->construct();
+
+                addSubInstances(arb, 1.0);
+                addElectricalSubResults(arb, 1.0);
+
+                getEventResult("Allocate")->addSubResult(arb->getEventResult("Arbitrate"), arb->getInstanceName(), 1.0);
+
+                createNet("Stage2Arb_In" + (String)i, makeNetIndex(0, number_requesters-1));
+                createNet("Stage2Arb_Out" + (String)i, makeNetIndex(0, number_requesters-1));
+
+                portConnect(arb, "CK", "CK");
+                for(unsigned int j = 0; j < number_requesters; ++j)
+                {
+                    assign("Stage2Arb_In" + (String)i, makeNetIndex(j), "Stage1Arb_Out" + (String)j, makeNetIndex(i));
+                    portConnect(arb, "Request" + (String)j, "Stage2Arb_In" + (String)i, makeNetIndex(j));
+                    portConnect(arb, "Grant" + (String)j, "Stage2Arb_Out" + (String)i, makeNetIndex(j));
+                    assign("Grant" + (String)j, makeNetIndex(i), "Stage2Arb_Out" + (String)i, makeNetIndex(j));
+                }
+            }
+        }
+        else
+        {
+            // Init stage 1 arbiters
+            for(unsigned int i = 0; i < number_resources; ++i)
+            {
+                ElectricalModel* arb = (ElectricalModel*)ModelGen::createModel(stage1_arbiter_model, "Stage1Arb" + (String)i, getTechModel());
+                arb->setParameter("NumberRequests", number_requesters);
+                arb->construct();
+
+                addSubInstances(arb, 1.0);
+                addElectricalSubResults(arb, 1.0);
+
+                getEventResult("Allocate")->addSubResult(arb->getEventResult("Arbitrate"), arb->getInstanceName(), 1.0);
+
+                createNet("Stage1Arb_In" + (String)i, makeNetIndex(0, number_requesters-1));
+                createNet("Stage1Arb_Out" + (String)i, makeNetIndex(0, number_requesters-1));
+
+                portConnect(arb, "CK", "CK");
+                for(unsigned int j = 0; j < number_requesters; ++j)
+                {
+                    assign("Stage1Arb_In" + (String)i, makeNetIndex(j), "Request" + (String)j, makeNetIndex(i));
+                    portConnect(arb, "Request" + (String)j, "Stage1Arb_In" + (String)i, makeNetIndex(j));
+                    portConnect(arb, "Grant" + (String)j, "Stage1Arb_Out" + (String)i, makeNetIndex(j));
+                }
+            }
+
+            // Init stage 2 arbiters
+            for(unsigned int i = 0; i < number_requesters; ++i)
+            {
+                ElectricalModel* arb = (ElectricalModel*)ModelGen::createModel(stage2_arbiter_model, "Stage2Arb" + (String)i, getTechModel());
+                arb->setParameter("NumberRequests", number_requesters);
+                arb->construct();
+
+                addSubInstances(arb, 1.0);
+                addElectricalSubResults(arb, 1.0);
+
+                getEventResult("Allocate")->addSubResult(arb->getEventResult("Arbitrate"), arb->getInstanceName(), 1.0);
+
+                createNet("Stage2Arb_In" + (String)i, makeNetIndex(0, number_resources-1));
+                createNet("Stage2Arb_Out" + (String)i, makeNetIndex(0, number_resources-1));
+
+                portConnect(arb, "CK", "CK");
+                for(unsigned int j = 0; j < number_resources; ++j)
+                {
+                    assign("Stage2Arb_In" + (String)i, makeNetIndex(j), "Stage1Arb_Out" + (String)j, makeNetIndex(i));
+                    portConnect(arb, "Request" + (String)j, "Stage2Arb_In", makeNetIndex(j));
+                    portConnect(arb, "Grant" + (String)j, "Stage2Arb_Out", makeNetIndex(j));
+                }
+                assign("Grant" + (String)i, "Stage2Arb_Out" + (String)i);
+            }
+        }
+        return;
+    }
+
+    void SeparableAllocator::updateModel()
+    {
+        // Get parameters
+        unsigned int number_requesters = getParameter("NumberRequesters").toUInt();
+        unsigned int number_resources = getParameter("NumberResources").toUInt();
+        bool is_requester_first = getParameter("IsRequesterFirst").toBool();
+
+        // Get probabilities from inputs
+        const String& P_request = getProperty("P(Request)");
+        const String& act_request = getProperty("Act(Request)");
+        const String& P_CK = getProperty("P(CK)");
+        const String& act_CK = getProperty("Act(CK)");
+
+        const vector<double>& P_request_vector = LibUtil::castStringVector<double>(P_request.split("[,]"));
+        const vector<double>& act_request_vector = LibUtil::castStringVector<double>(act_request.split("[,]"));
+
+        ASSERT(P_request_vector.size() == (number_requesters * number_resources), "[Error] " + getInstanceName() +
+                " -> Expecting " + (String)(number_requesters * number_resources) + 
+                " request probabilities, but got " + P_request);
+        ASSERT(act_request_vector.size() == (number_requesters * number_resources), "[Error] " + getInstanceName() +
+                " -> Expecting " + (String)(number_requesters * number_resources) + 
+                " request actvities multiplier, but got " + act_request);
+
+        vector<double> P_int_request_vector(number_requesters * number_resources, 0.0);
+        vector<double> act_int_request_vector(number_requesters * number_resources, 0.0);
+        vector<double> P_out_request_vector(number_requesters * number_resources, 0.0);
+        vector<double> act_out_request_vector(number_requesters * number_resources, 0.0);
+        if(is_requester_first)
+        {
+            // Update stage1 arbiter 
+            for(unsigned int i = 0; i < number_requesters; ++i)
+            {
+                vector<double> P_arb_request_vector(number_resources, 0.0);
+                vector<double> act_arb_request_vector(number_resources, 0.0);
+                for(unsigned int j = 0; j < number_resources; ++j)
+                {
+                    P_arb_request_vector[j] = P_request_vector[i * number_resources + j];
+                    act_arb_request_vector[j] = act_request_vector[i * number_resources + j];
+                }
+
+                Model* arb = getSubInstance("Stage1Arb" + (String)i);
+                arb->setProperty("P(Request)", LibUtil::vectorToString(P_arb_request_vector));
+                arb->setProperty("Act(Request)", LibUtil::vectorToString(act_arb_request_vector));
+                arb->setProperty("P(CK)", P_CK);
+                arb->setProperty("Act(CK)", act_CK);
+                arb->update();
+
+                const vector<double>& P_arb_out_request_vector = LibUtil::castStringVector<double>(arb->getGenProperties()->get("P(Grant)").split("[,]"));
+                const vector<double>& act_arb_out_request_vector = LibUtil::castStringVector<double>(arb->getGenProperties()->get("Act(Grant)").split("[,]"));
+                for(unsigned int j = 0; j < number_resources; ++j)
+                {
+                    P_int_request_vector[i * number_resources + j] = P_arb_out_request_vector[j];
+                    act_int_request_vector[i * number_resources + j] = act_arb_out_request_vector[j];
+                }
+            }
+            // Update stage2 arbiter
+            for(unsigned int i = 0; i < number_resources; ++i)
+            {
+                vector<double> P_arb_request_vector(number_requesters, 0.0);
+                vector<double> act_arb_request_vector(number_requesters, 0.0);
+                for(unsigned int j = 0; j < number_requesters; ++j)
+                {
+                    P_arb_request_vector[j] = P_int_request_vector[j * number_resources + i];
+                    act_arb_request_vector[j] = act_int_request_vector[j * number_resources + i];
+                }
+
+                Model* arb = getSubInstance("Stage2Arb" + (String)i);
+                arb->setProperty("P(Request)", LibUtil::vectorToString(P_arb_request_vector));
+                arb->setProperty("Act(Request)", LibUtil::vectorToString(act_arb_request_vector));
+                arb->setProperty("P(CK)", P_CK);
+                arb->setProperty("Act(CK)", act_CK);
+                arb->update();
+
+                const vector<double>& P_arb_out_request_vector = LibUtil::castStringVector<double>(arb->getGenProperties()->get("P(Grant)").split("[,]"));
+                const vector<double>& act_arb_out_request_vector = LibUtil::castStringVector<double>(arb->getGenProperties()->get("Act(Grant)").split("[,]"));
+                for(unsigned int j = 0; j < number_requesters; ++j)
+                {
+                    P_out_request_vector[j * number_resources + i] = P_arb_out_request_vector[j];
+                    act_out_request_vector[j * number_resources + i] = act_arb_out_request_vector[j];
+                }
+            }
+        }
+        else
+        {
+
+        }
+
+        // Update output probabilities
+        getGenProperties()->set("P(Grant)", LibUtil::vectorToString(P_out_request_vector));
+        getGenProperties()->set("Act(Grant)", LibUtil::vectorToString(act_out_request_vector));
+
+        return;
+    }
+} // namespace DSENT
+
diff --git a/ext/dsent/model/electrical/SeparableAllocator.h b/ext/dsent/model/electrical/SeparableAllocator.h
new file mode 100644 (file)
index 0000000..21519bf
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef __DSENT_MODEL_ELECTRICAL_SEPARABLE_ALLOCATOR_H__
+#define __DSENT_MODEL_ELECTRICAL_SEPARABLE_ALLOCATOR_H__
+
+#include "util/CommonType.h"
+#include "model/ElectricalModel.h"
+
+namespace DSENT
+{
+    class SeparableAllocator : public ElectricalModel
+    {
+        public:
+            SeparableAllocator(const String& instance_name_, const TechModel* tech_model_);
+            virtual ~SeparableAllocator();
+
+        public:
+            // Set a list of properties' name needed to construct model
+            void initParameters();
+            // Set a list of properties' name needed to construct model
+            void initProperties();
+
+            // Clone and return a new instance
+            virtual SeparableAllocator* clone() const;
+
+        protected:
+            // Build the model
+            virtual void constructModel();
+            virtual void updateModel();
+
+    }; // class SeparableAllocator
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_ELECTRICAL_SEPARABLE_ALLOCATOR_H__
+
diff --git a/ext/dsent/model/electrical/TestModel.cc b/ext/dsent/model/electrical/TestModel.cc
new file mode 100644 (file)
index 0000000..24f1fab
--- /dev/null
@@ -0,0 +1,218 @@
+#include "model/electrical/TestModel.h"
+
+#include <cmath>
+
+#include "model/std_cells/StdCell.h"
+#include "model/std_cells/StdCellLib.h"
+#include "model/electrical/RippleAdder.h"
+#include "model/electrical/Multiplexer.h"
+#include "model/timing_graph/ElectricalNet.h"
+#include "model/timing_graph/ElectricalDriver.h"
+#include "model/timing_graph/ElectricalLoad.h"
+#include "model/timing_graph/ElectricalTimingTree.h"
+
+namespace DSENT
+{
+    TestModel::TestModel(const String& instance_name_, const TechModel* tech_model_)
+        : ElectricalModel(instance_name_, tech_model_)
+    {
+        initProperties();
+    }
+
+    TestModel::~TestModel()
+    {}
+
+    void TestModel::initProperties()
+    {
+        return;
+    }
+
+    TestModel* TestModel::clone() const
+    {
+        return NULL;
+    }
+
+    void TestModel::constructModel()
+    {
+        unsigned int num_bits = 64;
+        unsigned int mux_bits = 1;
+    
+        // Create the instance        
+        createNet("CK");
+        createNet("CI");
+        getNet("CI")->setDistributedCap(100e-15);
+        getNet("CI")->setDistributedRes(10);
+        createNet("CO");
+        createNet("A", makeNetIndex(0, num_bits - 1));
+        createNet("B", makeNetIndex(0, num_bits - 1));
+        createNet("S", makeNetIndex(0, num_bits - 1));        
+        
+        StdCell* ci_reg = getTechModel()->getStdCellLib()->createStdCell("DFFQ", "DFFQ-CI");
+        ci_reg->setProperty("P(D)", 0.5);
+        ci_reg->setProperty("P(CK)", 0.5);
+        ci_reg->construct();
+        portConnect(ci_reg, "Q", "CI");
+        portConnect(ci_reg, "CK", "CK");
+        //ci_reg->connect("Q", getNet("CI"));
+        //ci_reg->connect("CK", getNet("CK"));
+        addSubInstances(ci_reg, 1.0);
+
+        StdCell* co_reg = getTechModel()->getStdCellLib()->createStdCell("DFFQ", "DFFQ-CO");
+        co_reg->setProperty("P(D)", 0.5);
+        co_reg->setProperty("P(CK)", 0.5);
+        co_reg->construct();
+        portConnect(co_reg, "D", "CO");
+        portConnect(co_reg, "CK", "CK");        
+        //co_reg->connect("D", getNet("CO"));
+        //co_reg->connect("CK", getNet("CK"));
+        addSubInstances(co_reg, 1.0);
+        
+        for (unsigned int i = 0; i < num_bits; i++)
+        {
+            StdCell* a_reg = getTechModel()->getStdCellLib()->createStdCell("DFFQ", "DFFQ-A[" + (String) i + "]");
+            a_reg->setProperty("P(D)", 0.5);
+            a_reg->setProperty("P(CK)", 0.5);
+            a_reg->construct();
+            portConnect(a_reg, "Q", "A", makeNetIndex(i));
+            portConnect(a_reg, "CK", "CK");
+            //a_reg->connect("Q", getNet("A[" + (String) i + "]"));
+            //a_reg->connect("CK", getNet("CK"));
+            addSubInstances(a_reg, 1.0);
+            
+            StdCell* b_reg = getTechModel()->getStdCellLib()->createStdCell("DFFQ", "DFFQ-B[" + (String) i + "]");
+            b_reg->setProperty("P(D)", 0.5);
+            b_reg->setProperty("P(CK)", 0.5);
+            b_reg->construct();
+            portConnect(b_reg, "Q", "B", makeNetIndex(i));
+            portConnect(b_reg, "CK", "CK");
+            //b_reg->connect("Q", getNet("B[" + (String) i + "]"));
+            //b_reg->connect("CK", getNet("CK"));
+            addSubInstances(b_reg, 1.0);
+
+            StdCell* s_reg = getTechModel()->getStdCellLib()->createStdCell("DFFQ", "DFFQ-S[" + (String) i + "]");
+            s_reg->setProperty("P(D)", 0.5);
+            s_reg->setProperty("P(CK)", 0.5);
+            s_reg->construct();
+            portConnect(s_reg, "D", "S", makeNetIndex(i));
+            portConnect(s_reg, "CK", "CK");
+            //s_reg->connect("D", getNet("A[" + (String) i + "]"));
+            //s_reg->connect("CK", getNet("CK"));
+            addSubInstances(s_reg, 1.0);
+        }
+        
+
+        //Create some adders!
+
+        ElectricalModel* ripple_adder = new RippleAdder("Adder_1", getTechModel());
+        ripple_adder->setParameter("NumberBits", num_bits);
+        ripple_adder->setProperty("P(A)", 0.5);
+        ripple_adder->setProperty("P(B)", 0.5);
+        ripple_adder->setProperty("P(CI)", 0.5);        
+        
+        ripple_adder->construct();
+        addSubInstances(ripple_adder, 1.0);
+        portConnect(ripple_adder, "CI", "CI");
+        portConnect(ripple_adder, "CO", "CO");
+        portConnect(ripple_adder, "A", "A");
+        portConnect(ripple_adder, "B", "B");
+        portConnect(ripple_adder, "S", "S");
+
+        ElectricalModel* multiplexer = new Multiplexer("Mux_1", getTechModel());
+        multiplexer->setParameter("NumberInputs", 2);
+        multiplexer->setParameter("NumberBits", mux_bits);
+        multiplexer->setParameter("BitDuplicate", "FALSE");
+        //multiplexer->setProperty("P(In)", "[0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5]");
+        //multiplexer->setProperty("P(Sel)", "[0.5, 0.5, 0.5]");
+        //multiplexer->setProperty("Act(In)", "[1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]");
+        //multiplexer->setProperty("Act(Sel)", "[2.0, 4.0, 8.0]");
+        multiplexer->setProperty("P(In)", "[0.5, 0.5]");
+        multiplexer->setProperty("P(Sel)", "[0.5]");
+        multiplexer->setProperty("Act(In)", "[1.0, 1.0]");
+        multiplexer->setProperty("Act(Sel)", "[1.0]");
+        multiplexer->construct();
+        
+        createNet("In0", makeNetIndex(0, mux_bits-1));
+        createNet("In1", makeNetIndex(0, mux_bits-1));
+        createNet("In2", makeNetIndex(0, mux_bits-1));
+        createNet("In3", makeNetIndex(0, mux_bits-1));
+        createNet("In4", makeNetIndex(0, mux_bits-1));
+        createNet("Out", makeNetIndex(0, mux_bits-1));
+        
+        portConnect(multiplexer, "In0", "In0");
+        portConnect(multiplexer, "In1", "In1");
+        //portConnect(multiplexer, "In2", "In2");
+        //portConnect(multiplexer, "In3", "In3");
+        //portConnect(multiplexer, "In4", "In4");
+        portConnect(multiplexer, "Out", "Out");
+        
+        for (unsigned int i = 0; i < mux_bits; ++i)
+        {
+            String n = (String) i;
+
+            createLoad("OutLoad[" + n + "]");
+            getLoad("OutLoad[" + n + "]")->setLoadCap(100e-15);
+
+            getNet("Out", makeNetIndex(i))->addDownstreamNode(getLoad("OutLoad[" + n + "]"));
+        }
+        createNet("Sel", makeNetIndex(0, 2));
+        assign("Sel", makeNetIndex(0), "CK");
+        assign("Sel", makeNetIndex(1), "CK");
+        assign("Sel", makeNetIndex(2), "CK");
+        
+        //portConnect(multiplexer, "Sel", "Sel");
+
+        addSubInstances(multiplexer, 1.0);
+
+        //ElectricalTimingAbstract* abstract = new ElectricalTimingAbstract("HAHAHA", getTechModel(), ripple_adder);
+        //abstract->buildAbstract();                    
+        
+        return;
+    }
+    
+    void TestModel::updateModel()
+    {
+        Model::updateModel();
+        
+        //ElectricalTimingTree* t = new ElectricalTimingTree("Add", this);
+        //t->performTimingOpt(getNet("CK"), 4.21300e-8);
+        //t->performTimingOpt(getNet("CK"), 1e-9);
+        //delete t;
+
+        ElectricalTimingTree* t2 = new ElectricalTimingTree("Mux", this);
+        t2->performTimingOpt(getNet("In1", makeNetIndex(0)), 500e-12);
+        delete t2;
+
+
+    }
+    
+    void TestModel::evaluateModel()
+    {
+        Model::evaluateModel();
+        
+        //ripple_adder->getNddPowerResult("LeakagePower")->print("RippleAdder->Leakage", 10, cout);
+        getSubInstance("Adder_1")->getNddPowerResult("Leakage")->print("RippleAdder->Leakage", 0, cout);
+        //ripple_adder->getAreaResult("TotalArea")->print("RippleAdder->TotalArea", 10, cout);
+        getSubInstance("Adder_1")->getAreaResult("Active")->print("RippleAdder->ActiveArea", 0, cout);
+        //ripple_adder->getEventResult("AddEvent")->print("RippleAdder->AddEvent", 10, cout);
+        getSubInstance("Adder_1")->getEventResult("Add")->print("RippleAdder->Add", 0, cout);
+
+        getSubInstance("Mux_1")->getNddPowerResult("Leakage")->print("Multiplexer->Leakage", 0, cout);
+        getSubInstance("Mux_1")->getAreaResult("Active")->print("Multiplexer->ActiveArea", 0, cout);
+        getSubInstance("Mux_1")->getEventResult("Mux")->print("Multiplexer->MuxEvent", 0, cout);
+        cout << "Multiplexer->P(Out) = " << getSubInstance("Mux_1")->getGenProperties()->get("P(Out)") << endl;
+
+        getSubInstance("DFFQ-CI")->getNddPowerResult("Leakage")->print("DFFQ-CI->Leakage", 0, cout);
+        getSubInstance("DFFQ-CI")->getAreaResult("Active")->print("DFFQ-CI->ActiveArea", 0, cout);
+        getSubInstance("DFFQ-CI")->getEventResult("DFF")->print("DFFQ-CI->DFF", 0, cout);
+        getSubInstance("DFFQ-CI")->getEventResult("CK")->print("DFFQ-CI->CK", 0, cout);
+        
+        //ripple_adder->getNddPowerResult("LeakagePower")->print("RippleAdder->Leakage", 10, cout);
+        getSubInstance("Adder_1")->getNddPowerResult("Leakage")->print("RippleAdder->Leakage", 0, cout);
+        //ripple_adder->getAreaResult("TotalArea")->print("RippleAdder->TotalArea", 10, cout);
+        getSubInstance("Adder_1")->getAreaResult("Active")->print("RippleAdder->ActiveArea", 0, cout);
+        //ripple_adder->getEventResult("AddEvent")->print("RippleAdder->AddEvent", 10, cout);
+        getSubInstance("Adder_1")->getEventResult("Add")->print("RippleAdder->AddEvent", 0, cout);
+    }
+    
+} // namespace DSENT
+
diff --git a/ext/dsent/model/electrical/TestModel.h b/ext/dsent/model/electrical/TestModel.h
new file mode 100644 (file)
index 0000000..5e07ea3
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef __DSENT_MODEL_ELECTRICAL_TESTMODEL_H__
+#define __DSENT_MODEL_ELECTRICAL_TESTMODEL_H__
+
+#include "util/CommonType.h"
+#include "model/ElectricalModel.h"
+
+namespace DSENT
+{
+    class TestModel : public ElectricalModel
+    {
+        public:
+            TestModel(const String& instance_name_, const TechModel* tech_model_);
+            virtual ~TestModel();
+
+        public:
+            // Set a list of properties' name needed to construct model
+            void initProperties();
+
+            // Clone and return a new instance
+            virtual TestModel* clone() const;
+
+        protected:
+            // Build the model
+            void constructModel();
+            void updateModel();
+            void evaluateModel();
+
+    }; // class TestModel
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_ELECTRICAL_TESTMODEL_H__
+
diff --git a/ext/dsent/model/electrical/router/Router.cc b/ext/dsent/model/electrical/router/Router.cc
new file mode 100644 (file)
index 0000000..c079bd1
--- /dev/null
@@ -0,0 +1,536 @@
+#include "model/electrical/router/Router.h"
+
+#include <cmath>
+#include <vector>
+
+#include "model/PortInfo.h"
+#include "model/EventInfo.h"
+#include "model/TransitionInfo.h"
+#include "model/ModelGen.h"
+#include "model/std_cells/StdCellLib.h"
+#include "model/std_cells/StdCell.h"
+#include "model/electrical/router/RouterInputPort.h"
+#include "model/electrical/router/RouterSwitchAllocator.h"
+#include "model/timing_graph/ElectricalNet.h"
+
+namespace DSENT
+{
+    using std::sqrt;
+    using std::vector;
+
+    using LibUtil::castStringVector;
+    using LibUtil::vectorToString;
+
+    Router::Router(const String& instance_name_, const TechModel* tech_model_)
+        : ElectricalModel(instance_name_, tech_model_)
+    {
+        initParameters();
+        initProperties();
+    }
+
+    Router::~Router()
+    {}
+
+    void Router::initParameters()
+    {
+        addParameterName("NumberInputPorts");
+        addParameterName("NumberOutputPorts");
+        addParameterName("NumberBitsPerFlit");
+        addParameterName("NumberVirtualNetworks");
+        addParameterName("NumberVirtualChannelsPerVirtualNetwork");
+        addParameterName("NumberBuffersPerVirtualChannel");
+        // Spec for input port
+        addParameterName("InputPort->BufferModel");
+        // Spec for crossbar
+        addParameterName("CrossbarModel");
+        // Spec for switch allocator
+        addParameterName("SwitchAllocator->ArbiterModel");
+        // Spec for clock tree
+        addParameterName("ClockTreeModel");
+        addParameterName("ClockTree->NumberLevels");
+        addParameterName("ClockTree->WireLayer");
+        addParameterName("ClockTree->WireWidthMultiplier");
+        addParameterName("ClockTree->WireSpacingMultiplier", 3.0);
+        return;
+    }
+
+    void Router::initProperties()
+    {
+        return;
+    }
+
+    Router* Router::clone() const
+    {
+        // TODO
+        return NULL;
+    }
+
+    void Router::constructModel()
+    {
+        // Get parameters
+        unsigned int number_input_ports = getParameter("NumberInputPorts").toUInt();
+        unsigned int number_output_ports = getParameter("NumberOutputPorts").toUInt();
+        unsigned int number_bits_per_flit = getParameter("NumberBitsPerFlit").toUInt();
+
+        ASSERT(number_input_ports > 0, "[Error] " + getInstanceName() + 
+                " -> Number of input ports must be > 0!");
+        ASSERT(number_output_ports > 0, "[Error] " + getInstanceName() + 
+                " -> Number of output ports must be > 0!");
+        ASSERT(number_bits_per_flit > 0, "[Error] " + getInstanceName() + 
+                " -> Number of bits per buffer must be > 0!");
+
+        // Create ports
+        createInputPort("CK");
+        for(unsigned int i = 0; i < number_input_ports; ++i)
+        {
+            createInputPort("FlitIn" + (String)i, makeNetIndex(0, number_bits_per_flit-1));
+        }
+        for(unsigned int i = 0; i < number_output_ports; ++i)
+        {
+            createOutputPort("FlitOut" + (String)i, makeNetIndex(0, number_bits_per_flit-1));
+        }
+
+        // Create area, power, event results
+        createElectricalResults();
+        getEventInfo("Idle")->setStaticTransitionInfos();
+        getEventInfo("Idle")->setTransitionInfo("CK", TransitionInfo(0.0, 1.0, 0.0));
+
+        createElectricalEventResult("ReadBuffer");
+        getEventInfo("ReadBuffer")->setTransitionInfo("CK", TransitionInfo(0.0, 1.0, 0.0));
+        createElectricalEventResult("WriteBuffer");
+        getEventInfo("WriteBuffer")->setTransitionInfo("CK", TransitionInfo(0.0, 1.0, 0.0));
+        for(unsigned int i = 1; i <= number_output_ports; ++i)
+        {
+            createElectricalEventResult("TraverseCrossbar->Multicast" + (String)i);
+            getEventInfo("TraverseCrossbar->Multicast" + (String)i)->setTransitionInfo("CK", TransitionInfo(0.0, 1.0, 0.0));
+        }
+        createElectricalEventResult("ArbitrateSwitch->ArbitrateStage1");
+        createElectricalEventResult("ArbitrateSwitch->ArbitrateStage2");
+        createElectricalEventResult("DistributeClock");
+        getEventInfo("DistributeClock")->setTransitionInfo("CK", TransitionInfo(0.0, 1.0, 0.0));
+
+        // Create intermediate nets
+        createNet("PipelineReg0_In");
+        createNet("PipelineReg0_Out");
+        createNet("PipelineReg1_In");
+        createNet("PipelineReg1_Out");
+        for(unsigned int i = 0; i < number_output_ports; ++i)
+        {
+            createNet("PipelineReg2_In" + (String)i);
+            createNet("PipelineReg2_Out" + (String)i);
+        }
+
+        createRouterInputPort();
+        createSwitchAllocator();
+        createVirtualChannelAllocator();
+        createCrossbar();
+        createClockTree();
+        createPipelineReg();
+
+        // Get generated numbers
+        unsigned int number_crossbar_selects = getGenProperties()->get("Crossbar->NumberSelects");
+
+        // Add write buffer event
+        getEventResult("WriteBuffer")->addSubResult(getSubInstance("PipelineReg0")->getEventResult("DFFD"), "PipelineReg0", number_bits_per_flit);
+        getEventResult("WriteBuffer")->addSubResult(getSubInstance("PipelineReg0")->getEventResult("DFFQ"), "PipelineReg0", number_bits_per_flit);
+        getEventResult("WriteBuffer")->addSubResult(getSubInstance("PipelineReg0")->getEventResult("CK"), "PipelineReg0", number_bits_per_flit);
+        getEventResult("WriteBuffer")->addSubResult(getSubInstance("InputPort")->getEventResult("WriteBuffer"), "InputPort", 1.0);
+
+        // Add read buffer event
+        getEventResult("ReadBuffer")->addSubResult(getSubInstance("InputPort")->getEventResult("ReadBuffer"), "InputPort", 1.0);
+        getEventResult("ReadBuffer")->addSubResult(getSubInstance("PipelineReg1")->getEventResult("DFFD"), "PipelineReg1", number_bits_per_flit);
+        getEventResult("ReadBuffer")->addSubResult(getSubInstance("PipelineReg1")->getEventResult("DFFQ"), "PipelineReg1", number_bits_per_flit);
+        getEventResult("ReadBuffer")->addSubResult(getSubInstance("PipelineReg1")->getEventResult("CK"), "PipelineReg1", number_bits_per_flit);
+
+        // Add crossbar traversal event
+        for(unsigned int i = 1; i <= number_output_ports; ++i)
+        {
+            Result* traverse_crossbar_event = getEventResult("TraverseCrossbar->Multicast" + (String)i);
+            traverse_crossbar_event->addSubResult(getSubInstance("Crossbar_Sel_DFF")->getEventResult("DFFD"), "Crossbar_Sel_DFF", number_crossbar_selects);
+            traverse_crossbar_event->addSubResult(getSubInstance("Crossbar_Sel_DFF")->getEventResult("DFFQ"), "Crossbar_Sel_DFF", number_crossbar_selects);
+            traverse_crossbar_event->addSubResult(getSubInstance("Crossbar_Sel_DFF")->getEventResult("CK"), "Crossbar_Sel_DFF", number_crossbar_selects);
+            traverse_crossbar_event->addSubResult(getSubInstance("Crossbar")->getEventResult("Multicast" + (String)i), "Crossbar", 1.0);
+            for(unsigned int j = 0; j < i; ++j)
+            {
+                traverse_crossbar_event->addSubResult(getSubInstance("PipelineReg2_" + (String)j)->getEventResult("DFFD"), "PipelineReg2_" + (String)j, number_bits_per_flit);
+                traverse_crossbar_event->addSubResult(getSubInstance("PipelineReg2_" + (String)j)->getEventResult("DFFQ"), "PipelineReg2_" + (String)j, number_bits_per_flit);
+                traverse_crossbar_event->addSubResult(getSubInstance("PipelineReg2_" + (String)j)->getEventResult("CK"), "PipelineReg2_" + (String)j, number_bits_per_flit);
+            }
+        }
+
+        // Add stage1 allocator arbitrate
+        Result* arb_sw_stage1_event = getEventResult("ArbitrateSwitch->ArbitrateStage1");
+        arb_sw_stage1_event->addSubResult(getSubInstance("SwitchAllocator")->getEventResult("ArbitrateStage1"), "SwitchAllocator", 1.0);
+
+        // Add stage2 allocator arbitrate
+        Result* arb_sw_stage2_event = getEventResult("ArbitrateSwitch->ArbitrateStage2");
+        arb_sw_stage2_event->addSubResult(getSubInstance("SwitchAllocator")->getEventResult("ArbitrateStage2"), "SwitchAllocator", 1.0);
+
+        // Add CK event
+        getEventResult("DistributeClock")->addSubResult(getSubInstance("ClockTree")->getEventResult("Send"), "ClockTree", 1.0);
+        return;
+    }
+
+    void Router::updateModel()
+    {
+        // Get parameters
+        unsigned int number_output_ports = getParameter("NumberOutputPorts").toUInt();
+
+        // Update other components
+        getSubInstance("PipelineReg0")->update();
+        getSubInstance("InputPort")->update();
+        getSubInstance("PipelineReg1")->update();
+        getSubInstance("Crossbar_Sel_DFF")->update();
+        getSubInstance("Crossbar")->update();
+        for(unsigned int i = 0; i < number_output_ports; ++i)
+        {
+            getSubInstance("PipelineReg2_" + (String)i)->update();
+        }
+        getSubInstance("SwitchAllocator")->update();
+
+        // Update clock tree
+        double total_clock_tree_cap = getNet("CK")->getTotalDownstreamCap();
+        double router_area = getAreaResult("Active")->calculateSum();
+        Model* clock_tree = getSubInstance("ClockTree");
+        clock_tree->setProperty("SitePitch", sqrt(router_area));
+        clock_tree->setProperty("TotalLoadCapPerBit", total_clock_tree_cap);
+        clock_tree->update();
+
+        return;
+    }
+
+    void Router::propagateTransitionInfo()
+    {
+        // Update probability
+        unsigned int number_output_ports = getParameter("NumberOutputPorts");
+
+        // Current event
+        const String& current_event = getGenProperties()->get("UseModelEvent");
+
+        ElectricalModel* pipeline_reg0 = (ElectricalModel*)getSubInstance("PipelineReg0");
+        propagatePortTransitionInfo(pipeline_reg0, "D", "FlitIn0");
+        propagatePortTransitionInfo(pipeline_reg0, "CK", "CK");
+        pipeline_reg0->use();
+
+        ElectricalModel* input_port = (ElectricalModel*)getSubInstance("InputPort");
+        propagatePortTransitionInfo(input_port, "FlitIn", pipeline_reg0, "Q");
+        propagatePortTransitionInfo(input_port, "CK", "CK");
+        input_port->getGenProperties()->set("UseModelEvent", "ReadWrite");
+        input_port->use();
+
+        ElectricalModel* pipeline_reg1 = (ElectricalModel*)getSubInstance("PipelineReg1");
+        propagatePortTransitionInfo(pipeline_reg1, "D", "FlitIn0");
+        propagatePortTransitionInfo(pipeline_reg1, "CK", "CK");
+        pipeline_reg1->use();
+
+        ElectricalModel* crossbar_sel_dff = (ElectricalModel*)getSubInstance("Crossbar_Sel_DFF");
+        assignPortTransitionInfo(crossbar_sel_dff, "D", TransitionInfo());
+        propagatePortTransitionInfo(crossbar_sel_dff, "CK", "CK");
+        crossbar_sel_dff->use();
+
+        ElectricalModel* crossbar = (ElectricalModel*)getSubInstance("Crossbar");
+        bool is_crossbar_event = false;
+        for(unsigned int i = 1; i <= number_output_ports; ++i)
+        {
+            if(current_event == ("TraverseCrossbar->Multicast" + (String)i))
+            {
+                is_crossbar_event = true;
+                // Assume the flit is sent from port 0 to port 0~i-1
+                // Apply default transition info
+                crossbar->applyTransitionInfo("Multicast" + (String)i);
+                // Overwrite transition info
+                propagatePortTransitionInfo(crossbar, "In0", "FlitIn0");
+                break;
+            }
+        }
+        if(is_crossbar_event == false)
+        {
+            crossbar->applyTransitionInfo("Multicast1");
+            propagatePortTransitionInfo(crossbar, "In0", "FlitIn0");
+        }
+        crossbar->use();
+
+        vector<ElectricalModel*> pipeline_reg2s(number_output_ports, NULL);
+        for(unsigned int i = 0; i < number_output_ports; ++i)
+        {
+            pipeline_reg2s[i] = (ElectricalModel*)getSubInstance("PipelineReg2_" + (String)i);
+            propagatePortTransitionInfo(pipeline_reg2s[i], "D", "FlitIn0");
+            propagatePortTransitionInfo(pipeline_reg2s[i], "CK", "CK");
+            pipeline_reg2s[i]->use();
+        }
+
+        ElectricalModel* sw_allocator = (ElectricalModel*)getSubInstance("SwitchAllocator");
+        if(current_event == "ArbitrateSwitch->ArbitrateStage1")
+        {
+            sw_allocator->applyTransitionInfo("ArbitrateStage1");
+        }
+        else if(current_event == "ArbitrateSwitch->ArbitrateStage2")
+        {
+            sw_allocator->applyTransitionInfo("ArbitrateStage2");
+        }
+        else
+        {
+            sw_allocator->applyTransitionInfo("Idle");
+        }
+        sw_allocator->use();
+
+        ElectricalModel* clock_tree = (ElectricalModel*)getSubInstance("ClockTree");
+        propagatePortTransitionInfo(clock_tree, "In", "CK");
+        clock_tree->use();
+        return;
+    }
+
+    void Router::createRouterInputPort()
+    {
+        // Get parameters
+        unsigned int number_input_ports = getParameter("NumberInputPorts").toUInt();
+        unsigned int number_vns = getParameter("NumberVirtualNetworks").toUInt();
+        const String& number_vcs_per_vn = getParameter("NumberVirtualChannelsPerVirtualNetwork");
+        const String& number_bufs_per_vc = getParameter("NumberBuffersPerVirtualChannel");
+        unsigned int number_bits_per_flit = getParameter("NumberBitsPerFlit").toUInt();
+        const String& buffer_model = getParameter("InputPort->BufferModel");
+
+        // Init input port model
+        const String& input_port_name = "InputPort";
+        RouterInputPort* input_port = new RouterInputPort(input_port_name, getTechModel());
+        input_port->setParameter("NumberVirtualNetworks", number_vns);
+        input_port->setParameter("NumberVirtualChannelsPerVirtualNetwork", number_vcs_per_vn);
+        input_port->setParameter("NumberBuffersPerVirtualChannel", number_bufs_per_vc);
+        input_port->setParameter("NumberBitsPerFlit", number_bits_per_flit);
+        input_port->setParameter("BufferModel", buffer_model);
+        input_port->construct();
+
+        unsigned int number_input_port_outputs = input_port->getGenProperties()->get("NumberOutputs");
+        unsigned int number_input_port_addr_bits = input_port->getGenProperties()->get("NumberAddressBits");
+        getGenProperties()->set("InputPort->NumberOutputs", number_input_port_outputs);
+        getGenProperties()->set("InputPort->NumberAddressBits", number_input_port_addr_bits);
+
+        unsigned int total_number_vcs = input_port->getGenProperties()->get("TotalNumberVirtualChannels");
+        getGenProperties()->set("TotalNumberVirtualChannels", total_number_vcs);
+
+        // Add the instance and the results
+        addSubInstances(input_port, number_input_ports);
+        addElectricalSubResults(input_port, number_input_ports);
+
+        // Create connections
+        createNet("InputPort_In", makeNetIndex(0, number_bits_per_flit-1));
+        createNet("InputPort_Out", makeNetIndex(0, number_bits_per_flit-1));
+
+        assignVirtualFanout("InputPort_In", "PipelineReg0_Out");
+        portConnect(input_port, "FlitIn", "InputPort_In");
+        portConnect(input_port, "CK", "CK");
+        portConnect(input_port, "FlitOut", "InputPort_Out");
+        assignVirtualFanin("PipelineReg1_In", "InputPort_Out");
+
+        return;
+    }
+
+    void Router::createVirtualChannelAllocator()
+    {}
+
+    void Router::createSwitchAllocator()
+    {
+        // Get parameters
+        unsigned int number_input_ports = getParameter("NumberInputPorts").toUInt();
+        unsigned int number_output_ports = getParameter("NumberOutputPorts").toUInt();
+        unsigned int total_number_vcs = getGenProperties()->get("TotalNumberVirtualChannels").toUInt();
+        const String& arb_model = getParameter("SwitchAllocator->ArbiterModel");
+
+        // Init switch allocator model
+        const String& sw_allocator_name = "SwitchAllocator";
+        RouterSwitchAllocator* sw_allocator = new RouterSwitchAllocator(sw_allocator_name, getTechModel());
+        sw_allocator->setParameter("NumberInputPorts", number_input_ports);
+        sw_allocator->setParameter("NumberOutputPorts", number_output_ports);
+        sw_allocator->setParameter("TotalNumberVirtualChannels", total_number_vcs);
+        sw_allocator->setParameter("ArbiterModel", arb_model);
+        sw_allocator->construct();
+
+        // Add the instance and the results
+        addSubInstances(sw_allocator, 1.0);
+        addElectricalSubResults(sw_allocator, 1.0);
+
+        // Create connections (currently connect CK only)
+        portConnect(sw_allocator, "CK", "CK");
+        return;
+    }
+
+    void Router::createCrossbar()
+    {
+        // Get parameters
+        const String& crossbar_model = getParameter("CrossbarModel");
+        unsigned int number_input_ports = getParameter("NumberInputPorts").toUInt();
+        unsigned int number_output_ports = getParameter("NumberOutputPorts").toUInt();
+        unsigned int number_bits_per_flit = getParameter("NumberBitsPerFlit").toUInt();
+        unsigned int number_input_port_outputs = getGenProperties()->get("InputPort->NumberOutputs").toUInt();
+
+        unsigned int number_crossbar_inputs = number_input_port_outputs * number_input_ports;
+        unsigned int number_crossbar_outputs = number_output_ports;
+        getGenProperties()->set("Crossbar->NumberInputs", number_crossbar_inputs);
+        getGenProperties()->set("Crossbar->NumberOutputs", number_crossbar_outputs);
+
+        // Init crossbar model
+        const String& crossbar_name = "Crossbar";
+        ElectricalModel* crossbar = ModelGen::createCrossbar(crossbar_model, crossbar_name, getTechModel());
+        crossbar->setParameter("NumberInputs", number_crossbar_inputs);
+        crossbar->setParameter("NumberOutputs", number_crossbar_outputs);
+        crossbar->setParameter("NumberBits", number_bits_per_flit);
+        crossbar->setParameter("BitDuplicate", "TRUE");
+        crossbar->construct();
+
+        unsigned int number_crossbar_selects = crossbar->getGenProperties()->get("NumberSelectsPerPort");
+        getGenProperties()->set("Crossbar->NumberSelects", number_crossbar_selects);
+
+        // Init DFF for crossbar selections
+        const String& crossbar_sel_dff_name = "Crossbar_Sel_DFF";
+        StdCell* crossbar_sel_dff = getTechModel()->getStdCellLib()->createStdCell("DFFQ", crossbar_sel_dff_name);
+        crossbar_sel_dff->construct();
+
+        // Add instances and results
+        addSubInstances(crossbar, 1.0);
+        addElectricalSubResults(crossbar, 1.0);
+
+        addSubInstances(crossbar_sel_dff, number_crossbar_outputs * number_crossbar_selects);
+        addElectricalSubResults(crossbar_sel_dff, number_crossbar_outputs * number_crossbar_selects);
+
+        // Create connections
+        createNet("Crossbar_Sel_DFF_Out");
+        for(unsigned int i = 0; i < number_crossbar_outputs; ++i)
+        {
+            for(unsigned int j = 0; j < number_crossbar_selects; ++j)
+            {
+                createNet(String::format("Crossbar_Sel%d_%d", i, j));
+            }
+            createNet("Crossbar_Out" + (String)i, makeNetIndex(0, number_bits_per_flit-1));
+        }
+        for(unsigned int i = 0; i < number_crossbar_inputs; ++i)
+        {
+            createNet("Crossbar_In" + (String)i, makeNetIndex(0, number_bits_per_flit-1));
+        }
+
+        for(unsigned int i = 0; i < number_crossbar_selects; ++i)
+        {
+            portConnect(crossbar_sel_dff, "CK", "CK");
+        }
+        portConnect(crossbar_sel_dff, "Q", "Crossbar_Sel_DFF_Out");
+        for(unsigned int i = 0; i < number_crossbar_inputs; ++i)
+        {
+            assignVirtualFanout("Crossbar_In" + (String)i, "PipelineReg1_Out");
+            portConnect(crossbar, "In" + (String)i, "Crossbar_In" + (String)i);
+        }
+        for(unsigned int i = 0; i < number_crossbar_outputs; ++i)
+        {
+            for(unsigned int j = 0; j < number_crossbar_selects; ++j)
+            {
+                assignVirtualFanout(String::format("Crossbar_Sel%d_%d", i, j), "Crossbar_Sel_DFF_Out");
+                portConnect(crossbar, String::format("Sel%d_%d", i, j), String::format("Crossbar_Sel%d_%d", i, j));
+            }
+            portConnect(crossbar, "Out" + (String)i, "Crossbar_Out" + (String)i);
+            assignVirtualFanin("PipelineReg2_In" + (String)i, "Crossbar_Out" + (String)i);
+        }
+
+        return;
+    }
+
+    void Router::createPipelineReg()
+    {
+        // Get parameters
+        unsigned int number_input_ports = getParameter("NumberInputPorts").toUInt();
+        unsigned int number_output_ports = getParameter("NumberOutputPorts").toUInt();
+        unsigned int number_bits_per_flit = getParameter("NumberBitsPerFlit").toUInt();
+        unsigned int number_crossbar_inputs = getGenProperties()->get("Crossbar->NumberInputs");
+
+        // Init pipeline reg model
+        // First stage: from router input to input port
+        const String& pipeline_reg0_name = "PipelineReg0";
+        StdCell* pipeline_reg0 = getTechModel()->getStdCellLib()->createStdCell("DFFQ", pipeline_reg0_name);
+        pipeline_reg0->construct();
+        // Second stage: from input port to crossbar
+        const String& pipeline_reg1_name = "PipelineReg1";
+        StdCell* pipeline_reg1 = getTechModel()->getStdCellLib()->createStdCell("DFFQ", pipeline_reg1_name);
+        pipeline_reg1->construct();
+
+        // Third stage: from crossbar to router output
+        vector<StdCell*> pipeline_reg2s(number_output_ports, (StdCell*)NULL);
+        vector<String> pipeline_reg2_names(number_output_ports, "");
+        for(unsigned int i = 0; i < number_output_ports; ++i)
+        {
+            pipeline_reg2_names[i] = "PipelineReg2_" + (String)i;
+            pipeline_reg2s[i] = getTechModel()->getStdCellLib()->createStdCell("DFFQ", pipeline_reg2_names[i]);
+            pipeline_reg2s[i]->construct();
+        }
+
+        // Add instances and results
+        addSubInstances(pipeline_reg0, number_input_ports * number_bits_per_flit);
+        addElectricalSubResults(pipeline_reg0, number_input_ports * number_bits_per_flit);
+
+        addSubInstances(pipeline_reg1, number_crossbar_inputs * number_bits_per_flit);
+        addElectricalSubResults(pipeline_reg1, number_crossbar_inputs * number_bits_per_flit);
+
+        for(unsigned int i = 0; i < number_output_ports; ++i)
+        {
+            addSubInstances(pipeline_reg2s[i], number_bits_per_flit);
+            addElectricalSubResults(pipeline_reg2s[i], number_bits_per_flit);
+        }
+
+        // Create data connections
+        for(unsigned int i = 0; i < number_input_ports; ++i)
+        {
+            assignVirtualFanin("PipelineReg0_In", "FlitIn" + (String)i);
+        }
+        portConnect(pipeline_reg0, "D", "PipelineReg0_In");
+        portConnect(pipeline_reg0, "Q", "PipelineReg0_Out");
+        portConnect(pipeline_reg1, "D", "PipelineReg1_In");
+        portConnect(pipeline_reg1, "Q", "PipelineReg1_Out");
+        for(unsigned int i = 0; i < number_output_ports; ++i)
+        {
+            portConnect(pipeline_reg2s[i], "D", "PipelineReg2_In" + (String)i);
+            portConnect(pipeline_reg2s[i], "Q", "PipelineReg2_Out" + (String)i);
+            assignVirtualFanout("FlitOut" + (String)i, "PipelineReg2_Out" + (String)i);
+        }
+
+        // Create CK connections
+        for(unsigned int n = 0; n < number_bits_per_flit; ++n)
+        {
+            for(unsigned int i = 0; i < number_input_ports; ++i)
+            {
+                portConnect(pipeline_reg0, "CK", "CK");
+            }
+            for(unsigned int i = 0; i < number_crossbar_inputs; ++i)
+            {
+                portConnect(pipeline_reg1, "CK", "CK");
+            }
+            for(unsigned int i = 0; i < number_output_ports; ++i)
+            {
+                portConnect(pipeline_reg2s[i], "CK", "CK");
+            }
+        }
+        return;
+    }
+
+    void Router::createClockTree()
+    {
+        // Get parameters
+        const String& clock_tree_model = getParameter("ClockTreeModel");
+        const String& clock_tree_number_levels = getParameter("ClockTree->NumberLevels");
+        const String& clock_tree_wire_layer = getParameter("ClockTree->WireLayer");
+        const String& clock_tree_wire_width_multiplier = getParameter("ClockTree->WireWidthMultiplier");
+        const String& clock_tree_wire_spacing_multiplier = getParameter("ClockTree->WireSpacingMultiplier");
+
+        // Init clock tree model
+        const String& clock_tree_name = "ClockTree";
+        ElectricalModel* clock_tree = (ElectricalModel*)ModelGen::createModel(clock_tree_model, clock_tree_name, getTechModel());
+        clock_tree->setParameter("NumberLevels", clock_tree_number_levels);
+        clock_tree->setParameter("NumberBits", 1);
+        clock_tree->setParameter("WireLayer", clock_tree_wire_layer);
+        clock_tree->setParameter("WireWidthMultiplier", clock_tree_wire_width_multiplier);
+        clock_tree->setParameter("WireSpacingMultiplier", clock_tree_wire_spacing_multiplier);
+        clock_tree->construct();
+
+        // Add instances and results
+        addSubInstances(clock_tree, 1.0);
+        addElectricalSubResults(clock_tree, 1.0);
+
+        return;
+    }
+} // namespace DSENT
+
diff --git a/ext/dsent/model/electrical/router/Router.h b/ext/dsent/model/electrical/router/Router.h
new file mode 100644 (file)
index 0000000..c2c1df3
--- /dev/null
@@ -0,0 +1,46 @@
+#ifndef __DSENT_MODEL_ELECTRICAL_ROUTER_ROUTER_H__
+#define __DSENT_MODEL_ELECTRICAL_ROUTER_ROUTER_H__
+
+#include "util/CommonType.h"
+#include "model/ElectricalModel.h"
+
+namespace DSENT
+{
+    /** \class Router
+     * \param Input ports: In[0-9]*
+     * \param Output ports: Out[0-9]*
+     */
+    class Router : public ElectricalModel
+    {
+        public:
+            Router(const String& instance_name_, const TechModel* tech_model_);
+            virtual ~Router();
+
+        public:
+            // Set a list of properties' name needed to construct model
+            void initParameters();
+            // Set a list of properties' name needed to construct model
+            void initProperties();
+
+            // Clone and return a new instance
+            virtual Router* clone() const;
+
+        protected:
+            // Build the model
+            virtual void constructModel();
+            virtual void updateModel();
+            virtual void propagateTransitionInfo();
+
+        private:
+            void createRouterInputPort();
+            void createVirtualChannelAllocator();
+            void createSwitchAllocator();
+            void createCrossbar();
+            void createClockTree();
+            void createPipelineReg();
+
+    }; // class Router
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_ELECTRICAL_ROUTER_ROUTER_H__
+
diff --git a/ext/dsent/model/electrical/router/RouterInputPort.cc b/ext/dsent/model/electrical/router/RouterInputPort.cc
new file mode 100644 (file)
index 0000000..b698d3d
--- /dev/null
@@ -0,0 +1,201 @@
+#include "model/electrical/router/RouterInputPort.h"
+
+#include <cmath>
+#include <vector>
+
+#include "model/PortInfo.h"
+#include "model/EventInfo.h"
+#include "model/TransitionInfo.h"
+#include "model/ModelGen.h"
+#include "model/std_cells/StdCellLib.h"
+#include "model/std_cells/StdCell.h"
+
+namespace DSENT
+{
+    using std::ceil;
+    using std::vector;
+    using LibUtil::castStringVector;
+
+    RouterInputPort::RouterInputPort(const String& instance_name_, const TechModel* tech_model_)
+        : ElectricalModel(instance_name_, tech_model_)
+    {
+        initParameters();
+        initProperties();
+    }
+
+    RouterInputPort::~RouterInputPort()
+    {}
+
+    void RouterInputPort::initParameters()
+    {
+        addParameterName("NumberVirtualNetworks");
+        addParameterName("NumberVirtualChannelsPerVirtualNetwork");
+        addParameterName("NumberBuffersPerVirtualChannel");
+        addParameterName("NumberBitsPerFlit");
+        addParameterName("BufferModel");
+        return;
+    }
+
+    void RouterInputPort::initProperties()
+    {
+        return;
+    }
+
+    RouterInputPort* RouterInputPort::clone() const
+    {
+        // TODO 
+        return NULL;
+    }
+
+    void RouterInputPort::constructModel()
+    {
+        // Get parameters
+        unsigned int number_vns = getParameter("NumberVirtualNetworks").toUInt();
+        const vector<unsigned int>& number_vcs_per_vn_vector = castStringVector<unsigned int>(getParameter("NumberVirtualChannelsPerVirtualNetwork").split("[,]"));
+        const vector<unsigned int>& number_bufs_per_vc_vector = castStringVector<unsigned int>(getParameter("NumberBuffersPerVirtualChannel").split("[,]"));
+        unsigned int number_bits_per_flit = getParameter("NumberBitsPerFlit").toUInt();
+        const String& buffer_model = getParameter("BufferModel");
+
+        ASSERT(number_vns > 0, "[Error] " + getInstanceName() + 
+            " -> Number of virtual networks must be > 0!");
+        ASSERT(number_vcs_per_vn_vector.size() == number_vns, "[Error] " + getInstanceName() + 
+            " -> Expecting " + (String)number_vns + " number of vcs, got " + 
+            getParameter("NumberVirtualChannelsPerVirtualNetwork"));
+        for(unsigned int i = 0; i < number_vns; ++i)
+        {
+            ASSERT(number_vcs_per_vn_vector[i] > 0, "[Error] " + getInstanceName() + 
+                " -> Number of virtual channels per virtual network must be > 0!");
+        }
+        ASSERT(number_bufs_per_vc_vector.size() == number_vns, "[Error] " + getInstanceName() + 
+            " -> Expecting " + (String)number_vns + " number of bufs per vc, got " + 
+            getParameter("NumberBuffersPerVirtualChannel"));
+        for(unsigned int i = 0; i < number_vns; ++i)
+        {
+            ASSERT(number_bufs_per_vc_vector[i] > 0, "[Error] " + getInstanceName() + 
+                " -> Number of buffers per virtual channel must be > 0!");
+        }
+        ASSERT(number_bits_per_flit > 0, "[Error] " + getInstanceName() + 
+            " -> Number of bits per buffer must be > 0!");
+
+        // Calculate total number of buffers needed in the RAM
+        unsigned int total_number_vcs = 0;
+        unsigned int total_number_bufs = 0;
+        for(unsigned int i = 0; i < number_vns; ++i)
+        {
+            total_number_vcs += number_vcs_per_vn_vector[i];
+            total_number_bufs += number_vcs_per_vn_vector[i] * number_bufs_per_vc_vector[i];
+        }
+        unsigned int number_addr_bits = (unsigned int)ceil(log2(total_number_bufs));
+
+        getGenProperties()->set("TotalNumberVirtualChannels", total_number_vcs);
+        getGenProperties()->set("TotalNumberBuffers", total_number_bufs);
+        getGenProperties()->set("NumberAddressBits", number_addr_bits);
+        getGenProperties()->set("NumberOutputs", 1);
+
+        createInputPort("CK");
+        createInputPort("FlitIn", makeNetIndex(0, number_bits_per_flit-1));
+        createOutputPort("FlitOut", makeNetIndex(0, number_bits_per_flit-1));
+
+        // Create energy, power, and area results
+        createElectricalResults();
+        getEventInfo("Idle")->setStaticTransitionInfos();
+        getEventInfo("Idle")->setTransitionInfo("CK", TransitionInfo(0.0, 1.0, 0.0));
+
+        addEventResult(new Result("ReadBuffer"));
+        addEventResult(new Result("WriteBuffer"));
+
+        // Init RAM
+        const String& ram_name = "RAM";
+        ElectricalModel* ram = ModelGen::createRAM(buffer_model, ram_name, getTechModel());
+        ram->setParameter("NumberEntries", total_number_bufs);
+        ram->setParameter("NumberBits", number_bits_per_flit);
+        ram->construct();
+
+        // Init DFF for read address
+        vector<String> rd_addr_dff_names(number_addr_bits, "");
+        vector<StdCell*> rd_addr_dffs(number_addr_bits, NULL);
+        for(unsigned int i = 0; i < number_addr_bits; ++i)
+        {
+            rd_addr_dff_names[i] = "RDAddr_DFF" + (String)i;
+            rd_addr_dffs[i] = getTechModel()->getStdCellLib()->createStdCell("DFFQ", rd_addr_dff_names[i]);
+            rd_addr_dffs[i]->construct();
+        }
+
+        // Connect RDAddr_DFFs
+        for(unsigned int i = 0; i < number_addr_bits; ++i)
+        {
+            createNet("RDAddr_DFF_Out" + (String)i);
+
+            portConnect(rd_addr_dffs[i], "CK", "CK");
+            portConnect(rd_addr_dffs[i], "Q", "RDAddr_DFF_Out" + (String)i);
+        }
+
+        // Connect RAM
+        portConnect(ram, "In", "FlitIn");
+        for(unsigned int i = 0; i < number_addr_bits; ++i)
+        {
+            portConnect(ram, "WRAddr" + (String)i, "FlitIn", makeNetIndex(i));
+            portConnect(ram, "RDAddr" + (String)i, "RDAddr_DFF_Out" + (String)i);
+        }
+        portConnect(ram, "WE", "FlitIn", makeNetIndex(number_bits_per_flit-1));
+        portConnect(ram, "CK", "CK");
+        portConnect(ram, "Out", "FlitOut");
+
+        // Add area, power, event results 
+        for(unsigned int i = 0; i < number_addr_bits; ++i)
+        {
+            addSubInstances(rd_addr_dffs[i], number_addr_bits);
+            addElectricalSubResults(rd_addr_dffs[i], number_addr_bits);
+        }
+        addSubInstances(ram, 1.0);
+        addElectricalSubResults(ram, 1.0);
+
+        getEventResult("WriteBuffer")->addSubResult(ram->getEventResult("Write"), ram_name, 1.0);
+
+        for(unsigned int i = 0; i < number_addr_bits; ++i)
+        {
+            getEventResult("ReadBuffer")->addSubResult(rd_addr_dffs[i]->getEventResult("DFFD"), rd_addr_dff_names[i], number_addr_bits);
+            getEventResult("ReadBuffer")->addSubResult(rd_addr_dffs[i]->getEventResult("DFFQ"), rd_addr_dff_names[i], number_addr_bits);
+            getEventResult("ReadBuffer")->addSubResult(rd_addr_dffs[i]->getEventResult("CK"), rd_addr_dff_names[i], number_addr_bits);
+        }
+        getEventResult("ReadBuffer")->addSubResult(ram->getEventResult("Read"), ram_name, 1.0);
+
+        return;
+    }
+
+    void RouterInputPort::propagateTransitionInfo()
+    {
+        // Update probability and activity
+        unsigned int number_addr_bits = getGenProperties()->get("NumberAddressBits").toUInt();
+
+        vector<ElectricalModel*> rd_addr_dffs(number_addr_bits, NULL);
+        for(unsigned int i = 0; i < number_addr_bits; ++i)
+        {
+            rd_addr_dffs[i] = (ElectricalModel*)getSubInstance("RDAddr_DFF" + (String)i);
+            assignPortTransitionInfo(rd_addr_dffs[i], "D", TransitionInfo());
+            propagatePortTransitionInfo(rd_addr_dffs[i], "CK", "CK");
+            rd_addr_dffs[i]->use();
+        }
+
+        ElectricalModel* ram = (ElectricalModel*)getSubInstance("RAM");
+
+        // Setup default transition info
+        const String& current_event = getGenProperties()->get("UseModelEvent");
+        if(current_event != "Idle")
+        {
+            propagatePortTransitionInfo(ram, "In", "FlitIn");
+            propagatePortTransitionInfo(ram, "CK", "CK");
+            assignPortTransitionInfo(ram, "WE", TransitionInfo(0.0, 0.0, 1.0));
+            for(unsigned int i = 0; i < number_addr_bits; ++i)
+            {
+                assignPortTransitionInfo(ram, "WRAddr" + (String)i, TransitionInfo(0.25, 0.25, 0.25));
+                assignPortTransitionInfo(ram, "RDAddr" + (String)i, TransitionInfo(0.25, 0.25, 0.25));
+            }
+        }
+        ram->use();
+        // Set output probability
+        propagatePortTransitionInfo("FlitOut", ram, "Out");
+        return;
+    }
+} // namespace DSENT
+
diff --git a/ext/dsent/model/electrical/router/RouterInputPort.h b/ext/dsent/model/electrical/router/RouterInputPort.h
new file mode 100644 (file)
index 0000000..1d326a5
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef __DSENT_MODEL_ELECTRICAL_ROUTER_ROUTER_INPUT_PORT_H__
+#define __DSENT_MODEL_ELECTRICAL_ROUTER_ROUTER_INPUT_PORT_H__
+
+#include "util/CommonType.h"
+#include "model/ElectricalModel.h"
+
+namespace DSENT
+{
+    class RouterInputPort : public ElectricalModel
+    {
+        public:
+            RouterInputPort(const String& instance_name_, const TechModel* tech_model_);
+            virtual ~RouterInputPort();
+
+        public:
+            // Set a list of properties' name needed to construct model
+            void initParameters();
+            // Set a list of properties' name needed to construct model
+            void initProperties();
+
+            // Clone and return a new instance
+            virtual RouterInputPort* clone() const;
+
+        protected:
+            // Build the model
+            virtual void constructModel();
+            virtual void propagateTransitionInfo();
+
+    }; // class RouterInputPort
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_ELECTRICAL_ROUTER_ROUTER_INPUT_PORT_H__
+
diff --git a/ext/dsent/model/electrical/router/RouterSwitchAllocator.cc b/ext/dsent/model/electrical/router/RouterSwitchAllocator.cc
new file mode 100644 (file)
index 0000000..92e5431
--- /dev/null
@@ -0,0 +1,199 @@
+#include "model/electrical/router/RouterSwitchAllocator.h"
+
+#include "model/PortInfo.h"
+#include "model/EventInfo.h"
+#include "model/TransitionInfo.h"
+#include "model/ModelGen.h"
+#include "model/std_cells/StdCell.h"
+#include "model/std_cells/StdCellLib.h"
+
+namespace DSENT
+{
+    RouterSwitchAllocator::RouterSwitchAllocator(const String& instance_name_, const TechModel* tech_model_)
+        : ElectricalModel(instance_name_, tech_model_)
+    {
+        initParameters();
+        initProperties();
+    }
+
+    RouterSwitchAllocator::~RouterSwitchAllocator()
+    {}
+
+    void RouterSwitchAllocator::initParameters()
+    {
+        addParameterName("NumberInputPorts");
+        addParameterName("NumberOutputPorts");
+        addParameterName("TotalNumberVirtualChannels");
+        addParameterName("ArbiterModel");
+        return;
+    }
+
+    void RouterSwitchAllocator::initProperties()
+    {}
+
+    RouterSwitchAllocator* RouterSwitchAllocator::clone() const
+    {
+        // TODO
+        return NULL;
+    }
+
+    void RouterSwitchAllocator::constructModel()
+    {
+        // Get parameters
+        unsigned int number_input_ports = getParameter("NumberInputPorts").toUInt();
+        unsigned int number_output_ports = getParameter("NumberOutputPorts").toUInt();
+        unsigned int total_number_vcs = getParameter("TotalNumberVirtualChannels").toUInt();
+        const String& arb_model = getParameter("ArbiterModel");
+
+        ASSERT(number_input_ports > 0, "[Error] " + getInstanceName() +
+                " -> Number of input ports must be > 0!");
+        ASSERT(number_output_ports > 0, "[Error] " + getInstanceName() +
+                " -> Number of output ports must be > 0!");
+        ASSERT(total_number_vcs > 0, "[Error] " + getInstanceName() +
+                " -> Total number of virtual channels must be > 0!");
+
+        unsigned int stage1_number_requests = total_number_vcs;
+        unsigned int number_stage1_arbiters = number_input_ports;
+        unsigned int stage2_number_requests = number_input_ports;
+        unsigned int number_stage2_arbiters = number_output_ports;
+
+        getGenProperties()->set("NumberStage1Arbiters", number_stage1_arbiters);
+        getGenProperties()->set("Stage1->NumberRequests", stage1_number_requests);
+        getGenProperties()->set("NumberStage2Arbiters", number_stage2_arbiters);
+        getGenProperties()->set("Stage2->NumberRequests", stage2_number_requests);
+
+        // Create ports
+        createInputPort("CK");
+        for(unsigned int i = 0; i < number_stage1_arbiters; ++i)
+        {
+            for(unsigned int j = 0; j < stage1_number_requests; ++j)
+            {
+                createInputPort(String::format("Stage1Arb%d->Request%d", i, j));
+                createInputPort(String::format("Stage1Arb%d->Grant%d", i, j));
+            }
+        }
+        for(unsigned int i = 0; i < number_stage2_arbiters; ++i)
+        {
+            for(unsigned int j = 0; j < stage2_number_requests; ++j)
+            {
+                createInputPort(String::format("Stage2Arb%d->Request%d", i, j));
+                createInputPort(String::format("Stage2Arb%d->Grant%d", i, j));
+            }
+        }
+
+        // Create area, power, and event results
+        createElectricalResults();
+        getEventInfo("Idle")->setStaticTransitionInfos();
+        getEventInfo("Idle")->setTransitionInfo("CK", TransitionInfo(0.0, 1.0, 0.0));
+
+        createElectricalEventResult("ArbitrateStage1");
+        getEventInfo("ArbitrateStage1")->setTransitionInfo("CK", TransitionInfo(0.0, 1.0, 0.0));
+        createElectricalEventResult("ArbitrateStage2");
+        getEventInfo("ArbitrateStage2")->setTransitionInfo("CK", TransitionInfo(0.0, 1.0, 0.0));
+
+        // Init Stage1 arbiter
+        vector<String> stage1_arb_dff_names(stage1_number_requests, "");
+        vector<StdCell*> stage1_arb_dffs(stage1_number_requests, NULL);
+        for(unsigned int i = 0; i < stage1_number_requests; ++i)
+        {
+            stage1_arb_dff_names[i] = "Stage1ArbDFF" + (String)i;
+            stage1_arb_dffs[i] = getTechModel()->getStdCellLib()->createStdCell("DFFQ", stage1_arb_dff_names[i]);
+            stage1_arb_dffs[i]->construct();
+        }
+        const String& stage1_arb_name = "Stage1Arb";
+        ElectricalModel* stage1_arb = (ElectricalModel*)ModelGen::createModel(arb_model, stage1_arb_name, getTechModel());
+        stage1_arb->setParameter("NumberRequests", stage1_number_requests);
+        stage1_arb->construct();
+
+        // Init stage2 arbiter
+        vector<String> stage2_arb_dff_names(stage2_number_requests, "");
+        vector<StdCell*> stage2_arb_dffs(stage2_number_requests, NULL);
+        for(unsigned int i = 0; i < stage2_number_requests; ++i)
+        {
+            stage2_arb_dff_names[i] = "Stage2ArbDFF" + (String)i;
+            stage2_arb_dffs[i] = getTechModel()->getStdCellLib()->createStdCell("DFFQ", stage2_arb_dff_names[i]);
+            stage2_arb_dffs[i]->construct();
+        }
+        const String& stage2_arb_name = "Stage2Arb";
+        ElectricalModel* stage2_arb = (ElectricalModel*)ModelGen::createModel(arb_model, stage2_arb_name, getTechModel());
+        stage2_arb->setParameter("NumberRequests", stage2_number_requests);
+        stage2_arb->construct();
+
+        // Connect ports
+        for(unsigned int i = 0; i < stage1_number_requests; ++i)
+        {
+            const String& dff_in_name = "Stage1Arb_DFF_In" + (String)i;
+            const String& req_name = "Stage1Arb->Request" + (String)i;
+            const String& grant_name = "Stage1Arb->Grant" + (String)i;
+            createNet(dff_in_name);
+            createNet(req_name);
+            createNet(grant_name);
+            portConnect(stage1_arb_dffs[i], "D", dff_in_name);
+            portConnect(stage1_arb_dffs[i], "CK", "CK");
+            portConnect(stage1_arb_dffs[i], "Q", req_name);
+            portConnect(stage1_arb, "Request" + (String)i, req_name);
+            portConnect(stage1_arb, "Grant" + (String)i, grant_name);
+            for(unsigned int j = 0; j < number_stage1_arbiters; ++j)
+            {
+                assignVirtualFanin(dff_in_name, String::format("Stage1Arb%d->Request%d", j, i));
+                assignVirtualFanout(String::format("Stage1Arb%d->Grant%d", j, i), grant_name);
+            }
+        }
+        for(unsigned int i = 0; i < stage2_number_requests; ++i)
+        {
+            const String& dff_in_name = "Stage2Arb_DFF_In" + (String)i;
+            const String& req_name = "Stage2Arb->Request" + (String)i;
+            const String& grant_name = "Stage2Arb->Grant" + (String)i;
+            createNet(dff_in_name);
+            createNet(req_name);
+            createNet(grant_name);
+            portConnect(stage2_arb_dffs[i], "D", dff_in_name);
+            portConnect(stage2_arb_dffs[i], "CK", "CK");
+            portConnect(stage2_arb_dffs[i], "Q", req_name);
+            portConnect(stage2_arb, "Request" + (String)i, req_name);
+            portConnect(stage2_arb, "Grant" + (String)i, grant_name);
+            for(unsigned int j = 0; j < number_stage2_arbiters; ++j)
+            {
+                assignVirtualFanin(dff_in_name, String::format("Stage2Arb%d->Request%d", j, i));
+                assignVirtualFanout(String::format("Stage2Arb%d->Grant%d", j, i), grant_name);
+            }
+        }
+
+        // Add sub components
+        for(unsigned int i = 0; i < stage1_number_requests; ++i)
+        {
+            addSubInstances(stage1_arb_dffs[i], 1.0);
+            addElectricalSubResults(stage1_arb_dffs[i], 1.0);
+        }
+        addSubInstances(stage1_arb, number_stage1_arbiters);
+        addElectricalSubResults(stage1_arb, number_stage1_arbiters);
+        for(unsigned int i = 0; i < stage2_number_requests; ++i)
+        {
+            addSubInstances(stage2_arb_dffs[i], 1.0);
+            addElectricalSubResults(stage2_arb_dffs[i], 1.0);
+        }
+        addSubInstances(stage2_arb, number_stage2_arbiters);
+        addElectricalSubResults(stage2_arb, number_stage2_arbiters);
+
+        // Update stage1 arb arbitrate
+        getEventResult("ArbitrateStage1")->addSubResult(stage1_arb->getEventResult("Arbitrate"), stage1_arb_name, 1.0);
+
+        // Update stage2 arb arbitrate
+        getEventResult("ArbitrateStage2")->addSubResult(stage2_arb->getEventResult("Arbitrate"), stage2_arb_name, 1.0);
+        return;
+    }
+
+    void RouterSwitchAllocator::propagateTransitionInfo()
+    {
+        ElectricalModel* stage1_arb = (ElectricalModel*)getSubInstance("Stage1Arb");
+        stage1_arb->applyTransitionInfo("Arbitrate");
+        stage1_arb->use();
+
+        ElectricalModel* stage2_arb = (ElectricalModel*)getSubInstance("Stage2Arb");
+        stage2_arb->applyTransitionInfo("Arbitrate");
+        stage2_arb->use();
+
+        return;
+    }
+} // namespace DSENT
+
diff --git a/ext/dsent/model/electrical/router/RouterSwitchAllocator.h b/ext/dsent/model/electrical/router/RouterSwitchAllocator.h
new file mode 100644 (file)
index 0000000..8b18e19
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef __DSENT_MODEL_ELECTRICAL_ROUTER_ROUTER_SWITCH_ALLOCATOR_H__
+#define __DSENT_MODEL_ELECTRICAL_ROUTER_ROUTER_SWITCH_ALLOCATOR_H__
+
+#include "util/CommonType.h"
+#include "model/ElectricalModel.h"
+
+namespace DSENT
+{
+    class RouterSwitchAllocator : public ElectricalModel
+    {
+        public:
+            RouterSwitchAllocator(const String& instance_name_, const TechModel* tech_model_);
+            virtual ~RouterSwitchAllocator();
+
+        public:
+            // Set a list of properties' name needed to construct model
+            void initParameters();
+            // Set a list of properties' name needed to construct model
+            void initProperties();
+
+            // Clone and return a new instance
+            virtual RouterSwitchAllocator* clone() const;
+
+        protected:
+            // Build the model
+            virtual void constructModel();
+            virtual void propagateTransitionInfo();
+
+    }; // RouterSwitchAllocator
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_ELECTRICAL_ROUTER_ROUTER_SWITCH_ALLOCATOR_H__
+
diff --git a/ext/dsent/model/network/ElectricalClos.cc b/ext/dsent/model/network/ElectricalClos.cc
new file mode 100644 (file)
index 0000000..94781d8
--- /dev/null
@@ -0,0 +1,489 @@
+#include "model/network/ElectricalClos.h"
+
+#include <cmath>
+
+#include "model/ModelGen.h"
+#include "model/timing_graph/ElectricalTimingTree.h"
+#include "model/timing_graph/ElectricalNet.h"
+
+namespace DSENT
+{
+    using std::sqrt;
+
+    ElectricalClos::ElectricalClos(const String& instance_name_, const TechModel* tech_model_)
+        : ElectricalModel(instance_name_, tech_model_)
+    {
+        initParameters();
+        initProperties();
+    }
+
+    ElectricalClos::~ElectricalClos()
+    {}
+
+    void ElectricalClos::initParameters()
+    {
+        // Frequency
+        addParameterName("Frequency");        
+        // Physical Parameters
+        addParameterName("NumberInputSites");
+        addParameterName("NumberOutputSites");
+        addParameterName("NumberBitsPerFlit");
+        // Number of each type of routers
+        addParameterName("NumberIngressRouters");
+        addParameterName("NumberMiddleRouters");
+        addParameterName("NumberEgressRouters");
+        // Router parameters
+        addParameterName("Router->NumberVirtualNetworks");
+        addParameterName("Router->NumberVirtualChannelsPerVirtualNetwork");
+        addParameterName("Router->NumberBuffersPerVirtualChannel");
+        addParameterName("Router->InputPort->BufferModel");
+        addParameterName("Router->CrossbarModel");
+        addParameterName("Router->SwitchAllocator->ArbiterModel");
+        addParameterName("Router->ClockTreeModel");
+        addParameterName("Router->ClockTree->NumberLevels");
+        addParameterName("Router->ClockTree->WireLayer");
+        addParameterName("Router->ClockTree->WireWidthMultiplier");
+        addParameterName("Router->ClockTree->WireSpacingMultiplier", 3.0);
+        // Link parameters
+        addParameterName("Link->WireLayer");
+        addParameterName("Link->WireWidthMultiplier");
+        addParameterName("Link->WireSpacingMultiplier");
+        return;
+    }
+
+    void ElectricalClos::initProperties()
+    {
+        addPropertyName("InputSitePitch");
+        addPropertyName("OutputSitePitch");
+        return;
+    }
+
+    ElectricalClos* ElectricalClos::clone() const
+    {
+        // TODO
+        return NULL;
+    }
+
+    void ElectricalClos::constructModel()
+    {
+        // Get input parameters
+        unsigned int number_input_sites = getParameter("NumberInputSites").toUInt();
+        unsigned int number_output_sites = getParameter("NumberOutputSites").toUInt();
+        unsigned int number_bits_per_flit = getParameter("NumberBitsPerFlit").toUInt();
+        unsigned int number_ingress_routers = getParameter("NumberIngressRouters").toUInt();
+        unsigned int number_middle_routers = getParameter("NumberMiddleRouters").toUInt();
+        unsigned int number_egress_routers = getParameter("NumberEgressRouters").toUInt();
+
+        ASSERT(number_input_sites > 0, "[Error] " + getInstanceName() + 
+                " -> Number of input sites must be > 0!");
+        ASSERT(number_output_sites > 0, "[Error] " + getInstanceName() + 
+                " -> Number of output sites must be > 0!");
+        ASSERT(number_bits_per_flit > 0, "[Error] " + getInstanceName() + 
+                " -> Number of bits per flit must be > 0!");
+        ASSERT(number_ingress_routers > 0, "[Error] " + getInstanceName() +
+                " -> Number of ingress routers must be > 0!");
+        ASSERT(number_middle_routers > 0, "[Error] " + getInstanceName() + 
+                " -> Number of middle routers must be > 0!");
+        ASSERT(number_egress_routers > 0, "[Error] " + getInstanceName() +
+                " -> Number of egress routers must be > 0!");
+
+        // Get input parameters that will be forwarded to the sub instances
+        const String& router_number_vns = getParameter("Router->NumberVirtualNetworks");
+        const String& router_number_vcs_per_vn = getParameter("Router->NumberVirtualChannelsPerVirtualNetwork");
+        const String& router_number_bufs_per_vc = getParameter("Router->NumberBuffersPerVirtualChannel");
+        const String& router_buffer_model = getParameter("Router->InputPort->BufferModel");
+        const String& router_crossbar_model = getParameter("Router->CrossbarModel");
+        const String& link_wire_layer = getParameter("Link->WireLayer");
+        const String& link_wire_width_multiplier = getParameter("Link->WireWidthMultiplier");
+        const String& link_wire_spacing_multiplier = getParameter("Link->WireSpacingMultiplier");
+
+        // Calculate properties from input parameters
+        unsigned int ingress_router_number_input_ports = number_input_sites / number_ingress_routers;
+        unsigned int ingress_router_number_output_ports = number_middle_routers;
+        unsigned int middle_router_number_input_ports = number_ingress_routers;
+        unsigned int middle_router_number_output_ports = number_egress_routers;
+        unsigned int egress_router_number_input_ports = number_middle_routers;
+        unsigned int egress_router_number_output_ports = number_output_sites / number_egress_routers;
+        unsigned int number_input_to_ingress_links = number_input_sites;
+        unsigned int number_ingress_to_middle_links = number_ingress_routers * number_middle_routers;
+        unsigned int number_middle_to_egress_links = number_middle_routers * number_egress_routers;
+        unsigned int number_egress_to_output_links = number_output_sites;
+
+        getGenProperties()->set("NumberInputSitesPerIngressRouter", ingress_router_number_input_ports);
+        getGenProperties()->set("NumberOutputSitesPerEgressRouter", egress_router_number_output_ports);
+        getGenProperties()->set("IngressRouter->NumberInputPorts", ingress_router_number_input_ports);
+        getGenProperties()->set("IngressRouter->NumberOutputPorts", ingress_router_number_output_ports);
+        getGenProperties()->set("MiddleRouter->NumberInputPorts", middle_router_number_input_ports);
+        getGenProperties()->set("MiddleRouter->NumberOutputPorts", middle_router_number_output_ports);
+        getGenProperties()->set("EgressRouter->NumberInputPorts", egress_router_number_input_ports);
+        getGenProperties()->set("EgressRouter->NumberOutputPorts", egress_router_number_output_ports);
+
+        // Create ports
+        createInputPort("CK");
+
+        // Init ingress router
+        ElectricalModel* ingress_router = (ElectricalModel*)ModelGen::createModel("Router", "IngressRouter", getTechModel());
+        ingress_router->setParameter("NumberInputPorts", ingress_router_number_input_ports);
+        ingress_router->setParameter("NumberOutputPorts", ingress_router_number_output_ports);
+        ingress_router->setParameter("NumberVirtualNetworks", router_number_vns);
+        ingress_router->setParameter("NumberVirtualChannelsPerVirtualNetwork", router_number_vcs_per_vn);
+        ingress_router->setParameter("NumberBuffersPerVirtualChannel", router_number_bufs_per_vc);
+        ingress_router->setParameter("NumberBitsPerFlit", number_bits_per_flit);
+        ingress_router->setParameter("InputPort->BufferModel", router_buffer_model);
+        ingress_router->setParameter("CrossbarModel", router_crossbar_model);
+        ingress_router->setParameter("SwitchAllocator->ArbiterModel", getParameter("Router->SwitchAllocator->ArbiterModel"));
+        ingress_router->setParameter("ClockTreeModel", getParameter("Router->ClockTreeModel"));
+        ingress_router->setParameter("ClockTree->NumberLevels", getParameter("Router->ClockTree->NumberLevels"));
+        ingress_router->setParameter("ClockTree->WireLayer", getParameter("Router->ClockTree->WireLayer"));
+        ingress_router->setParameter("ClockTree->WireWidthMultiplier", getParameter("Router->ClockTree->WireWidthMultiplier"));
+        ingress_router->setParameter("ClockTree->WireSpacingMultiplier", getParameter("Router->ClockTree->WireSpacingMultiplier"));
+        ingress_router->construct();
+        // Init middle routers
+        ElectricalModel* middle_router = (ElectricalModel*)ModelGen::createModel("Router", "MiddleRouter", getTechModel());
+        middle_router->setParameter("NumberInputPorts", middle_router_number_input_ports);
+        middle_router->setParameter("NumberOutputPorts", middle_router_number_output_ports);
+        middle_router->setParameter("NumberVirtualNetworks", router_number_vns);
+        middle_router->setParameter("NumberVirtualChannelsPerVirtualNetwork", router_number_vcs_per_vn);
+        middle_router->setParameter("NumberBuffersPerVirtualChannel", router_number_bufs_per_vc);
+        middle_router->setParameter("NumberBitsPerFlit", number_bits_per_flit);
+        middle_router->setParameter("InputPort->BufferModel", router_buffer_model);
+        middle_router->setParameter("CrossbarModel", router_crossbar_model);
+        middle_router->setParameter("SwitchAllocator->ArbiterModel", getParameter("Router->SwitchAllocator->ArbiterModel"));
+        middle_router->setParameter("ClockTreeModel", getParameter("Router->ClockTreeModel"));
+        middle_router->setParameter("ClockTree->NumberLevels", getParameter("Router->ClockTree->NumberLevels"));
+        middle_router->setParameter("ClockTree->WireLayer", getParameter("Router->ClockTree->WireLayer"));
+        middle_router->setParameter("ClockTree->WireWidthMultiplier", getParameter("Router->ClockTree->WireWidthMultiplier"));
+        middle_router->setParameter("ClockTree->WireSpacingMultiplier", getParameter("Router->ClockTree->WireSpacingMultiplier"));
+        middle_router->construct();
+        // Init egress routers
+        ElectricalModel* egress_router = (ElectricalModel*)ModelGen::createModel("Router", "EgressRouter", getTechModel());
+        egress_router->setParameter("NumberInputPorts", egress_router_number_input_ports);
+        egress_router->setParameter("NumberOutputPorts", egress_router_number_output_ports);
+        egress_router->setParameter("NumberVirtualNetworks", router_number_vns);
+        egress_router->setParameter("NumberVirtualChannelsPerVirtualNetwork", router_number_vcs_per_vn);
+        egress_router->setParameter("NumberBuffersPerVirtualChannel", router_number_bufs_per_vc);
+        egress_router->setParameter("NumberBitsPerFlit", number_bits_per_flit);
+        egress_router->setParameter("InputPort->BufferModel", router_buffer_model);
+        egress_router->setParameter("CrossbarModel", router_crossbar_model);
+        egress_router->setParameter("SwitchAllocator->ArbiterModel", getParameter("Router->SwitchAllocator->ArbiterModel"));
+        egress_router->setParameter("ClockTreeModel", getParameter("Router->ClockTreeModel"));
+        egress_router->setParameter("ClockTree->NumberLevels", getParameter("Router->ClockTree->NumberLevels"));
+        egress_router->setParameter("ClockTree->WireLayer", getParameter("Router->ClockTree->WireLayer"));
+        egress_router->setParameter("ClockTree->WireWidthMultiplier", getParameter("Router->ClockTree->WireWidthMultiplier"));
+        egress_router->setParameter("ClockTree->WireSpacingMultiplier", getParameter("Router->ClockTree->WireSpacingMultiplier"));
+        egress_router->construct();
+        // Init input to ingress link
+        ElectricalModel* input_to_ingress_link = (ElectricalModel*)ModelGen::createModel("RepeatedLink", "InputToIngressLink", getTechModel());
+        input_to_ingress_link->setParameter("NumberBits", number_bits_per_flit);
+        input_to_ingress_link->setParameter("WireLayer", link_wire_layer);
+        input_to_ingress_link->setParameter("WireWidthMultiplier", link_wire_width_multiplier);
+        input_to_ingress_link->setParameter("WireSpacingMultiplier", link_wire_spacing_multiplier);
+        input_to_ingress_link->construct();
+        // Init ingress to middle link
+        ElectricalModel* ingress_to_middle_link = (ElectricalModel*)ModelGen::createModel("RepeatedLink", "IngressToMiddleLink", getTechModel());
+        ingress_to_middle_link->setParameter("NumberBits", number_bits_per_flit);
+        ingress_to_middle_link->setParameter("WireLayer", link_wire_layer);
+        ingress_to_middle_link->setParameter("WireWidthMultiplier", link_wire_width_multiplier);
+        ingress_to_middle_link->setParameter("WireSpacingMultiplier", link_wire_spacing_multiplier);
+        ingress_to_middle_link->construct();
+        // Init middle to egress link
+        ElectricalModel* middle_to_egress_link = (ElectricalModel*)ModelGen::createModel("RepeatedLink", "MiddleToEgressLink", getTechModel());
+        middle_to_egress_link->setParameter("NumberBits", number_bits_per_flit);
+        middle_to_egress_link->setParameter("WireLayer", link_wire_layer);
+        middle_to_egress_link->setParameter("WireWidthMultiplier", link_wire_width_multiplier);
+        middle_to_egress_link->setParameter("WireSpacingMultiplier", link_wire_spacing_multiplier);
+        middle_to_egress_link->construct();
+        // Init egress to output link
+        ElectricalModel* egress_to_output_link = (ElectricalModel*)ModelGen::createModel("RepeatedLink", "EgressToOutputLink", getTechModel());
+        egress_to_output_link->setParameter("NumberBits", number_bits_per_flit);
+        egress_to_output_link->setParameter("WireLayer", link_wire_layer);
+        egress_to_output_link->setParameter("WireWidthMultiplier", link_wire_width_multiplier);
+        egress_to_output_link->setParameter("WireSpacingMultiplier", link_wire_spacing_multiplier);
+        egress_to_output_link->construct();
+
+        // Connect ports
+        createNet("InputToIngressLink_Out", makeNetIndex(0, number_bits_per_flit-1));
+        createNet("InputToIngressLink_In", makeNetIndex(0, number_bits_per_flit-1));
+        portConnect(input_to_ingress_link, "In", "InputToIngressLink_In");
+        portConnect(input_to_ingress_link, "Out", "InputToIngressLink_Out");
+
+        createNet("IngressToMiddleLink_In", makeNetIndex(0, number_bits_per_flit-1));
+        createNet("IngressToMiddleLink_Out", makeNetIndex(0, number_bits_per_flit-1));
+        portConnect(ingress_to_middle_link, "In", "IngressToMiddleLink_In");
+        portConnect(ingress_to_middle_link, "Out", "IngressToMiddleLink_Out");
+
+        createNet("MiddleToEgressLink_In", makeNetIndex(0, number_bits_per_flit-1));
+        createNet("MiddleToEgressLink_Out", makeNetIndex(0, number_bits_per_flit-1));
+        portConnect(middle_to_egress_link, "In", "MiddleToEgressLink_In");
+        portConnect(middle_to_egress_link, "Out", "MiddleToEgressLink_Out");
+
+        createNet("EgressToOutputLink_In", makeNetIndex(0, number_bits_per_flit-1));
+        createNet("EgressToOutputLink_Out", makeNetIndex(0, number_bits_per_flit-1));
+        portConnect(egress_to_output_link, "In", "EgressToOutputLink_In");
+        portConnect(egress_to_output_link, "Out", "EgressToOutputLink_Out");
+
+        
+        portConnect(ingress_router, "CK", "CK");
+        for(unsigned int i = 0; i < ingress_router_number_input_ports; ++i)
+        {
+            createNet("IngressRouter_In" + (String)i, makeNetIndex(0, number_bits_per_flit-1));
+            for (unsigned int j = 0; j < number_bits_per_flit; ++j)
+                assignVirtualFanout("IngressRouter_In" + (String)i, makeNetIndex(j), "InputToIngressLink_Out", makeNetIndex(j));
+            portConnect(ingress_router, "FlitIn" + (String)i, "IngressRouter_In" + (String)i);
+        }
+        for(unsigned int i = 0; i < ingress_router_number_output_ports; ++i)
+        {
+            // VFI
+            portConnect(ingress_router, "FlitOut" + (String)i, "IngressToMiddleLink_In");
+        }
+
+        portConnect(middle_router, "CK", "CK");
+        for(unsigned int i = 0; i < middle_router_number_input_ports; ++i)
+        {
+            createNet("MiddleRouter_In" + (String)i, makeNetIndex(0, number_bits_per_flit-1));
+            for (unsigned int j = 0; j < number_bits_per_flit; ++j)
+                assignVirtualFanout("MiddleRouter_In" + (String)i, makeNetIndex(j), "IngressToMiddleLink_Out", makeNetIndex(j));
+            portConnect(middle_router, "FlitIn" + (String)i, "MiddleRouter_In" + (String)i);
+        }
+        for(unsigned int i = 0; i < middle_router_number_output_ports; ++i)
+        {
+            // VFI
+            portConnect(middle_router, "FlitOut" + (String)i, "MiddleToEgressLink_In");
+        }
+
+        portConnect(egress_router, "CK", "CK");
+        for(unsigned int i = 0; i < egress_router_number_input_ports; ++i)
+        {
+            createNet("EgressRouter_In" + (String)i, makeNetIndex(0, number_bits_per_flit-1));
+            for (unsigned int j = 0; j < number_bits_per_flit; ++j)
+                assignVirtualFanout("EgressRouter_In" + (String)i, makeNetIndex(j), "MiddleToEgressLink_Out", makeNetIndex(j));
+            portConnect(egress_router, "FlitIn" + (String)i, "EgressRouter_In" + (String)i);
+        }
+        for(unsigned int i = 0; i < egress_router_number_output_ports; ++i)
+        {
+            // VFI
+            portConnect(egress_router, "FlitOut" + (String)i, "EgressToOutputLink_In");
+        }
+
+        // Create area, power, and event results
+        createElectricalResults();
+        createElectricalEventResult("AvgUnicast");
+        createElectricalEventResult("AvgBroadcast");
+
+        // Add all instances
+        addSubInstances(ingress_router, number_ingress_routers);
+        addElectricalSubResults(ingress_router, number_ingress_routers);
+        addSubInstances(middle_router, number_middle_routers);
+        addElectricalSubResults(middle_router, number_middle_routers);
+        addSubInstances(egress_router, number_egress_routers);
+        addElectricalSubResults(egress_router, number_egress_routers);
+        addSubInstances(input_to_ingress_link, number_input_to_ingress_links);
+        addElectricalSubResults(input_to_ingress_link, number_input_to_ingress_links);
+        addSubInstances(ingress_to_middle_link, number_ingress_to_middle_links);
+        addElectricalSubResults(ingress_to_middle_link, number_ingress_to_middle_links);
+        addSubInstances(middle_to_egress_link, number_middle_to_egress_links);
+        addElectricalSubResults(middle_to_egress_link, number_middle_to_egress_links);
+        addSubInstances(egress_to_output_link, number_egress_to_output_links);
+        addElectricalSubResults(egress_to_output_link, number_egress_to_output_links);
+
+        // Update unicast event
+        Result* avg_unicast_event = getEventResult("AvgUnicast");
+        avg_unicast_event->addSubResult(input_to_ingress_link->getEventResult("Send"), "InputToIngressLink", 1.0);
+        if(ingress_router->hasEventResult("WriteBuffer"))
+        {
+            avg_unicast_event->addSubResult(ingress_router->getEventResult("WriteBuffer"), "IngressRouter", 1.0);
+        }
+        if(ingress_router->hasEventResult("ReadBuffer"))
+        {
+            avg_unicast_event->addSubResult(ingress_router->getEventResult("ReadBuffer"), "IngressRouter", 1.0);
+        }
+        avg_unicast_event->addSubResult(ingress_router->getEventResult("TraverseCrossbar->Multicast1"), "IngressRouter", 1.0);
+        avg_unicast_event->addSubResult(ingress_to_middle_link->getEventResult("Send"), "IngressToMiddleLink", 1.0);
+        if(middle_router->hasEventResult("WriteBuffer"))
+        {
+            avg_unicast_event->addSubResult(middle_router->getEventResult("WriteBuffer"), "MiddleRouter", 1.0);
+        }
+        if(middle_router->hasEventResult("ReadBuffer"))
+        {
+            avg_unicast_event->addSubResult(middle_router->getEventResult("ReadBuffer"), "MiddleRouter", 1.0);
+        }
+        avg_unicast_event->addSubResult(middle_router->getEventResult("TraverseCrossbar->Multicast1"), "MiddleRouter", 1.0);
+        avg_unicast_event->addSubResult(middle_to_egress_link->getEventResult("Send"), "MiddleToEgressLink", 1.0);
+        if(egress_router->hasEventResult("WriteBuffer"))
+        {
+            avg_unicast_event->addSubResult(egress_router->getEventResult("WriteBuffer"), "EgressRouter", 1.0);
+        }
+        if(egress_router->hasEventResult("ReadBuffer"))
+        {
+            avg_unicast_event->addSubResult(egress_router->getEventResult("ReadBuffer"), "EgressRouter", 1.0);
+        }
+        avg_unicast_event->addSubResult(egress_router->getEventResult("TraverseCrossbar->Multicast1"), "EgressRouter", 1.0);
+        avg_unicast_event->addSubResult(egress_to_output_link->getEventResult("Send"), "EgressToOutputLink", 1.0);
+
+        // Update broadcast event
+        Result* avg_broadcast_event = getEventResult("AvgBroadcast");
+        avg_broadcast_event->addSubResult(input_to_ingress_link->getEventResult("Send"), "InputToIngressLink", 1.0);
+        if(ingress_router->hasEventResult("WriteBuffer"))
+        {
+            avg_broadcast_event->addSubResult(ingress_router->getEventResult("WriteBuffer"), "IngressRouter", 1.0);
+        }
+        if(ingress_router->hasEventResult("ReadBuffer"))
+        {
+            avg_broadcast_event->addSubResult(ingress_router->getEventResult("ReadBuffer"), "IngressRouter", 1.0);
+        }
+        avg_broadcast_event->addSubResult(ingress_router->getEventResult("TraverseCrossbar->Multicast1"), "IngressRouter", 1.0);
+        avg_broadcast_event->addSubResult(ingress_to_middle_link->getEventResult("Send"), "IngressToMiddleLink", 1.0);
+        if(middle_router->hasEventResult("WriteBuffer"))
+        {
+            avg_broadcast_event->addSubResult(middle_router->getEventResult("WriteBuffer"), "MiddleRouter", 1.0);
+        }
+        if(middle_router->hasEventResult("ReadBuffer"))
+        {
+            avg_broadcast_event->addSubResult(middle_router->getEventResult("ReadBuffer"), "MiddleRouter", 1.0);
+        }
+        avg_broadcast_event->addSubResult(middle_router->getEventResult("TraverseCrossbar->Multicast1"), "MiddleRouter", 1.0);
+        avg_broadcast_event->addSubResult(middle_to_egress_link->getEventResult("Send"), "MiddleToEgressLink", number_egress_routers);
+        if(egress_router->hasEventResult("WriteBuffer"))
+        {
+            avg_broadcast_event->addSubResult(egress_router->getEventResult("WriteBuffer"), "EgressRouter", number_egress_routers);
+        }
+        if(egress_router->hasEventResult("ReadBuffer"))
+        {
+            avg_broadcast_event->addSubResult(egress_router->getEventResult("ReadBuffer"), "EgressRouter", number_egress_routers);
+        }
+        avg_broadcast_event->addSubResult(egress_router->getEventResult("TraverseCrossbar->Multicast" + (String)number_egress_routers), "EgressRouter", 1.0);
+        avg_broadcast_event->addSubResult(egress_to_output_link->getEventResult("Send"), "EgressToOutputLink", number_output_sites);
+        return;
+    }
+
+    void ElectricalClos::updateModel()
+    {
+        // Get properties
+        double input_site_pitch = getProperty("InputSitePitch").toDouble();
+        double output_site_pitch = getProperty("OutputSitePitch").toDouble();
+        double clock_freq = getParameter("Frequency");
+
+        ASSERT(input_site_pitch > 0, "[Error] " + getInstanceName() + 
+                " -> Input site pitch must be > 0!");
+        ASSERT(output_site_pitch > 0, "[Error] " + getInstanceName() + 
+                " -> Output site pitch must be > 0!");
+        ASSERT(clock_freq > 0, "[Error] " + getInstanceName() +
+                " -> Clock frequency must be > 0!");
+
+        unsigned int number_input_sites_per_ingress_router = getGenProperties()->get("NumberInputSitesPerIngressRouter");
+        unsigned int number_ingress_routers = getParameter("NumberIngressRouters");
+        unsigned int number_output_sites_per_egress_router = getGenProperties()->get("NumberOutputSitesPerEgressRouter");
+        unsigned int number_egress_routers = getParameter("NumberEgressRouters");
+        double delay = 1.0 / clock_freq;
+
+        double input_to_ingress_link_length = input_site_pitch * (sqrt(number_input_sites_per_ingress_router) - 1.0);
+        double input_to_ingress_link_delay = delay * 0.8;
+        double ingress_to_middle_link_length = input_site_pitch * (sqrt(number_input_sites_per_ingress_router) * sqrt(number_ingress_routers));
+        double ingress_to_middle_link_delay = delay * 0.8;
+        double middle_to_egress_link_length = output_site_pitch * (sqrt(number_output_sites_per_egress_router) * sqrt(number_egress_routers));
+        double middle_to_egress_link_delay = delay * 0.8;
+        double egress_to_output_link_length = output_site_pitch * (sqrt(number_output_sites_per_egress_router) - 1.0);
+        double egress_to_output_link_delay = delay * 0.8;
+        double ingress_router_delay = delay;
+        double middle_router_delay = delay;
+        double egress_router_delay = delay;
+
+        Model* input_to_ingress_link = getSubInstance("InputToIngressLink");
+        input_to_ingress_link->setProperty("WireLength", input_to_ingress_link_length);
+        input_to_ingress_link->setProperty("Delay", input_to_ingress_link_delay);
+        input_to_ingress_link->setProperty("IsKeepParity", "TRUE");
+        input_to_ingress_link->update();
+
+        Model* ingress_to_middle_link = getSubInstance("IngressToMiddleLink");
+        ingress_to_middle_link->setProperty("WireLength", ingress_to_middle_link_length);
+        ingress_to_middle_link->setProperty("Delay", ingress_to_middle_link_delay);
+        ingress_to_middle_link->setProperty("IsKeepParity", "TRUE");
+        ingress_to_middle_link->update();
+
+        Model* middle_to_egress_link = getSubInstance("MiddleToEgressLink");
+        middle_to_egress_link->setProperty("WireLength", middle_to_egress_link_length);
+        middle_to_egress_link->setProperty("Delay", middle_to_egress_link_delay);
+        middle_to_egress_link->setProperty("IsKeepParity", "TRUE");
+        middle_to_egress_link->update();
+
+        Model* egress_to_output_link = getSubInstance("EgressToOutputLink");
+        egress_to_output_link->setProperty("WireLength", egress_to_output_link_length);
+        egress_to_output_link->setProperty("Delay", egress_to_output_link_delay);
+        egress_to_output_link->setProperty("IsKeepParity", "TRUE");
+        egress_to_output_link->update();
+
+        ElectricalModel* ingress_router = (ElectricalModel*)getSubInstance("IngressRouter");
+        ingress_router->update();
+        
+        ElectricalTimingTree ingress_router_timing_tree("IngressRouter", ingress_router);
+        ingress_router_timing_tree.performTimingOpt(ingress_router->getNet("CK"), ingress_router_delay);
+
+        ElectricalModel* middle_router = (ElectricalModel*)getSubInstance("MiddleRouter");
+        middle_router->update();
+        
+        ElectricalTimingTree middle_router_timing_tree("MiddleRouter", middle_router);
+        middle_router_timing_tree.performTimingOpt(middle_router->getNet("CK"), middle_router_delay);
+
+        ElectricalModel* egress_router = (ElectricalModel*)getSubInstance("EgressRouter");
+        egress_router->update();
+        
+        ElectricalTimingTree egress_router_timing_tree("EgressRouter", egress_router);
+        egress_router_timing_tree.performTimingOpt(egress_router->getNet("CK"), egress_router_delay);
+
+        return;
+    }
+
+    void ElectricalClos::propagateTransitionInfo()
+    {
+        // Get properties
+        unsigned int ingress_router_number_input_ports = getGenProperties()->get("IngressRouter->NumberInputPorts");
+        unsigned int middle_router_number_input_ports = getGenProperties()->get("MiddleRouter->NumberInputPorts");
+        unsigned int egress_router_number_input_ports = getGenProperties()->get("EgressRouter->NumberInputPorts");
+
+        ElectricalModel* input_to_ingress_link = (ElectricalModel*)getSubInstance("InputToIngressLink");
+        assignPortTransitionInfo(input_to_ingress_link, "In", TransitionInfo(0.25, 0.25, 0.25));
+        input_to_ingress_link->use();
+
+        ElectricalModel* ingress_to_middle_link = (ElectricalModel*)getSubInstance("IngressToMiddleLink");
+        assignPortTransitionInfo(ingress_to_middle_link, "In", TransitionInfo(0.25, 0.25, 0.25));
+        ingress_to_middle_link->use();
+
+        ElectricalModel* middle_to_egress_link = (ElectricalModel*)getSubInstance("MiddleToEgressLink");
+        assignPortTransitionInfo(middle_to_egress_link, "In", TransitionInfo(0.25, 0.25, 0.25));
+        middle_to_egress_link->use();
+
+        ElectricalModel* egress_to_output_link = (ElectricalModel*)getSubInstance("EgressToOutputLink");
+        assignPortTransitionInfo(egress_to_output_link, "In", TransitionInfo(0.25, 0.25, 0.25));
+        egress_to_output_link->use();
+
+        ElectricalModel* ingress_router = (ElectricalModel*)getSubInstance("IngressRouter");
+        for(unsigned int i = 0; i < ingress_router_number_input_ports; ++i)
+        {
+            assignPortTransitionInfo(ingress_router, "FlitIn" + (String)i, TransitionInfo(0.25, 0.25, 0.25));
+        }
+        assignPortTransitionInfo(ingress_router, "CK", TransitionInfo(0.0, 1.0, 0.0));
+        ingress_router->getGenProperties()->set("UseModelEvent", "");
+        ingress_router->use();
+
+        ElectricalModel* middle_router = (ElectricalModel*)getSubInstance("MiddleRouter");
+        for(unsigned int i = 0; i < middle_router_number_input_ports; ++i)
+        {
+            assignPortTransitionInfo(middle_router, "FlitIn" + (String)i, TransitionInfo(0.25, 0.25, 0.25));
+        }
+        assignPortTransitionInfo(middle_router, "CK", TransitionInfo(0.0, 1.0, 0.0));
+        middle_router->getGenProperties()->set("UseModelEvent", "");
+        middle_router->use();
+
+        ElectricalModel* egress_router = (ElectricalModel*)getSubInstance("EgressRouter");
+        for(unsigned int i = 0; i < egress_router_number_input_ports; ++i)
+        {
+            assignPortTransitionInfo(egress_router, "FlitIn" + (String)i, TransitionInfo(0.25, 0.25, 0.25));
+        }
+        assignPortTransitionInfo(egress_router, "CK", TransitionInfo(0.0, 1.0, 0.0));
+        egress_router->getGenProperties()->set("UseModelEvent", "");
+        egress_router->use();
+
+        return;
+    }
+} // namespace DSENT
+
diff --git a/ext/dsent/model/network/ElectricalClos.h b/ext/dsent/model/network/ElectricalClos.h
new file mode 100644 (file)
index 0000000..c6a1f80
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef __DSENT_MODEL_NETWORK_ELECTRICAL_CLOS_H__
+#define __DSENT_MODEL_NETWORK_ELECTRICAL_CLOS_H__
+
+#include "util/CommonType.h"
+#include "model/ElectricalModel.h"
+
+namespace DSENT
+{
+    /** 
+     * \brief An electrical 3-stage clos network
+     */
+    class ElectricalClos : public ElectricalModel
+    {
+        public:
+            ElectricalClos(const String& instance_name_, const TechModel* tech_model_);
+            virtual ~ElectricalClos();
+
+        public:
+            // Set a list of properties' name needed to construct model
+            void initParameters();
+            // Set a list of properties' name needed to construct model
+            void initProperties();
+
+            // Clone and return a new instance
+            virtual ElectricalClos* clone() const;
+
+        protected:
+            // Build the model
+            virtual void constructModel();
+            virtual void updateModel();
+            virtual void propagateTransitionInfo();
+
+    };
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_NETWORK_ELECTRICAL_CLOS_H__
+
diff --git a/ext/dsent/model/network/ElectricalMesh.cc b/ext/dsent/model/network/ElectricalMesh.cc
new file mode 100644 (file)
index 0000000..5ad544e
--- /dev/null
@@ -0,0 +1,296 @@
+#include "model/network/ElectricalMesh.h"
+
+#include <cmath>
+
+#include "model/PortInfo.h"
+#include "model/EventInfo.h"
+#include "model/TransitionInfo.h"
+#include "model/ModelGen.h"
+#include "model/std_cells/StdCellLib.h"
+#include "model/timing_graph/ElectricalTimingTree.h"
+#include "model/timing_graph/ElectricalNet.h"
+
+namespace DSENT
+{
+    using std::sqrt;
+
+    ElectricalMesh::ElectricalMesh(const String& instance_name_, const TechModel* tech_model_)
+        : ElectricalModel(instance_name_, tech_model_)
+    {
+        initParameters();
+        initProperties();
+    }
+
+    ElectricalMesh::~ElectricalMesh()
+    {}
+
+    void ElectricalMesh::initParameters()
+    {
+        // Clock Frequency
+        addParameterName("Frequency");
+        // Physical Parameters
+        addParameterName("NumberSites");
+        addParameterName("NumberBitsPerFlit");
+        // Concentration factor
+        addParameterName("NumberSitesPerRouter");
+        // Router parameters
+        addParameterName("Router->NumberVirtualNetworks");
+        addParameterName("Router->NumberVirtualChannelsPerVirtualNetwork");
+        addParameterName("Router->NumberBuffersPerVirtualChannel");
+        addParameterName("Router->InputPort->BufferModel");
+        addParameterName("Router->CrossbarModel");
+        addParameterName("Router->SwitchAllocator->ArbiterModel");
+        addParameterName("Router->ClockTreeModel");
+        addParameterName("Router->ClockTree->NumberLevels");
+        addParameterName("Router->ClockTree->WireLayer");
+        addParameterName("Router->ClockTree->WireWidthMultiplier");
+        addParameterName("Router->ClockTree->WireSpacingMultiplier", 3.0);
+        // Link parameters
+        addParameterName("Link->WireLayer");
+        addParameterName("Link->WireWidthMultiplier");
+        addParameterName("Link->WireSpacingMultiplier");
+        return;
+    }
+
+    void ElectricalMesh::initProperties()
+    {
+        addPropertyName("SitePitch");
+        return;
+    }
+
+    ElectricalMesh* ElectricalMesh::clone() const
+    {
+        // TODO
+        return NULL;
+    }
+
+    void ElectricalMesh::constructModel()
+    {
+        // Get input paramters
+        unsigned int number_sites = getParameter("NumberSites").toUInt();
+        unsigned int number_bits_per_flit = getParameter("NumberBitsPerFlit").toUInt();
+        unsigned int number_sites_per_router = getParameter("NumberSitesPerRouter").toUInt();
+
+        ASSERT(number_sites > 0, "[Error] " + getInstanceName() + 
+                " -> Number of sites must be > 0!");
+        ASSERT(number_bits_per_flit > 0, "[Error] " + getInstanceName() + 
+                " -> Number of bits per flit must be > 0!");
+        ASSERT(number_sites_per_router > 0, "[Error] " + getInstanceName() + 
+                " -> Number of sites per router must be > 0!");
+
+        // Get input parameters that will be forwarded to the sub instances
+        const String& router_number_vns = getParameter("Router->NumberVirtualNetworks");
+        const String& router_number_vcs_per_vn = getParameter("Router->NumberVirtualChannelsPerVirtualNetwork");
+        const String& router_number_bufs_per_vc = getParameter("Router->NumberBuffersPerVirtualChannel");
+        const String& link_wire_layer = getParameter("Link->WireLayer");
+        const String& link_wire_width_multiplier = getParameter("Link->WireWidthMultiplier");
+        const String& link_wire_spacing_multiplier = getParameter("Link->WireSpacingMultiplier");
+
+        // Calculate properties from input parameters
+        unsigned int number_routers = number_sites / number_sites_per_router;
+        unsigned int number_router_to_router_links = 4 * number_routers;
+        unsigned int number_router_to_site_links = 2 * number_sites;
+        unsigned int router_number_input_ports = 4 + number_sites_per_router;
+        unsigned int router_number_output_ports = 4 + number_sites_per_router;
+
+        getGenProperties()->set("NumberRouters", number_routers);
+        getGenProperties()->set("NumberRouterToRouterLinks", number_router_to_router_links);
+        getGenProperties()->set("NumberRouterToSiteLinks", number_router_to_site_links);
+        getGenProperties()->set("Router->NumberInputPorts", router_number_input_ports);
+        getGenProperties()->set("Router->NumberOutputPorts", router_number_output_ports);
+
+        // Create ports
+        createInputPort("CK");
+
+        // Init mesh routers
+        ElectricalModel* router = (ElectricalModel*)ModelGen::createModel("Router", "MeshRouter", getTechModel());
+        router->setParameter("NumberInputPorts", router_number_input_ports);
+        router->setParameter("NumberOutputPorts", router_number_output_ports);
+        router->setParameter("NumberVirtualNetworks", router_number_vns);
+        router->setParameter("NumberVirtualChannelsPerVirtualNetwork", router_number_vcs_per_vn);
+        router->setParameter("NumberBuffersPerVirtualChannel", router_number_bufs_per_vc);
+        router->setParameter("NumberBitsPerFlit", number_bits_per_flit);
+        router->setParameter("InputPort->BufferModel", getParameter("Router->InputPort->BufferModel"));
+        router->setParameter("CrossbarModel", getParameter("Router->CrossbarModel"));
+        router->setParameter("SwitchAllocator->ArbiterModel", getParameter("Router->SwitchAllocator->ArbiterModel"));
+        router->setParameter("ClockTreeModel", getParameter("Router->ClockTreeModel"));
+        router->setParameter("ClockTree->NumberLevels", getParameter("Router->ClockTree->NumberLevels"));
+        router->setParameter("ClockTree->WireLayer", getParameter("Router->ClockTree->WireLayer"));
+        router->setParameter("ClockTree->WireWidthMultiplier", getParameter("Router->ClockTree->WireWidthMultiplier"));
+        router->setParameter("ClockTree->WireSpacingMultiplier", getParameter("Router->ClockTree->WireSpacingMultiplier"));
+        router->construct();
+
+        // Init router to router links
+        ElectricalModel* rr_link = (ElectricalModel*)ModelGen::createModel("RepeatedLink", "RouterToRouterLink", getTechModel());
+        rr_link->setParameter("NumberBits", number_bits_per_flit);
+        rr_link->setParameter("WireLayer", link_wire_layer);
+        rr_link->setParameter("WireWidthMultiplier", link_wire_width_multiplier);
+        rr_link->setParameter("WireSpacingMultiplier", link_wire_spacing_multiplier);
+        rr_link->construct();
+
+        // Init router to site links
+        ElectricalModel* rs_link = (ElectricalModel*)ModelGen::createModel("RepeatedLink", "RouterToSiteLink", getTechModel());
+        rs_link->setParameter("NumberBits", number_bits_per_flit);
+        rs_link->setParameter("WireLayer", link_wire_layer);
+        rs_link->setParameter("WireWidthMultiplier", link_wire_width_multiplier);
+        rs_link->setParameter("WireSpacingMultiplier", link_wire_spacing_multiplier);
+        rs_link->construct();
+
+        // Connect ports
+        createNet("RR_Link_Out", makeNetIndex(0, number_bits_per_flit-1));
+        createNet("RR_Link_In", makeNetIndex(0, number_bits_per_flit-1));
+        portConnect(rr_link, "In", "RR_Link_In");
+        portConnect(rr_link, "Out", "RR_Link_Out");
+
+        createNet("RS_Link_Out", makeNetIndex(0, number_bits_per_flit-1));
+        createNet("RS_Link_In", makeNetIndex(0, number_bits_per_flit-1));
+        portConnect(rs_link, "In", "RS_Link_In");
+        portConnect(rs_link, "Out", "RS_Link_Out");
+
+        portConnect(router, "CK", "CK");
+        for(unsigned int i = 0; i < router_number_input_ports; ++i)
+        {
+            createNet("Router_In" + (String)i, makeNetIndex(0, number_bits_per_flit-1));
+            portConnect(router, "FlitIn" + (String)i, "Router_In" + (String)i);
+        }
+        for(unsigned int i = 0; i < router_number_output_ports; ++i)
+        {
+            createNet("Router_Out" + (String)i, makeNetIndex(0, number_bits_per_flit-1));
+            portConnect(router, "FlitOut" + (String)i, "Router_Out" + (String)i);
+        }
+        for(unsigned int i = 0; i < number_bits_per_flit; ++i)
+        {
+            for(unsigned int j = 0; j < 4; ++j)
+            {
+                assignVirtualFanout("Router_In" + (String)j, makeNetIndex(i), "RR_Link_Out", makeNetIndex(i));
+                assignVirtualFanin("RR_Link_In", makeNetIndex(i), "Router_Out" + (String)j, makeNetIndex(i));
+            }
+            for(unsigned int j = 4; j < router_number_input_ports; ++j)
+            {
+                assignVirtualFanout("Router_In" + (String)j, makeNetIndex(i), "RS_Link_Out", makeNetIndex(i));
+                assignVirtualFanin("RS_Link_In", makeNetIndex(i), "Router_Out" + (String)j, makeNetIndex(i));
+            }
+        }
+
+        // Create area, power and event results
+        createElectricalResults();
+        createElectricalEventResult("AvgUnicast");
+        createElectricalEventResult("AvgBroadcast");
+
+        // Add all instances
+        addSubInstances(router, number_routers);
+        addElectricalSubResults(router, number_routers);
+        addSubInstances(rr_link, number_router_to_router_links);
+        addElectricalSubResults(rr_link, number_router_to_router_links);
+        addSubInstances(rs_link, number_router_to_site_links);
+        addElectricalSubResults(rs_link, number_router_to_site_links);
+
+        double number_routers_per_side = sqrt(number_routers);
+
+        // Update unicast event
+        double avg_number_unicast_hop = 2.0 * number_routers_per_side / 3.0;
+        double avg_number_unicast_rr_links_traveled = avg_number_unicast_hop;
+        double avg_number_unicast_rs_links_traveled = 2.0;
+        double avg_number_unicast_router_traveled = avg_number_unicast_hop + 1.0;
+        Result* avg_unicast_flit = getEventResult("AvgUnicast");
+        avg_unicast_flit->addSubResult(rr_link->getEventResult("Send"), "RouterToRouterLink", avg_number_unicast_rr_links_traveled);
+        avg_unicast_flit->addSubResult(rs_link->getEventResult("Send"), "RouterToSiteLink", avg_number_unicast_rs_links_traveled);
+        if(router->hasEventResult("WriteBuffer"))
+        {
+            avg_unicast_flit->addSubResult(router->getEventResult("WriteBuffer"), "MeshRouter", avg_number_unicast_router_traveled);
+        }
+        if(router->hasEventResult("ReadBuffer"))
+        {
+            avg_unicast_flit->addSubResult(router->getEventResult("ReadBuffer"), "MeshRouter", avg_number_unicast_router_traveled);
+        }
+        avg_unicast_flit->addSubResult(router->getEventResult("TraverseCrossbar->Multicast1"), "MeshRouter", avg_number_unicast_router_traveled);
+
+        // Update broadcast event
+        double avg_number_broadcast_rr_links_traveled = (number_routers_per_side - 1.0) * number_routers_per_side + number_routers_per_side - 1.0;
+        double avg_number_broadcast_rs_links_traveled = number_sites;
+        double avg_number_broadcast_router_crossbar_traveled = number_routers * (number_sites_per_router + 1.0) - 2.0;
+        Result* avg_broadcast_flit = getEventResult("AvgBroadcast");
+        avg_broadcast_flit->addSubResult(rr_link->getEventResult("Send"), "RouterToRouterLink", avg_number_broadcast_rr_links_traveled);
+        avg_broadcast_flit->addSubResult(rs_link->getEventResult("Send"), "RouterToSiteLink", avg_number_broadcast_rs_links_traveled);
+        if(router->hasEventResult("WriteBuffer"))
+        {
+            avg_broadcast_flit->addSubResult(router->getEventResult("WriteBuffer"), "MeshRouter", number_routers);
+        }
+        if(router->hasEventResult("ReadBuffer"))
+        {
+            avg_broadcast_flit->addSubResult(router->getEventResult("ReadBuffer"), "MeshRouter", number_routers);
+        }
+        avg_broadcast_flit->addSubResult(router->getEventResult("TraverseCrossbar->Multicast1"), "MeshRouter", avg_number_broadcast_router_crossbar_traveled);
+
+        return;
+    }
+
+    void ElectricalMesh::updateModel()
+    {
+        // Get properties
+        double site_pitch = getProperty("SitePitch").toDouble();
+        double clock_freq = getParameter("Frequency");
+
+        ASSERT(site_pitch > 0, "[Error] " + getInstanceName() + 
+                " -> Site pitch must be > 0!");
+        ASSERT(clock_freq > 0, "[Error] " + getInstanceName() +
+                " -> Clock frequency must be > 0!");
+
+        unsigned int number_sites_per_router = getParameter("NumberSitesPerRouter");
+        // Get margin on link delays, since there are registers before and after the link
+        double delay_ck_to_q = getTechModel()->getStdCellLib()->getStdCellCache()->get("DFFQ_X1->Delay->CK_to_Q");
+        double delay_setup = getTechModel()->getStdCellLib()->getStdCellCache()->get("DFFQ_X1->Delay->CK_to_Q");
+        double link_delay_margin = (delay_ck_to_q + delay_setup) * 1.5;
+        
+        double rr_link_length = site_pitch * sqrt(number_sites_per_router);
+        double rr_link_delay = std::max(1e-99, 1.0 / clock_freq - link_delay_margin);
+        double rs_link_length = site_pitch * (sqrt(number_sites_per_router) - 1.0);
+        double rs_link_delay = std::max(1e-99, 1.0 / clock_freq - link_delay_margin );
+        double router_delay = 1.0 / clock_freq;
+
+        Model* rr_link = getSubInstance("RouterToRouterLink");
+        rr_link->setProperty("WireLength", rr_link_length);
+        rr_link->setProperty("Delay", rr_link_delay);
+        rr_link->setProperty("IsKeepParity", "TRUE");
+        rr_link->update();
+
+        Model* rs_link = getSubInstance("RouterToSiteLink");
+        rs_link->setProperty("WireLength", rs_link_length);
+        rs_link->setProperty("Delay", rs_link_delay);
+        rs_link->setProperty("IsKeepParity", "TRUE");
+        rs_link->update();
+
+        ElectricalModel* router = (ElectricalModel*)getSubInstance("MeshRouter");
+        router->update();
+
+        ElectricalTimingTree router_timing_tree("MeshRouter", router);
+        router_timing_tree.performTimingOpt(router->getNet("CK"), router_delay);
+        return;
+    }
+
+    void ElectricalMesh::propagateTransitionInfo()
+    {
+        // Get parameters
+        unsigned int router_number_input_ports = getGenProperties()->get("Router->NumberInputPorts");
+
+        ElectricalModel* rr_link = (ElectricalModel*)getSubInstance("RouterToRouterLink");
+        assignPortTransitionInfo(rr_link, "In", TransitionInfo(0.25, 0.25, 0.25));
+        rr_link->use();
+
+        ElectricalModel* rs_link = (ElectricalModel*)getSubInstance("RouterToSiteLink");
+        assignPortTransitionInfo(rs_link, "In", TransitionInfo(0.25, 0.25, 0.25));
+        rs_link->use();
+
+        ElectricalModel* router = (ElectricalModel*)getSubInstance("MeshRouter");
+        for(unsigned int i = 0; i < router_number_input_ports; ++i)
+        {
+            assignPortTransitionInfo(router, "FlitIn" + (String)i, TransitionInfo(0.25, 0.25, 0.25));
+        }
+        assignPortTransitionInfo(router, "CK", TransitionInfo(0.0, 1.0, 0.0));
+        router->getGenProperties()->set("UseModelEvent", "");
+        router->use();
+
+        return;
+    }
+} // namespace DSENT
+
diff --git a/ext/dsent/model/network/ElectricalMesh.h b/ext/dsent/model/network/ElectricalMesh.h
new file mode 100644 (file)
index 0000000..de89a8f
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef __DSENT_MODEL_NETWORK_ELECTRICAL_MESH_H__
+#define __DSENT_MODEL_NETWORK_ELECTRICAL_MESH_H__
+
+#include "util/CommonType.h"
+#include "model/ElectricalModel.h"
+
+namespace DSENT
+{
+    /** 
+     * \brief An electrical mesh network
+     */
+    class ElectricalMesh : public ElectricalModel
+    {
+        public:
+            ElectricalMesh(const String& instance_name_, const TechModel* tech_model_);
+            virtual ~ElectricalMesh();
+
+        public:
+            // Set a list of properties' name needed to construct model
+            void initParameters();
+            // Set a list of properties' name needed to construct model
+            void initProperties();
+
+            // Clone and return a new instance
+            virtual ElectricalMesh* clone() const;
+
+        protected:
+            // Build the model
+            virtual void constructModel();
+            virtual void updateModel();
+            virtual void propagateTransitionInfo();
+        
+    }; // class ElectricalMesh
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_NETWORK_ELECTRICAL_MESH_H__
+
diff --git a/ext/dsent/model/network/PhotonicClos.cc b/ext/dsent/model/network/PhotonicClos.cc
new file mode 100644 (file)
index 0000000..1b0868e
--- /dev/null
@@ -0,0 +1,512 @@
+#include "model/network/PhotonicClos.h"
+
+#include <cmath>
+
+#include "model/ModelGen.h"
+#include "model/timing_graph/ElectricalTimingTree.h"
+#include "model/timing_graph/ElectricalNet.h"
+
+namespace DSENT
+{
+    using std::sqrt;
+
+    PhotonicClos::PhotonicClos(const String& instance_name_, const TechModel* tech_model_)
+        : ElectricalModel(instance_name_, tech_model_)
+    {
+        initParameters();
+        initProperties();
+    }
+
+    PhotonicClos::~PhotonicClos()
+    {}
+
+    void PhotonicClos::initParameters()
+    {
+        // Clock Frequency
+        addParameterName("Frequency");
+        // Physical Parameters
+        addParameterName("NumberInputSites");
+        addParameterName("NumberOutputSites");
+        addParameterName("NumberBitsPerFlit");
+        // Number of each type of routers
+        addParameterName("NumberIngressRouters");
+        addParameterName("NumberMiddleRouters");
+        addParameterName("NumberEgressRouters");
+        // Optical link parameters
+        addParameterName("SWSR->LinkDataRate");
+        addParameterName("SWSR->LaserType");
+        addParameterName("SWSR->RingTuningMethod");
+        // Router parameters
+        addParameterName("Router->NumberVirtualNetworks");
+        addParameterName("Router->NumberVirtualChannelsPerVirtualNetwork");
+        addParameterName("Router->NumberBuffersPerVirtualChannel");
+        addParameterName("Router->InputPort->BufferModel");
+        addParameterName("Router->CrossbarModel");
+        addParameterName("Router->SwitchAllocator->ArbiterModel");
+        addParameterName("Router->ClockTreeModel");
+        addParameterName("Router->ClockTree->NumberLevels");
+        addParameterName("Router->ClockTree->WireLayer");
+        addParameterName("Router->ClockTree->WireWidthMultiplier");
+        addParameterName("Router->ClockTree->WireSpacingMultiplier", 3.0);
+        // Link parameters
+        addParameterName("Link->WireLayer");
+        addParameterName("Link->WireWidthMultiplier");
+        addParameterName("Link->WireSpacingMultiplier");
+        return;
+    }
+
+    void PhotonicClos::initProperties()
+    {
+        addPropertyName("InputSitePitch");
+        addPropertyName("OutputSitePitch");
+               addPropertyName("SWSR->OptUtil", 1.0);
+        return;
+    }
+
+    PhotonicClos* PhotonicClos::clone() const
+    {
+        // TODO
+        return NULL;
+    }
+
+    void PhotonicClos::constructModel()
+    {
+        // Get input parameters
+        double clock_freq = getParameter("Frequency");
+        unsigned int number_input_sites = getParameter("NumberInputSites").toUInt();
+        unsigned int number_output_sites = getParameter("NumberOutputSites").toUInt();
+        unsigned int number_bits_per_flit = getParameter("NumberBitsPerFlit").toUInt();
+        unsigned int number_ingress_routers = getParameter("NumberIngressRouters").toUInt();
+        unsigned int number_middle_routers = getParameter("NumberMiddleRouters").toUInt();
+        unsigned int number_egress_routers = getParameter("NumberEgressRouters").toUInt();
+
+        ASSERT(clock_freq > 0, "[Error] " + getInstanceName() +
+                " -> Clock frequency must be > 0!");
+        ASSERT(number_input_sites > 0, "[Error] " + getInstanceName() + 
+                " -> Number of input sites must be > 0!");
+        ASSERT(number_output_sites > 0, "[Error] " + getInstanceName() + 
+                " -> Number of output sites must be > 0!");
+        ASSERT(number_bits_per_flit > 0, "[Error] " + getInstanceName() + 
+                " -> Number of bits per flit must be > 0!");
+        ASSERT(number_ingress_routers > 0, "[Error] " + getInstanceName() +
+                " -> Number of ingress routers must be > 0!");
+        ASSERT(number_middle_routers > 0, "[Error] " + getInstanceName() + 
+                " -> Number of middle routers must be > 0!");
+        ASSERT(number_egress_routers > 0, "[Error] " + getInstanceName() +
+                " -> Number of egress routers must be > 0!");
+
+        // Get input parameters that will be forwarded to the sub instances
+        const String& swsr_link_data_rate = getParameter("SWSR->LinkDataRate");
+        const String& swsr_laser_type = getParameter("SWSR->LaserType");
+        const String& swsr_ring_tuning_method = getParameter("SWSR->RingTuningMethod");
+        const String& router_number_vns = getParameter("Router->NumberVirtualNetworks");
+        const String& router_number_vcs_per_vn = getParameter("Router->NumberVirtualChannelsPerVirtualNetwork");
+        const String& router_number_bufs_per_vc = getParameter("Router->NumberBuffersPerVirtualChannel");
+        const String& router_buffer_model = getParameter("Router->InputPort->BufferModel");
+        const String& router_crossbar_model = getParameter("Router->CrossbarModel");
+        const String& link_wire_layer = getParameter("Link->WireLayer");
+        const String& link_wire_width_multiplier = getParameter("Link->WireWidthMultiplier");
+        const String& link_wire_spacing_multiplier = getParameter("Link->WireSpacingMultiplier");
+
+        // Calculate properties from input parameters
+        unsigned int ingress_router_number_input_ports = number_input_sites / number_ingress_routers;
+        unsigned int ingress_router_number_output_ports = number_middle_routers;
+        unsigned int middle_router_number_input_ports = number_ingress_routers;
+        unsigned int middle_router_number_output_ports = number_egress_routers;
+        unsigned int egress_router_number_input_ports = number_middle_routers;
+        unsigned int egress_router_number_output_ports = number_output_sites / number_egress_routers;
+        unsigned int number_input_to_ingress_links = number_input_sites;
+        unsigned int number_ingress_to_middle_links = number_ingress_routers * number_middle_routers;
+        unsigned int number_middle_to_egress_links = number_middle_routers * number_egress_routers;
+        unsigned int number_egress_to_output_links = number_output_sites;
+
+        getGenProperties()->set("NumberInputSitesPerIngressRouter", ingress_router_number_input_ports);
+        getGenProperties()->set("NumberOutputSitesPerEgressRouter", egress_router_number_output_ports);
+        getGenProperties()->set("IngressRouter->NumberInputPorts", ingress_router_number_input_ports);
+        getGenProperties()->set("IngressRouter->NumberOutputPorts", ingress_router_number_output_ports);
+        getGenProperties()->set("MiddleRouter->NumberInputPorts", middle_router_number_input_ports);
+        getGenProperties()->set("MiddleRouter->NumberOutputPorts", middle_router_number_output_ports);
+        getGenProperties()->set("EgressRouter->NumberInputPorts", egress_router_number_input_ports);
+        getGenProperties()->set("EgressRouter->NumberOutputPorts", egress_router_number_output_ports);
+
+        // Create ports
+        createInputPort("CK");
+
+        // Init ingress router
+        ElectricalModel* ingress_router = (ElectricalModel*)ModelGen::createModel("Router", "IngressRouter", getTechModel());
+        ingress_router->setParameter("NumberInputPorts", ingress_router_number_input_ports);
+        ingress_router->setParameter("NumberOutputPorts", ingress_router_number_output_ports);
+        ingress_router->setParameter("NumberVirtualNetworks", router_number_vns);
+        ingress_router->setParameter("NumberVirtualChannelsPerVirtualNetwork", router_number_vcs_per_vn);
+        ingress_router->setParameter("NumberBuffersPerVirtualChannel", router_number_bufs_per_vc);
+        ingress_router->setParameter("NumberBitsPerFlit", number_bits_per_flit);
+        ingress_router->setParameter("InputPort->BufferModel", router_buffer_model);
+        ingress_router->setParameter("CrossbarModel", router_crossbar_model);
+        ingress_router->setParameter("SwitchAllocator->ArbiterModel", getParameter("Router->SwitchAllocator->ArbiterModel"));
+        ingress_router->setParameter("ClockTreeModel", getParameter("Router->ClockTreeModel"));
+        ingress_router->setParameter("ClockTree->NumberLevels", getParameter("Router->ClockTree->NumberLevels"));
+        ingress_router->setParameter("ClockTree->WireLayer", getParameter("Router->ClockTree->WireLayer"));
+        ingress_router->setParameter("ClockTree->WireWidthMultiplier", getParameter("Router->ClockTree->WireWidthMultiplier"));
+        ingress_router->setParameter("ClockTree->WireSpacingMultiplier", getParameter("Router->ClockTree->WireSpacingMultiplier"));
+        ingress_router->construct();
+        // Init middle routers
+        ElectricalModel* middle_router = (ElectricalModel*)ModelGen::createModel("Router", "MiddleRouter", getTechModel());
+        middle_router->setParameter("NumberInputPorts", middle_router_number_input_ports);
+        middle_router->setParameter("NumberOutputPorts", middle_router_number_output_ports);
+        middle_router->setParameter("NumberVirtualNetworks", router_number_vns);
+        middle_router->setParameter("NumberVirtualChannelsPerVirtualNetwork", router_number_vcs_per_vn);
+        middle_router->setParameter("NumberBuffersPerVirtualChannel", router_number_bufs_per_vc);
+        middle_router->setParameter("NumberBitsPerFlit", number_bits_per_flit);
+        middle_router->setParameter("InputPort->BufferModel", router_buffer_model);
+        middle_router->setParameter("CrossbarModel", router_crossbar_model);
+        middle_router->setParameter("SwitchAllocator->ArbiterModel", getParameter("Router->SwitchAllocator->ArbiterModel"));
+        middle_router->setParameter("ClockTreeModel", getParameter("Router->ClockTreeModel"));
+        middle_router->setParameter("ClockTree->NumberLevels", getParameter("Router->ClockTree->NumberLevels"));
+        middle_router->setParameter("ClockTree->WireLayer", getParameter("Router->ClockTree->WireLayer"));
+        middle_router->setParameter("ClockTree->WireWidthMultiplier", getParameter("Router->ClockTree->WireWidthMultiplier"));
+        middle_router->setParameter("ClockTree->WireSpacingMultiplier", getParameter("Router->ClockTree->WireSpacingMultiplier"));
+        middle_router->construct();
+        // Init egress routers
+        ElectricalModel* egress_router = (ElectricalModel*)ModelGen::createModel("Router", "EgressRouter", getTechModel());
+        egress_router->setParameter("NumberInputPorts", egress_router_number_input_ports);
+        egress_router->setParameter("NumberOutputPorts", egress_router_number_output_ports);
+        egress_router->setParameter("NumberVirtualNetworks", router_number_vns);
+        egress_router->setParameter("NumberVirtualChannelsPerVirtualNetwork", router_number_vcs_per_vn);
+        egress_router->setParameter("NumberBuffersPerVirtualChannel", router_number_bufs_per_vc);
+        egress_router->setParameter("NumberBitsPerFlit", number_bits_per_flit);
+        egress_router->setParameter("InputPort->BufferModel", router_buffer_model);
+        egress_router->setParameter("CrossbarModel", router_crossbar_model);
+        egress_router->setParameter("SwitchAllocator->ArbiterModel", getParameter("Router->SwitchAllocator->ArbiterModel"));
+        egress_router->setParameter("ClockTreeModel", getParameter("Router->ClockTreeModel"));
+        egress_router->setParameter("ClockTree->NumberLevels", getParameter("Router->ClockTree->NumberLevels"));
+        egress_router->setParameter("ClockTree->WireLayer", getParameter("Router->ClockTree->WireLayer"));
+        egress_router->setParameter("ClockTree->WireWidthMultiplier", getParameter("Router->ClockTree->WireWidthMultiplier"));
+        egress_router->setParameter("ClockTree->WireSpacingMultiplier", getParameter("Router->ClockTree->WireSpacingMultiplier"));
+        egress_router->construct();
+        // Init input to ingress link
+        ElectricalModel* input_to_ingress_link = (ElectricalModel*)ModelGen::createModel("RepeatedLink", "InputToIngressLink", getTechModel());
+        input_to_ingress_link->setParameter("NumberBits", number_bits_per_flit);
+        input_to_ingress_link->setParameter("WireLayer", link_wire_layer);
+        input_to_ingress_link->setParameter("WireWidthMultiplier", link_wire_width_multiplier);
+        input_to_ingress_link->setParameter("WireSpacingMultiplier", link_wire_spacing_multiplier);
+        input_to_ingress_link->construct();
+        // Init ingress to middle link
+        ElectricalModel* ingress_to_middle_link = (ElectricalModel*)ModelGen::createModel("SWSRLink", "IngressToMiddleLink", getTechModel());
+        ingress_to_middle_link->setParameter("NumberBits", number_bits_per_flit);
+        ingress_to_middle_link->setParameter("CoreDataRate", clock_freq);
+        ingress_to_middle_link->setParameter("LinkDataRate", swsr_link_data_rate);
+        ingress_to_middle_link->setParameter("LaserType", swsr_laser_type);
+        ingress_to_middle_link->setParameter("RingTuningMethod", swsr_ring_tuning_method);
+        ingress_to_middle_link->construct();
+        // Init middle to egress link
+        ElectricalModel* middle_to_egress_link = (ElectricalModel*)ModelGen::createModel("SWSRLink", "MiddleToEgressLink", getTechModel());
+        middle_to_egress_link->setParameter("NumberBits", number_bits_per_flit);
+        middle_to_egress_link->setParameter("CoreDataRate", clock_freq);
+        middle_to_egress_link->setParameter("LinkDataRate", swsr_link_data_rate);
+        middle_to_egress_link->setParameter("LaserType", swsr_laser_type);
+        middle_to_egress_link->setParameter("RingTuningMethod", swsr_ring_tuning_method);
+        middle_to_egress_link->construct();
+        // Init egress to output link
+        ElectricalModel* egress_to_output_link = (ElectricalModel*)ModelGen::createModel("RepeatedLink", "EgressToOutputLink", getTechModel());
+        egress_to_output_link->setParameter("NumberBits", number_bits_per_flit);
+        egress_to_output_link->setParameter("WireLayer", link_wire_layer);
+        egress_to_output_link->setParameter("WireWidthMultiplier", link_wire_width_multiplier);
+        egress_to_output_link->setParameter("WireSpacingMultiplier", link_wire_spacing_multiplier);
+        egress_to_output_link->construct();
+
+        // Connect ports
+        createNet("InputToIngressLink_Out", makeNetIndex(0, number_bits_per_flit - 1));
+        createNet("InputToIngressLink_In", makeNetIndex(0, number_bits_per_flit - 1));
+        portConnect(input_to_ingress_link, "In", "InputToIngressLink_In");
+        portConnect(input_to_ingress_link, "Out", "InputToIngressLink_Out");
+
+        createNet("IngressToMiddleLink_In", makeNetIndex(0, number_bits_per_flit - 1));
+        createNet("IngressToMiddleLink_Out", makeNetIndex(0, number_bits_per_flit - 1));
+        portConnect(ingress_to_middle_link, "In", "IngressToMiddleLink_In");
+        portConnect(ingress_to_middle_link, "Out", "IngressToMiddleLink_Out");
+
+        createNet("MiddleToEgressLink_In", makeNetIndex(0, number_bits_per_flit - 1));
+        createNet("MiddleToEgressLink_Out", makeNetIndex(0, number_bits_per_flit - 1));
+        portConnect(middle_to_egress_link, "In", "MiddleToEgressLink_In");
+        portConnect(middle_to_egress_link, "Out", "MiddleToEgressLink_Out");
+
+        createNet("EgressToOutputLink_In", makeNetIndex(0, number_bits_per_flit - 1));
+        createNet("EgressToOutputLink_Out", makeNetIndex(0, number_bits_per_flit - 1));
+        portConnect(egress_to_output_link, "In", "EgressToOutputLink_In");
+        portConnect(egress_to_output_link, "Out", "EgressToOutputLink_Out");
+
+        portConnect(ingress_router, "CK", "CK");
+        for(unsigned int i = 0; i < ingress_router_number_input_ports; ++i)
+        {
+            createNet("IngressRouter_In" + (String)i, makeNetIndex(0, number_bits_per_flit-1));
+            for (unsigned int j = 0; j < number_bits_per_flit; ++j)
+                assignVirtualFanout("IngressRouter_In" + (String)i, makeNetIndex(j), "InputToIngressLink_Out", makeNetIndex(j));
+            portConnect(ingress_router, "FlitIn" + (String)i, "IngressRouter_In" + (String)i);
+        }
+        for(unsigned int i = 0; i < ingress_router_number_output_ports; ++i)
+        {
+            // VFI
+            portConnect(ingress_router, "FlitOut" + (String)i, "IngressToMiddleLink_In");
+        }
+        portConnect(middle_router, "CK", "CK");
+        for(unsigned int i = 0; i < middle_router_number_input_ports; ++i)
+        {
+            createNet("MiddleRouter_In" + (String)i, makeNetIndex(0, number_bits_per_flit-1));
+            for (unsigned int j = 0; j < number_bits_per_flit; ++j)
+                assignVirtualFanout("MiddleRouter_In" + (String)i, makeNetIndex(j), "IngressToMiddleLink_Out", makeNetIndex(j));
+            portConnect(middle_router, "FlitIn" + (String)i, "MiddleRouter_In" + (String)i);
+        }
+        for(unsigned int i = 0; i < middle_router_number_output_ports; ++i)
+        {
+            // VFI
+            portConnect(middle_router, "FlitOut" + (String)i, "MiddleToEgressLink_In");
+        }        
+        portConnect(egress_router, "CK", "CK");
+        for(unsigned int i = 0; i < egress_router_number_input_ports; ++i)
+        {
+            createNet("EgressRouter_In" + (String)i, makeNetIndex(0, number_bits_per_flit-1));
+            for (unsigned int j = 0; j < number_bits_per_flit; ++j)
+                assignVirtualFanout("EgressRouter_In" + (String)i, makeNetIndex(j), "MiddleToEgressLink_Out", makeNetIndex(j));
+            portConnect(egress_router, "FlitIn" + (String)i, "EgressRouter_In" + (String)i);
+        }
+        for(unsigned int i = 0; i < egress_router_number_output_ports; ++i)
+        {
+            // VFI
+            portConnect(egress_router, "FlitOut" + (String)i, "EgressToOutputLink_In");
+        }
+
+        // Create area, power, and event results
+        createElectricalResults();
+        createElectricalEventResult("AvgUnicast");
+        createElectricalEventResult("AvgBroadcast");
+        addNddPowerResult(new Result("Laser"));
+        addNddPowerResult(new Result("RingTuning"));
+        addAreaResult(new Result("Photonic"));
+
+        // Add all instances
+        addSubInstances(ingress_router, number_ingress_routers);
+        addElectricalSubResults(ingress_router, number_ingress_routers);
+        addSubInstances(middle_router, number_middle_routers);
+        addElectricalSubResults(middle_router, number_middle_routers);
+        addSubInstances(egress_router, number_egress_routers);
+        addElectricalSubResults(egress_router, number_egress_routers);
+        addSubInstances(input_to_ingress_link, number_input_to_ingress_links);
+        addElectricalSubResults(input_to_ingress_link, number_input_to_ingress_links);
+        addSubInstances(ingress_to_middle_link, number_ingress_to_middle_links);
+        addElectricalSubResults(ingress_to_middle_link, number_ingress_to_middle_links);
+        getAreaResult("Photonic")->addSubResult(ingress_to_middle_link->getAreaResult("Photonic"), "IngressToMiddleLink", number_ingress_to_middle_links);
+        getNddPowerResult("Laser")->addSubResult(ingress_to_middle_link->getNddPowerResult("Laser"), "IngressToMiddleLink", number_ingress_to_middle_links);
+        getNddPowerResult("RingTuning")->addSubResult(ingress_to_middle_link->getNddPowerResult("RingTuning"), "IngressToMiddleLink", number_ingress_to_middle_links);
+        addSubInstances(middle_to_egress_link, number_middle_to_egress_links);
+        addElectricalSubResults(middle_to_egress_link, number_middle_to_egress_links);
+        getAreaResult("Photonic")->addSubResult(middle_to_egress_link->getAreaResult("Photonic"), "MiddletoEgressLink", number_middle_to_egress_links);
+        getNddPowerResult("Laser")->addSubResult(middle_to_egress_link->getNddPowerResult("Laser"), "MiddleToEgressLink", number_middle_to_egress_links);        
+        getNddPowerResult("RingTuning")->addSubResult(middle_to_egress_link->getNddPowerResult("RingTuning"), "MiddleToEgressLink", number_middle_to_egress_links);        
+        addSubInstances(egress_to_output_link, number_egress_to_output_links);
+        addElectricalSubResults(egress_to_output_link, number_egress_to_output_links);
+
+        // Update unicast event
+        Result* avg_unicast_event = getEventResult("AvgUnicast");
+        avg_unicast_event->addSubResult(input_to_ingress_link->getEventResult("Send"), "InputToIngressLink", 1.0);
+        if(ingress_router->hasEventResult("WriteBuffer"))
+        {
+            avg_unicast_event->addSubResult(ingress_router->getEventResult("WriteBuffer"), "IngressRouter", 1.0);
+        }
+        if(ingress_router->hasEventResult("ReadBuffer"))
+        {
+            avg_unicast_event->addSubResult(ingress_router->getEventResult("ReadBuffer"), "IngressRouter", 1.0);
+        }
+        avg_unicast_event->addSubResult(ingress_router->getEventResult("TraverseCrossbar->Multicast1"), "IngressRouter", 1.0);
+        avg_unicast_event->addSubResult(ingress_to_middle_link->getEventResult("Send"), "IngressToMiddleLink", 1.0);
+        if(middle_router->hasEventResult("WriteBuffer"))
+        {
+            avg_unicast_event->addSubResult(middle_router->getEventResult("WriteBuffer"), "MiddleRouter", 1.0);
+        }
+        if(middle_router->hasEventResult("ReadBuffer"))
+        {
+            avg_unicast_event->addSubResult(middle_router->getEventResult("ReadBuffer"), "MiddleRouter", 1.0);
+        }
+        avg_unicast_event->addSubResult(middle_router->getEventResult("TraverseCrossbar->Multicast1"), "MiddleRouter", 1.0);
+        avg_unicast_event->addSubResult(middle_to_egress_link->getEventResult("Send"), "MiddleToEgressLink", 1.0);
+        if(egress_router->hasEventResult("WriteBuffer"))
+        {
+            avg_unicast_event->addSubResult(egress_router->getEventResult("WriteBuffer"), "EgressRouter", 1.0);
+        }
+        if(egress_router->hasEventResult("ReadBuffer"))
+        {
+            avg_unicast_event->addSubResult(egress_router->getEventResult("ReadBuffer"), "EgressRouter", 1.0);
+        }
+        avg_unicast_event->addSubResult(egress_router->getEventResult("TraverseCrossbar->Multicast1"), "EgressRouter", 1.0);
+        avg_unicast_event->addSubResult(egress_to_output_link->getEventResult("Send"), "EgressToOutputLink", 1.0);
+
+        // Update broadcast event
+        Result* avg_broadcast_event = getEventResult("AvgBroadcast");
+        avg_broadcast_event->addSubResult(input_to_ingress_link->getEventResult("Send"), "InputToIngressLink", 1.0);
+        if(ingress_router->hasEventResult("WriteBuffer"))
+        {
+            avg_broadcast_event->addSubResult(ingress_router->getEventResult("WriteBuffer"), "IngressRouter", 1.0);
+        }
+        if(ingress_router->hasEventResult("ReadBuffer"))
+        {
+            avg_broadcast_event->addSubResult(ingress_router->getEventResult("ReadBuffer"), "IngressRouter", 1.0);
+        }
+        avg_broadcast_event->addSubResult(ingress_router->getEventResult("TraverseCrossbar->Multicast1"), "IngressRouter", 1.0);
+        avg_broadcast_event->addSubResult(ingress_to_middle_link->getEventResult("Send"), "IngressToMiddleLink", 1.0);
+        if(middle_router->hasEventResult("WriteBuffer"))
+        {
+            avg_broadcast_event->addSubResult(middle_router->getEventResult("WriteBuffer"), "MiddleRouter", 1.0);
+        }
+        if(middle_router->hasEventResult("ReadBuffer"))
+        {
+            avg_broadcast_event->addSubResult(middle_router->getEventResult("ReadBuffer"), "MiddleRouter", 1.0);
+        }
+        avg_broadcast_event->addSubResult(middle_router->getEventResult("TraverseCrossbar->Multicast1"), "MiddleRouter", 1.0);
+        avg_broadcast_event->addSubResult(middle_to_egress_link->getEventResult("Send"), "MiddleToEgressLink", number_egress_routers);
+        if(egress_router->hasEventResult("WriteBuffer"))
+        {
+            avg_broadcast_event->addSubResult(egress_router->getEventResult("WriteBuffer"), "EgressRouter", number_egress_routers);
+        }
+        if(egress_router->hasEventResult("ReadBuffer"))
+        {
+            avg_broadcast_event->addSubResult(egress_router->getEventResult("ReadBuffer"), "EgressRouter", number_egress_routers);
+        }
+        avg_broadcast_event->addSubResult(egress_router->getEventResult("TraverseCrossbar->Multicast" + (String)number_egress_routers), "EgressRouter", 1.0);
+        avg_broadcast_event->addSubResult(egress_to_output_link->getEventResult("Send"), "EgressToOutputLink", number_output_sites);
+        return;
+    }
+
+    void PhotonicClos::updateModel()
+    {
+        // Assumes waveguide runs adjacent to ingress and egress routers
+        // Assumes input sites belonging to each ingress router are centered around the ingress router
+        // Assumes middle routers are distributed around the chip adjacent to the main waveguide
+        // Assumes output sites belonging to each egress router are centered around the egress router
+
+        // Get properties
+        double input_site_pitch = getProperty("InputSitePitch").toDouble();
+        double output_site_pitch = getProperty("OutputSitePitch").toDouble();
+        double clock_freq = getParameter("Frequency");
+               const double swsr_opt_util = getProperty("SWSR->OptUtil");
+
+        ASSERT(input_site_pitch > 0, "[Error] " + getInstanceName() + 
+                " -> Input site pitch must be > 0!");
+        ASSERT(output_site_pitch > 0, "[Error] " + getInstanceName() + 
+                " -> Output site pitch must be > 0!");
+
+        unsigned int number_input_sites_per_ingress_router = getGenProperties()->get("NumberInputSitesPerIngressRouter");
+        unsigned int number_ingress_routers = getParameter("NumberIngressRouters");
+        unsigned int number_output_sites_per_egress_router = getGenProperties()->get("NumberOutputSitesPerEgressRouter");
+        unsigned int number_egress_routers = getParameter("NumberEgressRouters");
+        double delay = 1.0 / clock_freq;
+
+        //Calculate the length of the waveguide
+        double input_to_ingress_link_length = input_site_pitch * (sqrt(number_input_sites_per_ingress_router) - 1.0);
+        double input_to_ingress_link_delay = delay * 0.8;
+        double ingress_to_middle_link_length = input_site_pitch * (sqrt(number_input_sites_per_ingress_router) * number_ingress_routers);
+        double middle_to_egress_link_length = output_site_pitch * (sqrt(number_output_sites_per_egress_router) * number_egress_routers);
+        double egress_to_output_link_length = output_site_pitch * (sqrt(number_output_sites_per_egress_router) - 1.0);
+        double egress_to_output_link_delay = delay * 0.8;
+        double ingress_router_delay = delay;
+        double middle_router_delay = delay;
+        double egress_router_delay = delay;
+
+        Model* input_to_ingress_link = getSubInstance("InputToIngressLink");
+        input_to_ingress_link->setProperty("WireLength", input_to_ingress_link_length);
+        input_to_ingress_link->setProperty("Delay", input_to_ingress_link_delay);
+        input_to_ingress_link->setProperty("IsKeepParity", "TRUE");
+        input_to_ingress_link->update();
+
+        Model* ingress_to_middle_link = getSubInstance("IngressToMiddleLink");
+        ingress_to_middle_link->setProperty("Length", ingress_to_middle_link_length);
+               ingress_to_middle_link->setProperty("OptUtil", swsr_opt_util);
+        ingress_to_middle_link->update();
+
+        Model* middle_to_egress_link = getSubInstance("MiddleToEgressLink");
+        middle_to_egress_link->setProperty("Length", middle_to_egress_link_length);
+               middle_to_egress_link->setProperty("OptUtil", swsr_opt_util);
+        middle_to_egress_link->update();
+
+        Model* egress_to_output_link = getSubInstance("EgressToOutputLink");
+        egress_to_output_link->setProperty("WireLength", egress_to_output_link_length);
+        egress_to_output_link->setProperty("Delay", egress_to_output_link_delay);
+        egress_to_output_link->setProperty("IsKeepParity", "TRUE");
+        egress_to_output_link->update();
+
+        ElectricalModel* ingress_router = (ElectricalModel*)getSubInstance("IngressRouter");
+        ingress_router->update();
+        ElectricalTimingTree ingress_router_timing_tree("IngressRouter", ingress_router);
+        ingress_router_timing_tree.performTimingOpt(ingress_router->getNet("CK"), ingress_router_delay);
+
+        ElectricalModel* middle_router = (ElectricalModel*)getSubInstance("MiddleRouter");
+        middle_router->update();
+        ElectricalTimingTree middle_router_timing_tree("MiddleRouter", middle_router);
+        middle_router_timing_tree.performTimingOpt(middle_router->getNet("CK"), middle_router_delay);
+
+        ElectricalModel* egress_router = (ElectricalModel*)getSubInstance("EgressRouter");
+        egress_router->update();
+        ElectricalTimingTree egress_router_timing_tree("EgressRouter", egress_router);
+        egress_router_timing_tree.performTimingOpt(egress_router->getNet("CK"), egress_router_delay);
+
+        return;
+    }
+    
+    void PhotonicClos::propagateTransitionInfo()
+    {
+        // Get parameters
+        double clock_freq = getParameter("Frequency");
+        double swsr_link_data_rate = getParameter("SWSR->LinkDataRate");
+
+        // Get properties
+        unsigned int ingress_router_number_input_ports = getGenProperties()->get("IngressRouter->NumberInputPorts");
+        unsigned int middle_router_number_input_ports = getGenProperties()->get("MiddleRouter->NumberInputPorts");
+        unsigned int egress_router_number_input_ports = getGenProperties()->get("EgressRouter->NumberInputPorts");
+
+        ElectricalModel* input_to_ingress_link = (ElectricalModel*)getSubInstance("InputToIngressLink");
+        assignPortTransitionInfo(input_to_ingress_link, "In", TransitionInfo(0.25, 0.25, 0.25));
+        input_to_ingress_link->use();
+
+        ElectricalModel* ingress_to_middle_link = (ElectricalModel*)getSubInstance("IngressToMiddleLink");
+        assignPortTransitionInfo(ingress_to_middle_link, "LinkCK", TransitionInfo(0.0, (double) clock_freq / (swsr_link_data_rate * 2.0), 0.0));
+        assignPortTransitionInfo(ingress_to_middle_link, "In", TransitionInfo(0.25, 0.25, 0.25));
+        ingress_to_middle_link->use();
+
+        ElectricalModel* middle_to_egress_link = (ElectricalModel*)getSubInstance("MiddleToEgressLink");
+        assignPortTransitionInfo(middle_to_egress_link, "LinkCK", TransitionInfo(0.0, (double) clock_freq / (swsr_link_data_rate * 2.0), 0.0));
+        assignPortTransitionInfo(middle_to_egress_link, "In", TransitionInfo(0.25, 0.25, 0.25));
+        middle_to_egress_link->use();
+
+        ElectricalModel* egress_to_output_link = (ElectricalModel*)getSubInstance("EgressToOutputLink");
+        assignPortTransitionInfo(egress_to_output_link, "In", TransitionInfo(0.25, 0.25, 0.25));
+        egress_to_output_link->use();
+
+        ElectricalModel* ingress_router = (ElectricalModel*)getSubInstance("IngressRouter");
+        for(unsigned int i = 0; i < ingress_router_number_input_ports; ++i)
+        {
+            assignPortTransitionInfo(ingress_router, "FlitIn" + (String)i, TransitionInfo(0.25, 0.25, 0.25));
+        }
+        assignPortTransitionInfo(ingress_router, "CK", TransitionInfo(0.0, 1.0, 0.0));
+        ingress_router->getGenProperties()->set("UseModelEvent", "");
+        ingress_router->use();
+
+        ElectricalModel* middle_router = (ElectricalModel*)getSubInstance("MiddleRouter");
+        for(unsigned int i = 0; i < middle_router_number_input_ports; ++i)
+        {
+            assignPortTransitionInfo(middle_router, "FlitIn" + (String)i, TransitionInfo(0.25, 0.25, 0.25));
+        }
+        assignPortTransitionInfo(middle_router, "CK", TransitionInfo(0.0, 1.0, 0.0));
+        middle_router->getGenProperties()->set("UseModelEvent", "");
+        middle_router->use();
+
+        ElectricalModel* egress_router = (ElectricalModel*)getSubInstance("EgressRouter");
+        for(unsigned int i = 0; i < egress_router_number_input_ports; ++i)
+        {
+            assignPortTransitionInfo(egress_router, "FlitIn" + (String)i, TransitionInfo(0.25, 0.25, 0.25));
+        }
+        assignPortTransitionInfo(egress_router, "CK", TransitionInfo(0.0, 1.0, 0.0));
+        egress_router->getGenProperties()->set("UseModelEvent", "");
+        egress_router->use();
+
+        return;
+    }
+} // namespace DSENT
+
diff --git a/ext/dsent/model/network/PhotonicClos.h b/ext/dsent/model/network/PhotonicClos.h
new file mode 100644 (file)
index 0000000..814885d
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef __DSENT_MODEL_NETWORK_PHOTONIC_CLOS_H__
+#define __DSENT_MODEL_NETWORK_PHOTONIC_CLOS_H__
+
+#include "util/CommonType.h"
+#include "model/ElectricalModel.h"
+
+namespace DSENT
+{
+    /**
+     * \brief An 3-stage clos network implemented with photonic router-to-router links
+     */
+    class PhotonicClos : public ElectricalModel
+    {
+        public:
+            PhotonicClos(const String& instance_name_, const TechModel* tech_model_);
+            virtual ~PhotonicClos();
+
+        public:
+            // Set a list of properties' name needed to construct model
+            void initParameters();
+            // Set a list of properties' name needed to construct model
+            void initProperties();
+
+            // Clone and return a new instance
+            virtual PhotonicClos* clone() const;
+
+        protected:
+            // Build the model
+            virtual void constructModel();
+            virtual void updateModel();
+            virtual void propagateTransitionInfo();
+
+    };
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_NETWORK_PHOTONIC_CLOS_H__
+
diff --git a/ext/dsent/model/optical/GatedLaserSource.cc b/ext/dsent/model/optical/GatedLaserSource.cc
new file mode 100644 (file)
index 0000000..e32474d
--- /dev/null
@@ -0,0 +1,106 @@
+#include "model/optical/GatedLaserSource.h"
+
+#include "model/optical_graph/OpticalWaveguide.h"
+#include "model/optical_graph/OpticalWavelength.h"
+#include "model/optical_graph/OpticalLaser.h"
+#include "model/optical_graph/OpticalGraph.h"
+
+namespace DSENT
+{
+    GatedLaserSource::GatedLaserSource(const String& instance_name_, const TechModel* tech_model_)
+        : OpticalModel(instance_name_, tech_model_)
+    {
+        initParameters();
+        initProperties();
+    }
+
+    GatedLaserSource::~GatedLaserSource()
+    {}
+
+    void GatedLaserSource::initParameters()
+    {
+        addParameterName("OutStart");
+        addParameterName("OutEnd");
+        addParameterName("MaxDetectors");
+        return;
+    }
+
+    void GatedLaserSource::initProperties()
+    {
+               addPropertyName("OptUtil", 1.0);
+        addPropertyName("LaserEventTime");
+        return;
+    }
+
+    void GatedLaserSource::constructModel()
+    {
+        // Create Area result
+        Result* area_result = new AtomicResult("Photonic");
+        addAreaResult(area_result);
+        // Create NDD power result
+        Result* energy_result = new AtomicResult("Laser");
+        addEventResult(energy_result);
+    
+        // Get parameters
+        WavelengthGroup laser_wavelengths = makeWavelengthGroup(getParameter("OutStart"), getParameter("OutEnd"));
+
+        // Create optical ports
+        createOpticalOutputPort(    "Out",      laser_wavelengths);
+        // Create the filter
+        createLaser(                "Laser",    laser_wavelengths);
+        OpticalLaser* laser = getLaser("Laser");
+        // Connect the laser to the output
+        laser->addDownstreamNode(getWaveguide("Out"));
+    }
+    
+    void GatedLaserSource::updateModel()
+    {
+        // Get properties
+        double laser_efficiency = getTechModel()->get("Laser->CW->Efficiency");
+        double laser_area = getTechModel()->get("Laser->CW->Area");
+        double laser_diode_loss = getTechModel()->get("Laser->CW->LaserDiodeLoss");
+
+        // Get parameters
+        WavelengthGroup laser_wavelengths = makeWavelengthGroup(getParameter("OutStart"), getParameter("OutEnd"));
+        unsigned int number_wavelengths = laser_wavelengths.second - laser_wavelengths.first + 1;
+        // Update losses
+        OpticalLaser* laser = getLaser("Laser");
+        laser->setLoss(laser_diode_loss);
+        laser->setEfficiency(laser_efficiency);
+        // Update area
+        getAreaResult("Photonic")->setValue(laser_area * number_wavelengths);
+    }
+    
+    void GatedLaserSource::evaluateModel()
+    {    
+        // Get parameters
+        unsigned int max_detectors = getParameter("MaxDetectors");
+        double laser_event_time = getProperty("LaserEventTime");
+        WavelengthGroup laser_wavelengths = makeWavelengthGroup(getParameter("OutStart"), getParameter("OutEnd"));
+                
+               // Get properties
+               double opt_util = getProperty("OptUtil");
+
+        // Create optical graph object
+        OpticalGraph* optical_graph = new OpticalGraph("LaserTrace", this);        
+        // Ask optical graph object to perform power optimization
+        bool success = optical_graph->performPowerOpt(getLaser("Laser"), laser_wavelengths, max_detectors, opt_util);
+        if (!success)
+        {
+            Log::printLine(std::cerr, "[Warning] " + getInstanceName() +
+                " -> Wavelengths contains data paths with no possible modulator configurations!");
+        }        
+        // Trace the wavelengths the laser is outputting to find the output
+        // power needed by the laser        
+        OpticalWavelength* wavelength = optical_graph->traceWavelength(laser_wavelengths, getLaser("Laser"));                
+        // Calculate the power needed by the wavelength
+        double laser_power = wavelength->getLaserPower(max_detectors);
+        // Calculate NDD power
+        getEventResult("Laser")->setValue(laser_power * laser_event_time);
+        
+        delete wavelength;
+        delete optical_graph;
+    }
+    
+} // namespace DSENT
+
diff --git a/ext/dsent/model/optical/GatedLaserSource.h b/ext/dsent/model/optical/GatedLaserSource.h
new file mode 100644 (file)
index 0000000..b6413b0
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef __DSENT_MODEL_OPTICAL_GATEDLASERSOURCE_H__
+#define __DSENT_MODEL_OPTICAL_GATEDLASERSOURCE_H__
+
+#include "util/CommonType.h"
+#include "model/OpticalModel.h"
+
+namespace DSENT
+{
+    // A laser source that outputs some number of wavelengths. This laser
+    // full on/off power gating, thus all power are event-based energies
+    class GatedLaserSource : public OpticalModel
+    {
+        public:
+            GatedLaserSource(const String& instance_name_, const TechModel* tech_model_);
+            virtual ~GatedLaserSource();
+
+        public:
+            // Set a list of properties' name needed to construct model
+            void initParameters();
+            // Set a list of properties' name needed to construct model
+            void initProperties();
+
+        protected:
+            // Build the model
+            void constructModel();
+            void updateModel();
+            void evaluateModel();
+            
+    }; // class GatedLaserSource
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_OPTICAL_GATEDLASERSOURCE_H__
+
diff --git a/ext/dsent/model/optical/LaserSource.cc b/ext/dsent/model/optical/LaserSource.cc
new file mode 100644 (file)
index 0000000..e55de8c
--- /dev/null
@@ -0,0 +1,105 @@
+#include "model/optical/LaserSource.h"
+
+#include "model/optical_graph/OpticalWaveguide.h"
+#include "model/optical_graph/OpticalWavelength.h"
+#include "model/optical_graph/OpticalLaser.h"
+#include "model/optical_graph/OpticalGraph.h"
+
+namespace DSENT
+{
+    LaserSource::LaserSource(const String& instance_name_, const TechModel* tech_model_)
+        : OpticalModel(instance_name_, tech_model_)
+    {
+        initParameters();
+        initProperties();
+    }
+
+    LaserSource::~LaserSource()
+    {}
+
+    void LaserSource::initParameters()
+    {
+        addParameterName("OutStart");
+        addParameterName("OutEnd");
+        addParameterName("MaxDetectors");
+        return;
+    }
+
+    void LaserSource::initProperties()
+    {
+               addPropertyName("OptUtil", 1.0);
+        return;
+    }
+
+    void LaserSource::constructModel()
+    {
+        // Create Area result
+        Result* area_result = new AtomicResult("Photonic");
+        addAreaResult(area_result);
+        // Create NDD power result
+        Result* power_result = new AtomicResult("Laser");
+        addNddPowerResult(power_result);
+    
+        // Get parameters
+        WavelengthGroup laser_wavelengths = makeWavelengthGroup(getParameter("OutStart"), getParameter("OutEnd"));
+
+        // Create optical ports
+        createOpticalOutputPort(    "Out",      laser_wavelengths);
+        // Create the filter
+        createLaser(                "Laser",    laser_wavelengths);
+        OpticalLaser* laser = getLaser("Laser");
+        // Connect the laser to the output
+        laser->addDownstreamNode(getWaveguide("Out"));
+    }
+    
+    void LaserSource::updateModel()
+    {
+        // Get properties
+        double laser_efficiency = getTechModel()->get("Laser->CW->Efficiency").toDouble();
+        double laser_area = getTechModel()->get("Laser->CW->Area").toDouble();
+        double laser_diode_loss = getTechModel()->get("Laser->CW->LaserDiodeLoss");
+
+        // Get parameters
+        WavelengthGroup laser_wavelengths = makeWavelengthGroup(getParameter("OutStart"), getParameter("OutEnd"));
+        unsigned int number_wavelengths = laser_wavelengths.second - laser_wavelengths.first + 1;
+        // Update losses
+        OpticalLaser* laser = getLaser("Laser");
+        laser->setLoss(laser_diode_loss);
+        laser->setEfficiency(laser_efficiency);
+        // Update area
+        getAreaResult("Photonic")->setValue(laser_area * number_wavelengths);
+    }
+    
+    void LaserSource::evaluateModel()
+    {    
+        // Get parameters
+        unsigned int max_detectors = getParameter("MaxDetectors").toUInt();
+        WavelengthGroup laser_wavelengths = makeWavelengthGroup(getParameter("OutStart"), getParameter("OutEnd"));
+
+               // Get properties
+               double opt_util = getProperty("OptUtil");
+                
+        // Create optical graph object
+        OpticalGraph* optical_graph = new OpticalGraph("LaserTrace", this);        
+        // Ask optical graph object to perform power optimization
+        bool success = optical_graph->performPowerOpt(getLaser("Laser"), laser_wavelengths, max_detectors, opt_util);
+        if (!success)
+        {
+            Log::printLine(std::cerr, "[Warning] " + getInstanceName() +
+                " -> Wavelengths contains data paths with no possible modulator configurations!");
+        }        
+        // Trace the wavelengths the laser is outputting to find the output
+        // power needed by the laser        
+        OpticalWavelength* wavelength = optical_graph->traceWavelength(laser_wavelengths, getLaser("Laser"));                
+        // Calculate the power needed by the wavelength
+        double laser_power = wavelength->getLaserPower(max_detectors);
+        
+        // Calculate NDD power
+        getNddPowerResult("Laser")->setValue(laser_power);
+        
+        delete wavelength;
+        delete optical_graph;
+    }
+    
+} // namespace DSENT
+
diff --git a/ext/dsent/model/optical/LaserSource.h b/ext/dsent/model/optical/LaserSource.h
new file mode 100644 (file)
index 0000000..92c7658
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef __DSENT_MODEL_OPTICAL_LASERSOURCE_H__
+#define __DSENT_MODEL_OPTICAL_LASERSOURCE_H__
+
+#include "util/CommonType.h"
+#include "model/OpticalModel.h"
+
+namespace DSENT
+{
+    // A laser source that outputs some number of wavelengths. This laser cannot
+    // be gated on/off at will and thus constitutes an NDD Power consumer
+    class LaserSource : public OpticalModel
+    {
+        public:
+            LaserSource(const String& instance_name_, const TechModel* tech_model_);
+            virtual ~LaserSource();
+
+        public:
+            // Set a list of properties' name needed to construct model
+            void initParameters();
+            // Set a list of properties' name needed to construct model
+            void initProperties();
+
+        protected:
+            // Build the model
+            void constructModel();
+            void updateModel();
+            void evaluateModel();
+            
+    }; // class LaserSource
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_OPTICAL_LASERSOURCE_H__
+
diff --git a/ext/dsent/model/optical/OpticalLinkBackendRx.cc b/ext/dsent/model/optical/OpticalLinkBackendRx.cc
new file mode 100644 (file)
index 0000000..3a65cee
--- /dev/null
@@ -0,0 +1,364 @@
+#include "model/optical/OpticalLinkBackendRx.h"
+
+#include "util/Constants.h"
+#include "model/PortInfo.h"
+#include "model/TransitionInfo.h"
+#include "model/EventInfo.h"
+#include "model/electrical/DemuxTreeDeserializer.h"
+#include "model/electrical/BarrelShifter.h"
+#include "model/electrical/Multiplexer.h"
+#include <cmath>
+
+namespace DSENT
+{
+    // TODO: Kind of don't like the way thermal tuning is written here. Maybe will switch
+    // to curve fitting the CICC paper, which uses results from a monte-carlo sim. Also, there is
+    // redundant code between this one and the tx one...
+
+    OpticalLinkBackendRx::OpticalLinkBackendRx(const String& instance_name_, const TechModel* tech_model_)
+        : ElectricalModel(instance_name_, tech_model_)
+    {
+        initParameters();
+        initProperties();
+    }
+
+    OpticalLinkBackendRx::~OpticalLinkBackendRx()
+    {}
+
+    void OpticalLinkBackendRx::initParameters()
+    {
+        addParameterName("OutBits");
+        addParameterName("CoreDataRate");
+        addParameterName("LinkDataRate");
+        addParameterName("RingTuningMethod");
+        addParameterName("BitDuplicate");
+        return;
+    }
+
+    void OpticalLinkBackendRx::initProperties()
+    {
+        return;
+    }
+
+    void OpticalLinkBackendRx::constructModel()
+    {
+        unsigned int out_bits = getParameter("OutBits");
+        double core_data_rate = getParameter("CoreDataRate");
+        double link_data_rate = getParameter("LinkDataRate");
+        const String& tuning_method = getParameter("RingTuningMethod");
+        bool bit_duplicate = getParameter("BitDuplicate");
+
+        // Calculate deserialization ratio
+        unsigned int deserialization_ratio = (unsigned int) floor(link_data_rate / core_data_rate);    
+        ASSERT(deserialization_ratio == link_data_rate / core_data_rate,
+            "[Error] " + getInstanceName() + " -> Cannot have non-integer deserialization ratios!");
+        ASSERT((deserialization_ratio & (deserialization_ratio - 1)) == 0,
+            "[Error] " + getInstanceName() + " -> Deserialization ratio must be a power of 2");
+        
+        // Calculate output width
+        unsigned int in_bits = out_bits / deserialization_ratio;
+        ASSERT(out_bits >= deserialization_ratio, "[Error] " + getInstanceName() + 
+            " -> Output width must be >= deserialization ratio!");
+        ASSERT(floor((double) out_bits / deserialization_ratio) == in_bits,
+            "[Error] " + getInstanceName() + " -> Output width must be a multiple of the serialization ratio!");            
+
+        getGenProperties()->set("DeserializationRatio", deserialization_ratio);
+        getGenProperties()->set("InBits", in_bits);
+        
+        // Create ports
+        createInputPort("In", makeNetIndex(0, in_bits-1));
+        createInputPort("LinkCK");
+        createOutputPort("Out", makeNetIndex(0, out_bits-1));        
+        
+        //Create energy, power, and area results
+        createElectricalResults();
+        // Create ring heating power cost
+        addNddPowerResult(new AtomicResult("RingTuning"));
+        // Create process bits event
+        createElectricalEventResult("ProcessBits");
+        getEventInfo("ProcessBits")->setTransitionInfo("LinkCK", TransitionInfo(0.0, (double) deserialization_ratio / 2.0, 0.0));
+        // Set conditions during idle state
+        getEventInfo("Idle")->setStaticTransitionInfos();
+        getEventInfo("Idle")->setTransitionInfo("LinkCK", TransitionInfo(0.0, (double) deserialization_ratio / 2.0, 0.0));
+
+        // Create deserializer
+        const String& deserializer_name = "Deserializer";
+        DemuxTreeDeserializer* deserializer = new DemuxTreeDeserializer(deserializer_name, getTechModel());
+        deserializer->setParameter("OutBits", out_bits);
+        deserializer->setParameter("InDataRate", link_data_rate);
+        deserializer->setParameter("OutDataRate", core_data_rate);
+        deserializer->setParameter("BitDuplicate", bit_duplicate);
+        deserializer->construct();
+        
+        addSubInstances(deserializer, 1.0);
+        addElectricalSubResults(deserializer, 1.0);
+        getEventResult("ProcessBits")->addSubResult(deserializer->getEventResult("Deserialize"), deserializer_name, 1.0);
+        
+        if ((tuning_method == "ThermalWithBitReshuffle") || (tuning_method == "ElectricalAssistWithBitReshuffle"))
+        {            
+            // If a bit reshuffling backend is present, create the reshuffling backend
+            unsigned int reorder_degree = getBitReorderDegree();
+
+            // Create intermediate nets
+            createNet("ReorderIn", makeNetIndex(0, in_bits+reorder_degree-1));
+            assign("ReorderIn", makeNetIndex(0, in_bits-1), "In");
+            assign("ReorderIn", makeNetIndex(in_bits, in_bits+reorder_degree-1), "ReorderIn", makeNetIndex(0, reorder_degree-1));
+            createNet("DeserializerIn", makeNetIndex(0, in_bits-1));
+            createNet("BarrelShiftIn", makeNetIndex(0, out_bits-1));
+                        
+            // Create bit reorder muxes
+            const String& reorder_mux_name = "ReorderMux";
+            Multiplexer* reorder_mux = new Multiplexer(reorder_mux_name, getTechModel());
+            reorder_mux->setParameter("NumberBits", in_bits);
+            reorder_mux->setParameter("NumberInputs", reorder_degree);
+            reorder_mux->setParameter("BitDuplicate", bit_duplicate);
+            reorder_mux->construct();
+
+            // Create barrelshifter
+            unsigned int shift_index_min = (unsigned int)ceil(log2(deserialization_ratio));
+            unsigned int shift_index_max = std::max(shift_index_min, (unsigned int) ceil(log2(out_bits)) - 1);
+
+            // Remember some things
+            getGenProperties()->set("ReorderDegree", reorder_degree);
+            getGenProperties()->set("ShiftIndexMin", shift_index_min);
+            getGenProperties()->set("ShiftIndexMax", shift_index_max);
+            
+            const String& barrel_shift_name = "BarrelShifter";
+            BarrelShifter* barrel_shift = new BarrelShifter(barrel_shift_name, getTechModel());
+            barrel_shift->setParameter("NumberBits", out_bits);
+            barrel_shift->setParameter("ShiftIndexMax", shift_index_max);
+            barrel_shift->setParameter("ShiftIndexMin", shift_index_min);
+            barrel_shift->setParameter("BitDuplicate", bit_duplicate);
+            barrel_shift->construct();
+            
+            // Connect serializer
+            portConnect(deserializer, "In", "DeserializerIn");
+            portConnect(deserializer, "Out", "BarrelShiftIn");
+            portConnect(deserializer, "InCK", "LinkCK");
+
+            // Connect barrelshifter
+            // TODO: Connect barrelshift shifts!
+            portConnect(barrel_shift, "In", "BarrelShiftIn");
+            portConnect(barrel_shift, "Out", "Out");
+            
+            // Connect bit reorder muxes
+            // TODO: Connect re-order multiplex select signals!
+            for (unsigned int i = 0; i < reorder_degree; i++)
+                portConnect(reorder_mux, "In" + (String) i, "ReorderIn", makeNetIndex(i, i+in_bits-1));            
+            portConnect(reorder_mux, "Out", "DeserializerIn");
+            
+            addSubInstances(barrel_shift, 1.0);
+            addSubInstances(reorder_mux, 1.0);
+            addElectricalSubResults(barrel_shift, 1.0);
+            addElectricalSubResults(reorder_mux, 1.0);
+            getEventResult("ProcessBits")->addSubResult(barrel_shift->getEventResult("BarrelShift"), barrel_shift_name, 1.0);
+            getEventResult("ProcessBits")->addSubResult(reorder_mux->getEventResult("Mux"), reorder_mux_name, 1.0);
+        }
+        else if ((tuning_method == "FullThermal") || (tuning_method == "AthermalWithTrim"))
+        {
+            // If no bit reshuffling backend is present, then just connect deserializer up            
+            portConnect(deserializer, "In", "In");
+            portConnect(deserializer, "Out", "Out");
+            portConnect(deserializer, "InCK", "LinkCK");
+        }
+        else
+        {
+            ASSERT(false, "[Error] " + getInstanceName() + " -> Unknown ring tuning method '" + tuning_method + "'!");
+        }
+        
+        return;
+    }
+    
+    void OpticalLinkBackendRx::updateModel()
+    {
+        // Update everyone
+        Model::updateModel();
+        // Update ring tuning power
+        getNddPowerResult("RingTuning")->setValue(getRingTuningPower());        
+        return;
+    }
+
+    void OpticalLinkBackendRx::propagateTransitionInfo()
+    {
+        // Get parameters
+        const String& tuning_method = getParameter("RingTuningMethod");;
+
+        // Get properties
+        
+        // Update the deserializer        
+        if ((tuning_method == "ThermalWithBitReshuffle") || (tuning_method == "ElectricalAssistWithBitReshuffle"))
+        {
+            // Get generated properties
+            unsigned int reorder_degree = getGenProperties()->get("ReorderDegree");
+            unsigned int shift_index_min = getGenProperties()->get("ShiftIndexMin");
+            unsigned int shift_index_max = getGenProperties()->get("ShiftIndexMax"); 
+            
+            // Reorder mux shift select bits
+            unsigned int reorder_sel_bits = (unsigned int)ceil(log2(reorder_degree));
+
+            // Create bit reorder muxes
+            const String& reorder_mux_name = "ReorderMux";
+            ElectricalModel* reorder_mux = (ElectricalModel*) getSubInstance(reorder_mux_name);
+            for (unsigned int i = 0; i < reorder_degree; ++i)
+                propagatePortTransitionInfo(reorder_mux, "In" + (String) i, "In");
+            // Set select transitions to be 0, since these are statically configured
+            for (unsigned int i = 0; i < reorder_sel_bits; ++i)
+                reorder_mux->getInputPort("Sel" + (String) i)->setTransitionInfo(TransitionInfo(0.5, 0.0, 0.5));                
+            reorder_mux->use();
+
+            // Update the deserializer
+            ElectricalModel* deserializer = (ElectricalModel*) getSubInstance("Deserializer");
+            propagatePortTransitionInfo(deserializer, "In", reorder_mux, "Out");
+            propagatePortTransitionInfo(deserializer, "InCK", "LinkCK");
+            deserializer->use();
+            
+            // Update barrel shifter
+            const String& barrel_shift_name = "BarrelShifter";
+            ElectricalModel* barrel_shift = (ElectricalModel*) getSubInstance(barrel_shift_name);
+            propagatePortTransitionInfo(barrel_shift, "In", deserializer, "Out");
+            // Set shift transitions to be very low (since it is affected by slow temperature time constants)
+            for (unsigned int i = shift_index_min; i <= shift_index_max; ++i)
+                barrel_shift->getInputPort("Shift" + (String) i)->setTransitionInfo(TransitionInfo(0.499, 0.001, 0.499));
+            barrel_shift->use();
+            
+            // Set output transition info
+            propagatePortTransitionInfo("Out", barrel_shift, "Out");
+        }
+        else if ((tuning_method == "FullThermal") || (tuning_method == "AthermalWithTrim"))
+        {
+            // Update the deserializer
+            ElectricalModel* deserializer = (ElectricalModel*) getSubInstance("Deserializer");
+            propagatePortTransitionInfo(deserializer, "In", "In");
+            propagatePortTransitionInfo(deserializer, "InCK", "LinkCK");
+            deserializer->use();
+
+            // Set output transition info
+            propagatePortTransitionInfo("Out", deserializer, "Out");
+        }
+        else
+        {
+            ASSERT(false, "[Error] " + getInstanceName() + " -> Unknown ring tuning method '" + tuning_method + "'!");
+        }
+
+        return;
+    }
+    
+    double OpticalLinkBackendRx::getRingTuningPower()
+    {
+        // Get properties
+        const String& tuning_method = getParameter("RingTuningMethod");;
+        unsigned int number_rings = getGenProperties()->get("InBits");        
+
+        // Get tech model parameters
+        double R = getTechModel()->get("Ring->Radius");
+        double n_g = getTechModel()->get("Ring->GroupIndex");
+        double heating_efficiency = getTechModel()->get("Ring->HeatingEfficiency");
+        // This can actually be derived if we know thermo-optic coefficient (delta n / delta T)
+        double tuning_efficiency = getTechModel()->get("Ring->TuningEfficiency");        
+        double sigma_r_local = getTechModel()->get("Ring->LocalVariationSigma");
+        double sigma_r_systematic = getTechModel()->get("Ring->SystematicVariationSigma");
+        double T_max = getTechModel()->get("Ring->TemperatureMax");
+        double T_min = getTechModel()->get("Ring->TemperatureMin");
+        double T = getTechModel()->get("Temperature");
+        
+        // Get constants
+        double c = Constants::c;
+        double pi = Constants::pi;
+        
+        double tuning_power = 0.0;
+        
+        if (tuning_method == "ThermalWithBitReshuffle")
+        {
+            // When an electrical backend is present, rings only have to tune to the nearest channel
+            // This can be approximated as each ring tuning to something exactly 1 channel away
+
+            // Setup calculations
+            double L = 2 * pi * R;                  // Optical length
+            double FSR = c / (n_g * L);             // Free spectral range
+            double freq_sep = FSR / number_rings;   // Channel separation
+            
+            // Calculate tuning power
+            tuning_power = number_rings * freq_sep / (tuning_efficiency * heating_efficiency);
+        }
+        else if (tuning_method == "ElectricalAssistWithBitReshuffle")
+        {
+            // Electrical assistance allows for a fraction of the tuning range to be
+            // covered electrically. This is most pronounced when the tuning range is small,
+            // such is the case when bit reshuffling is applied
+
+            // Get electrically tunable range
+            double max_assist = getTechModel()->get("Ring->MaxElectricallyTunableFreq");
+            
+            // Setup calculations
+            double L = 2 * pi * R;                  // Optical length
+            double FSR = c / (n_g * L);             // Free spectral range
+            double freq_sep = FSR / number_rings;   // Channel separation
+            double heating_range = std::max(0.0, freq_sep - max_assist);  // The distance needed to bridge using heaters            
+            
+            // Calculate tuning power, which is really only the power spent on heating since
+            // distance tuned electrically is pretty much free
+            tuning_power = number_rings * heating_range / (tuning_efficiency * heating_efficiency);            
+        }        
+        else if (tuning_method == "FullThermal")
+        {
+            // If there is no bit reshuffling backend, each ring must tune to an
+            // absolute channel frequency. Since we can only heat rings (and not cool),
+            // we can only red-shift (decrease frequency). Thus, a fabrication bias
+            // must be applied such that under any process and temperature corner, the
+            // ring resonance remains above channel resonance
+            // I'll use 3 sigmas of sigma_r_local and sigma_r_systematic, and bias against
+            // the full temperature range
+            double fabrication_bias_freq = 3.0 * sqrt(pow(sigma_r_local, 2) + pow(sigma_r_systematic, 2)) +
+                (T_max - T_min) * tuning_efficiency;
+                
+            // The local/systematic variations are 0 on average. Thus, the tuning distance can be calculated as
+            double tuning_distance = fabrication_bias_freq - (T - T_min) * tuning_efficiency;
+            
+            // Tuning power needed is just the number of rings * tuning distance / (tuning and heating efficiencies)
+            tuning_power = number_rings * tuning_distance / (tuning_efficiency * heating_efficiency);
+        }
+        else if (tuning_method == "AthermalWithTrim")
+        {
+            // Athermal!
+            tuning_power = 0;
+        }
+        else
+        {
+            ASSERT(false, "[Error] " + getInstanceName() + " -> Unknown ring tuning method '" + tuning_method + "'!");
+        }
+
+        return tuning_power;
+    }
+    
+    unsigned int OpticalLinkBackendRx::getBitReorderDegree()
+    {
+        // Get properties
+        unsigned int number_rings = getGenProperties()->get("InBits");        
+
+        // Get tech model parameters
+        double R = getTechModel()->get("Ring->Radius");
+        double n_g = getTechModel()->get("Ring->GroupIndex");
+        // This can actually be derived if we know thermo-optic coefficient (delta n / delta T)
+        double sigma_r_local = getTechModel()->get("Ring->LocalVariationSigma");
+        
+        // Get constants
+        double c = Constants::c;
+        double pi = Constants::pi;
+        
+        // Calculates the degree of bit re-order multiplexing needed for bit-reshuffling backend
+        // Bit reshuffling tuning is largely unaffected by sigma_r_systematic. However, sigma_r_local
+        // Can potentially throw each ring to a channel several channels away. This just calculates
+        // the degree of bit reorder muxing needed to realign bits in the correct order
+
+        // Setup calculations
+        double L = 2 * pi * R;                  // Optical length
+        double FSR = c / (n_g * L);             // Free spectral range
+        double freq_sep = FSR / number_rings;   // Channel separation        
+        // Using 4 sigmas as the worst re-ordering case (must double to get both sides)
+        unsigned int worst_case_channels = (unsigned int)ceil(2.0 * 4.0 * sigma_r_local / freq_sep);
+        
+        return worst_case_channels;
+    }
+    
+} // namespace DSENT
+
diff --git a/ext/dsent/model/optical/OpticalLinkBackendRx.h b/ext/dsent/model/optical/OpticalLinkBackendRx.h
new file mode 100644 (file)
index 0000000..19f3966
--- /dev/null
@@ -0,0 +1,39 @@
+#ifndef __DSENT_MODEL_OPTICAL_OPTICALLINKBACKENDRX_H__
+#define __DSENT_MODEL_OPTICAL_OPTICALLINKBACKENDRX_H__
+
+#include "util/CommonType.h"
+#include "model/ElectricalModel.h"
+
+namespace DSENT
+{
+    class OpticalLinkBackendRx : public ElectricalModel
+    {
+        // An optical link backend rx contains everything needed for thermal
+        // tuning of rings, bit-reshuffling (if necessary), and deserialization (if necessary)
+        public:
+            OpticalLinkBackendRx(const String& instance_name_, const TechModel* tech_model_);
+            virtual ~OpticalLinkBackendRx();
+
+        public:
+            // Set a list of properties' name needed to construct model
+            void initParameters();
+            // Set a list of properties' name needed to construct model
+            void initProperties();
+
+        protected:
+            // Build the model
+            virtual void constructModel();
+            virtual void updateModel();
+            virtual void propagateTransitionInfo();
+            
+        private:
+            // Calculate ring tuning power
+            double getRingTuningPower();
+            // Calculate the degree of bit re-order muxing (for the bit-reshuffler)
+            unsigned int getBitReorderDegree();
+        
+    }; // class OpticalLinkBackendRx
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_OPTICAL_OPTICALLINKBACKENDRX_H__
+
diff --git a/ext/dsent/model/optical/OpticalLinkBackendTx.cc b/ext/dsent/model/optical/OpticalLinkBackendTx.cc
new file mode 100644 (file)
index 0000000..18d86cf
--- /dev/null
@@ -0,0 +1,355 @@
+#include "model/optical/OpticalLinkBackendTx.h"
+
+#include "util/Constants.h"
+#include "model/PortInfo.h"
+#include "model/TransitionInfo.h"
+#include "model/EventInfo.h"
+#include "model/electrical/MuxTreeSerializer.h"
+#include "model/electrical/BarrelShifter.h"
+#include "model/electrical/Multiplexer.h"
+#include <cmath>
+
+namespace DSENT
+{
+    // TODO: Kind of don't like the way thermal tuning is written here. Maybe will switch
+    // to curve fitting the CICC paper, which uses results from a monte-carlo sim
+
+    OpticalLinkBackendTx::OpticalLinkBackendTx(const String& instance_name_, const TechModel* tech_model_)
+        : ElectricalModel(instance_name_, tech_model_)
+    {
+        initParameters();
+        initProperties();
+    }
+
+    OpticalLinkBackendTx::~OpticalLinkBackendTx()
+    {}
+
+    void OpticalLinkBackendTx::initParameters()
+    {
+        addParameterName("InBits");
+        addParameterName("CoreDataRate");
+        addParameterName("LinkDataRate");
+        addParameterName("RingTuningMethod");
+        addParameterName("BitDuplicate");
+        return;
+    }
+
+    void OpticalLinkBackendTx::initProperties()
+    {
+        return;
+    }
+
+    void OpticalLinkBackendTx::constructModel()
+    {
+        unsigned int in_bits = getParameter("InBits");
+        double core_data_rate = getParameter("CoreDataRate");
+        double link_data_rate = getParameter("LinkDataRate");
+        const String& tuning_method = getParameter("RingTuningMethod");;
+        bool bit_duplicate = getParameter("BitDuplicate");
+        
+        // Calculate serialization ratio
+        unsigned int serialization_ratio = (unsigned int) floor(link_data_rate / core_data_rate);    
+        ASSERT(serialization_ratio == link_data_rate / core_data_rate,
+            "[Error] " + getInstanceName() + " -> Cannot have non-integer serialization ratios " +
+            "(" + (String) (core_data_rate / link_data_rate) + ")!");
+        
+        // Calculate output width
+        ASSERT(floor((double) in_bits / serialization_ratio) == (double) in_bits / serialization_ratio,
+            "[Error] " + getInstanceName() + " -> Input width (" + (String) in_bits + ") " +
+            "must be a multiple of the serialization ratio (" + (String) serialization_ratio + ")!");
+        unsigned int out_bits = in_bits / serialization_ratio;
+
+        getGenProperties()->set("SerializationRatio", serialization_ratio);
+        getGenProperties()->set("OutBits", out_bits);
+        
+        // Create ports
+        createInputPort("In", makeNetIndex(0, in_bits-1));
+        createInputPort("LinkCK");
+        createOutputPort("Out", makeNetIndex(0, out_bits-1));
+                
+        //Create energy, power, and area results
+        createElectricalResults();
+        // Create ring heating power cost
+        addNddPowerResult(new AtomicResult("RingTuning"));
+        // Create process bits event
+        createElectricalEventResult("ProcessBits");
+        getEventInfo("ProcessBits")->setTransitionInfo("LinkCK", TransitionInfo(0.0, (double) serialization_ratio / 2.0, 0.0));
+        // Set conditions during idle state
+        getEventInfo("Idle")->setStaticTransitionInfos();
+        getEventInfo("Idle")->setTransitionInfo("LinkCK", TransitionInfo(0.0, (double) serialization_ratio / 2.0, 0.0));
+        
+        // Create serializer
+        const String& serializer_name = "Serializer";
+        MuxTreeSerializer* serializer = new MuxTreeSerializer(serializer_name, getTechModel());
+        serializer->setParameter("InBits", in_bits);
+        serializer->setParameter("InDataRate", core_data_rate);
+        serializer->setParameter("OutDataRate", link_data_rate);
+        serializer->setParameter("BitDuplicate", bit_duplicate);
+        serializer->construct();
+        
+        addSubInstances(serializer, 1.0);
+        addElectricalSubResults(serializer, 1.0);
+        getEventResult("ProcessBits")->addSubResult(serializer->getEventResult("Serialize"), serializer_name, 1.0);
+        
+        if ((tuning_method == "ThermalWithBitReshuffle") || (tuning_method == "ElectricalAssistWithBitReshuffle"))
+        {            
+            // If a bit reshuffling backend is present, create the reshuffling backend
+            unsigned int reorder_degree = getBitReorderDegree();
+
+            // Create intermediate nets
+            createNet("SerializerIn", makeNetIndex(0, in_bits-1));
+            createNet("ReorderIn", makeNetIndex(0, out_bits+reorder_degree-1));
+            assign("ReorderIn", makeNetIndex(out_bits, out_bits+reorder_degree-1), "ReorderIn", makeNetIndex(0, reorder_degree-1));            
+            
+            // Create barrelshifter
+            unsigned int shift_index_min = (unsigned int)ceil(log2(serialization_ratio));
+            unsigned int shift_index_max = std::max(shift_index_min, (unsigned int) ceil(log2(in_bits)) - 1);
+            
+            // Remember some things
+            getGenProperties()->set("ReorderDegree", reorder_degree);
+            getGenProperties()->set("ShiftIndexMin", shift_index_min);
+            getGenProperties()->set("ShiftIndexMax", shift_index_max);
+            
+            const String& barrel_shift_name = "BarrelShifter";
+            BarrelShifter* barrel_shift = new BarrelShifter(barrel_shift_name, getTechModel());
+            barrel_shift->setParameter("NumberBits", in_bits);
+            barrel_shift->setParameter("ShiftIndexMax", shift_index_max);
+            barrel_shift->setParameter("ShiftIndexMin", shift_index_min);
+            barrel_shift->setParameter("BitDuplicate", bit_duplicate);
+            barrel_shift->construct();
+            
+            // Create bit reorder muxes
+            const String& reorder_mux_name = "ReorderMux";
+            Multiplexer* reorder_mux = new Multiplexer(reorder_mux_name, getTechModel());
+            reorder_mux->setParameter("NumberBits", out_bits);
+            reorder_mux->setParameter("NumberInputs", reorder_degree);
+            reorder_mux->setParameter("BitDuplicate", bit_duplicate);
+            reorder_mux->construct();
+
+            // Connect barrelshifter
+            // TODO: Connect barrelshift shifts!
+            portConnect(barrel_shift, "In", "In");
+            portConnect(barrel_shift, "Out", "SerializerIn");
+            
+            // Connect serializer
+            portConnect(serializer, "In", "SerializerIn");
+            portConnect(serializer, "Out", "ReorderIn", makeNetIndex(0, out_bits-1));
+            portConnect(serializer, "OutCK", "LinkCK");
+
+            // Connect bit reorder muxes
+            // TODO: Connect re-order multiplex select signals!
+            for (unsigned int i = 0; i < reorder_degree; i++)
+                portConnect(reorder_mux, "In" + (String) i, "ReorderIn", makeNetIndex(i, i+out_bits-1));            
+            portConnect(reorder_mux, "Out", "Out");
+            
+            addSubInstances(barrel_shift, 1.0);
+            addSubInstances(reorder_mux, 1.0);
+            addElectricalSubResults(barrel_shift, 1.0);
+            addElectricalSubResults(reorder_mux, 1.0);
+            getEventResult("ProcessBits")->addSubResult(barrel_shift->getEventResult("BarrelShift"), barrel_shift_name, 1.0);
+            getEventResult("ProcessBits")->addSubResult(reorder_mux->getEventResult("Mux"), reorder_mux_name, 1.0);      // This happens multiple times
+        }
+        else if ((tuning_method == "FullThermal") || (tuning_method == "AthermalWithTrim"))
+        {
+            // If no bit reshuffling backend is present, then just connect serializer up            
+            portConnect(serializer, "In", "In");
+            portConnect(serializer, "Out", "Out");
+            portConnect(serializer, "OutCK", "LinkCK");
+        }
+        else
+        {
+            ASSERT(false, "[Error] " + getInstanceName() + " -> Unknown ring tuning method '" + tuning_method + "'!");
+        }
+        
+        return;
+    }
+    
+    void OpticalLinkBackendTx::updateModel()
+    {
+        // Update everyone
+        Model::updateModel();
+        // Update ring tuning power
+        getNddPowerResult("RingTuning")->setValue(getRingTuningPower());        
+        return;
+    }
+    
+    void OpticalLinkBackendTx::propagateTransitionInfo()
+    {
+        // Get parameters
+        const String& tuning_method = getParameter("RingTuningMethod");
+        
+        // Update the serializer        
+        if ((tuning_method == "ThermalWithBitReshuffle") || (tuning_method == "ElectricalAssistWithBitReshuffle"))
+        {
+            // Get generated properties
+            unsigned int reorder_degree = getGenProperties()->get("ReorderDegree").toUInt();
+            unsigned int shift_index_min = getGenProperties()->get("ShiftIndexMin").toUInt();
+            unsigned int shift_index_max = getGenProperties()->get("ShiftIndexMax").toUInt();
+            
+            // Update barrel shifter
+            const String& barrel_shift_name = "BarrelShifter";
+            ElectricalModel* barrel_shift = (ElectricalModel*) getSubInstance(barrel_shift_name);
+            propagatePortTransitionInfo(barrel_shift, "In", "In");
+            // Set shift transitions to be very low (since it is affected by slow temperature time constants)
+            for (unsigned int i = shift_index_min; i <= shift_index_max; ++i)
+                barrel_shift->getInputPort("Shift" + (String) i)->setTransitionInfo(TransitionInfo(0.499, 0.001, 0.499));
+            barrel_shift->use();
+            
+            // Set serializer transition info
+            ElectricalModel* serializer = (ElectricalModel*) getSubInstance("Serializer");
+            propagatePortTransitionInfo(serializer, "In", barrel_shift, "Out");
+            propagatePortTransitionInfo(serializer, "OutCK", "LinkCK");
+            serializer->use();
+            
+            // Reorder mux shift select bits
+            unsigned int reorder_sel_bits = (unsigned int)ceil(log2(reorder_degree));
+
+            // Reorder mux probabilities
+            const String& reorder_mux_name = "ReorderMux";
+            ElectricalModel* reorder_mux = (ElectricalModel*) getSubInstance(reorder_mux_name);
+            for (unsigned int i = 0; i < reorder_degree; ++i)
+                propagatePortTransitionInfo(reorder_mux, "In" + (String) i, serializer, "Out"); 
+            // Set select transitions to be 0, since these are statically configured
+            for (unsigned int i = 0; i < reorder_sel_bits; ++i)
+                reorder_mux->getInputPort("Sel" + (String) i)->setTransitionInfo(TransitionInfo(0.5, 0.0, 0.5));
+            reorder_mux->use();
+            
+            // Set output transition info
+            propagatePortTransitionInfo("Out", reorder_mux, "Out");
+        }
+        else if ((tuning_method == "FullThermal") || (tuning_method == "AthermalWithTrim"))
+        {
+            // Set serializer transition info
+            ElectricalModel* serializer = (ElectricalModel*) getSubInstance("Serializer");
+            propagatePortTransitionInfo(serializer, "In", "In");
+            propagatePortTransitionInfo(serializer, "OutCK", "LinkCK");
+            serializer->use();
+
+            // Set output transition info
+            propagatePortTransitionInfo("Out", serializer, "Out");
+        }
+                
+        return;        
+    }
+
+    double OpticalLinkBackendTx::getRingTuningPower()
+    {
+        // Get properties
+        const String& tuning_method = getParameter("RingTuningMethod");;
+        unsigned int number_rings = getGenProperties()->get("OutBits");        
+
+        // Get tech model parameters
+        double R = getTechModel()->get("Ring->Radius");
+        double n_g = getTechModel()->get("Ring->GroupIndex");
+        double heating_efficiency = getTechModel()->get("Ring->HeatingEfficiency");
+        // This can actually be derived if we know thermo-optic coefficient (delta n / delta T)
+        double tuning_efficiency = getTechModel()->get("Ring->TuningEfficiency");        
+        double sigma_r_local = getTechModel()->get("Ring->LocalVariationSigma");
+        double sigma_r_systematic = getTechModel()->get("Ring->SystematicVariationSigma");
+        double T_max = getTechModel()->get("Ring->TemperatureMax");
+        double T_min = getTechModel()->get("Ring->TemperatureMin");
+        double T = getTechModel()->get("Temperature");
+        
+        // Get constants
+        double c = Constants::c;
+        double pi = Constants::pi;
+        
+        double tuning_power = 0.0;
+        
+        if (tuning_method == "ThermalWithBitReshuffle")
+        {
+            // When an electrical backend is present, rings only have to tune to the nearest channel
+            // This can be approximated as each ring tuning to something exactly 1 channel away
+
+            // Setup calculations
+            double L = 2 * pi * R;                  // Optical length
+            double FSR = c / (n_g * L);             // Free spectral range
+            double freq_sep = FSR / number_rings;   // Channel separation
+            
+            // Calculate tuning power
+            tuning_power = number_rings * freq_sep / (tuning_efficiency * heating_efficiency);
+        }
+        else if (tuning_method == "ElectricalAssistWithBitReshuffle")
+        {
+            // Electrical assistance allows for a fraction of the tuning range to be
+            // covered electrically. This is most pronounced when the tuning range is small,
+            // such is the case when bit reshuffling is applied. The electrically
+            // assisted part of it pretty much comes for free...
+
+            // Get electrically tunable range
+            double max_assist = getTechModel()->get("Ring->MaxElectricallyTunableFreq");
+            
+            // Setup calculations
+            double L = 2 * pi * R;                  // Optical length
+            double FSR = c / (n_g * L);             // Free spectral range
+            double freq_sep = FSR / number_rings;   // Channel separation
+            double heating_range = std::max(0.0, freq_sep - max_assist);  // The distance needed to bridge using heaters            
+            
+            // Calculate tuning power, which is really only the power spent on heating since
+            // distance tuned electrically is pretty much free
+            tuning_power = number_rings * heating_range / (tuning_efficiency * heating_efficiency);            
+        }
+        else if (tuning_method == "FullThermal")
+        {
+            // If there is no bit reshuffling backend, each ring must tune to an
+            // absolute channel frequency. Since we can only heat rings (and not cool),
+            // we can only red-shift (decrease frequency). Thus, a fabrication bias
+            // must be applied such that under any process and temperature corner, the
+            // ring resonance remains above channel resonance
+            // I'll use 3 sigmas of sigma_r_local and sigma_r_systematic, and bias against
+            // the full temperature range
+            double fabrication_bias_freq = 3.0 * sqrt(pow(sigma_r_local, 2) + pow(sigma_r_systematic, 2)) +
+                (T_max - T_min) * tuning_efficiency;
+                
+            // The local/systematic variations are 0 on average. Thus, the tuning distance can be calculated as
+            double tuning_distance = fabrication_bias_freq - (T - T_min) * tuning_efficiency;
+            
+            // Tuning power needed is just the number of rings * tuning distance / (tuning and heating efficiencies)
+            tuning_power = number_rings * tuning_distance / (tuning_efficiency * heating_efficiency);
+        }
+        else if (tuning_method == "AthermalWithTrim")
+        {
+            // Athermal! Each ring's process variations are trimmed! Everything is free!
+            // Basically an ideal scenario
+            tuning_power = 0;
+        }
+        else
+        {
+            ASSERT(false, "[Error] " + getInstanceName() + " -> Unknown ring tuning method '" + tuning_method + "'!");
+        }
+
+        return tuning_power;
+    }
+    
+    unsigned int OpticalLinkBackendTx::getBitReorderDegree()
+    {
+        // Get properties
+        unsigned int number_rings = getGenProperties()->get("OutBits");        
+
+        // Get tech model parameters
+        double R = getTechModel()->get("Ring->Radius");
+        double n_g = getTechModel()->get("Ring->GroupIndex");
+        // This can actually be derived if we know thermo-optic coefficient (delta n / delta T)
+        double sigma_r_local = getTechModel()->get("Ring->LocalVariationSigma");
+        
+        // Get constants
+        double c = Constants::c;
+        double pi = Constants::pi;
+        
+        // Calculates the degree of bit re-order multiplexing needed for bit-reshuffling backend
+        // Bit reshuffling tuning is largely unaffected by sigma_r_systematic. However, sigma_r_local
+        // Can potentially throw each ring to a channel several channels away. This just calculates
+        // the degree of bit reorder muxing needed to realign bits in the correct order
+
+        // Setup calculations
+        double L = 2 * pi * R;                  // Optical length
+        double FSR = c / (n_g * L);             // Free spectral range
+        double freq_sep = FSR / number_rings;   // Channel separation        
+        // Using 4 sigmas as the worst re-ordering case (must double to get both sides)
+        unsigned int worst_case_channels = (unsigned int)ceil(2.0 * 4.0 * sigma_r_local / freq_sep);
+        
+        return worst_case_channels;
+    }
+    
+} // namespace DSENT
+
diff --git a/ext/dsent/model/optical/OpticalLinkBackendTx.h b/ext/dsent/model/optical/OpticalLinkBackendTx.h
new file mode 100644 (file)
index 0000000..a3e5964
--- /dev/null
@@ -0,0 +1,39 @@
+#ifndef __DSENT_MODEL_OPTICAL_OPTICALLINKBACKENDTX_H__
+#define __DSENT_MODEL_OPTICAL_OPTICALLINKBACKENDTX_H__
+
+#include "util/CommonType.h"
+#include "model/ElectricalModel.h"
+
+namespace DSENT
+{
+    class OpticalLinkBackendTx : public ElectricalModel
+    {
+        // An optical link backend tx contains everything needed for thermal
+        // tuning of rings, bit-reshuffling (if necessary), and serialization (if necessary)
+        public:
+            OpticalLinkBackendTx(const String& instance_name_, const TechModel* tech_model_);
+            virtual ~OpticalLinkBackendTx();
+
+        public:
+            // Set a list of properties' name needed to construct model
+            void initParameters();
+            // Set a list of properties' name needed to construct model
+            void initProperties();
+
+        protected:
+            // Build the model
+            virtual void constructModel();
+            virtual void updateModel();
+            virtual void propagateTransitionInfo();
+            
+        private:
+            // Calculate ring tuning power
+            double getRingTuningPower();
+            // Calculate the degree of bit re-order muxing (for the bit-reshuffler)
+            unsigned int getBitReorderDegree();
+        
+    }; // class OpticalLinkBackendTx
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_OPTICAL_OPTICALLINKBACKENDTX_H__
+
diff --git a/ext/dsent/model/optical/OpticalTestModel.cc b/ext/dsent/model/optical/OpticalTestModel.cc
new file mode 100644 (file)
index 0000000..c821c48
--- /dev/null
@@ -0,0 +1,121 @@
+#include "model/optical/OpticalTestModel.h"
+#include "model/optical_graph/OpticalGraph.h"
+#include "model/optical_graph/OpticalWaveguide.h"
+#include "model/optical/RingModulator.h"
+#include "model/optical/RingFilter.h"
+#include "model/optical/RingDetector.h"
+#include "model/optical/LaserSource.h"
+
+namespace DSENT
+{
+    OpticalTestModel::OpticalTestModel(const String& instance_name_, const TechModel* tech_model_)
+        : OpticalModel(instance_name_, tech_model_)
+    {
+        initParameters();
+        initProperties();
+    }
+
+    OpticalTestModel::~OpticalTestModel()
+    {}
+
+    void OpticalTestModel::initParameters()
+    {
+        return;
+    }
+
+    void OpticalTestModel::initProperties()
+    {
+        return;
+    }
+
+    void OpticalTestModel::constructModel()
+    {
+        unsigned int wavelengths = 64;
+        unsigned int number_readers = 1;
+        
+        createWaveguide("LaserToMod", makeWavelengthGroup(0, wavelengths-1));
+                    
+        // Create laser
+        LaserSource* laser = new LaserSource("Laser", getTechModel());
+        laser->setParameter("OutStart", 0);
+        laser->setParameter("OutEnd", wavelengths-1);
+        laser->construct();
+        
+        // Create modulator
+        RingModulator* modulator = new RingModulator("Modulator", getTechModel());
+        modulator->setParameter("InStart", 0);
+        modulator->setParameter("InEnd", wavelengths-1);
+        modulator->setParameter("ModStart", 0);
+        modulator->setParameter("ModEnd", wavelengths-1);
+        modulator->construct();
+        
+        for (unsigned int i = 0; i <= number_readers; ++i)
+        {
+            String n = (String) i;            
+            createWaveguide("WaveguideDet-" + n, makeWavelengthGroup(0, wavelengths-1));        
+        }
+
+        // Create a SWMR Configuration
+        for (unsigned int i = 0; i < number_readers; ++i)
+        {
+            String n = (String) i;
+            
+            // Create resonant ring detector
+            RingDetector* detector = new RingDetector("Detector-" + n, getTechModel());
+            detector->setParameter("InStart", 0);
+            detector->setParameter("InEnd", wavelengths-1);
+            detector->setParameter("DetStart", 0);
+            detector->setParameter("DetEnd", wavelengths-1);
+            detector->setParameter("DropAll", "FALSE");
+            detector->setParameter("SenseAmp", "TRUE");
+            detector->construct();
+            
+            opticalPortConnect(detector, "In", "WaveguideDet-" + n);
+            opticalPortConnect(detector, "Out", "WaveguideDet-" + (String) (i + 1));
+            
+            addSubInstances(detector, 1.0);
+        }
+
+        opticalPortConnect(laser, "Out", "LaserToMod");
+        opticalPortConnect(modulator, "In", "LaserToMod");
+        opticalPortConnect(modulator, "Out", "WaveguideDet-0");
+        
+        addSubInstances(laser, 1.0);
+        addSubInstances(modulator, 1.0);
+    }
+    
+    void OpticalTestModel::updateModel()
+    {
+        double data_rate = 8e9;
+        double extinction_ratio = 5;
+        double insertion_loss = 3;
+
+        Model* laser = getSubInstance("Laser");
+        laser->update();
+        
+        getWaveguide("LaserToMod")->setLoss(10);
+        
+        Model* modulator = getSubInstance("Modulator");
+        modulator->setProperty("ExtinctionRatio", extinction_ratio);
+        modulator->setProperty("InsertionLoss", insertion_loss);
+        modulator->setProperty("DataRate", data_rate);
+        modulator->setProperty("P(In)", 0.5);
+        modulator->setProperty("Act(In)", 1.0);
+        modulator->update();        
+        
+        unsigned int number_readers = 1;
+        for (unsigned int i = 0; i < number_readers; ++i)
+        {
+            Model* detector = getSubInstance("Detector-" + (String) i);
+            detector->setProperty("ExtinctionRatio", extinction_ratio);
+            detector->setProperty("DataRate", data_rate);
+            detector->setProperty("P(In)", 0.5);
+            detector->setProperty("Act(In)", 1.0);
+            detector->update();
+        }
+        
+
+    }
+    
+} // namespace DSENT
+
diff --git a/ext/dsent/model/optical/OpticalTestModel.h b/ext/dsent/model/optical/OpticalTestModel.h
new file mode 100644 (file)
index 0000000..06a80e9
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef __DSENT_MODEL_OPTICAL_OPTICALTESTMODEL_H__
+#define __DSENT_MODEL_OPTICAL_OPTICALTESTMODEL_H__
+
+#include "util/CommonType.h"
+#include "model/OpticalModel.h"
+
+namespace DSENT
+{
+    class OpticalTestModel : public OpticalModel
+    {
+        public:
+            OpticalTestModel(const String& instance_name_, const TechModel* tech_model_);
+            virtual ~OpticalTestModel();
+
+        public:
+            // Set a list of properties' name needed to construct model
+            void initParameters();
+            // Set a list of properties' name needed to construct model
+            void initProperties();
+
+        protected:
+            // Build the model
+            virtual void constructModel();
+            virtual void updateModel();
+
+    }; // class OpticalTestModel
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_OPTICAL_RINGLASERSOURCE_H__
+
diff --git a/ext/dsent/model/optical/RingDetector.cc b/ext/dsent/model/optical/RingDetector.cc
new file mode 100644 (file)
index 0000000..4baf2f6
--- /dev/null
@@ -0,0 +1,338 @@
+#include "model/optical/RingDetector.h"
+
+#include <cmath>
+
+#include "util/Constants.h"
+#include "model/PortInfo.h"
+#include "model/TransitionInfo.h"
+#include "model/EventInfo.h"
+#include "model/std_cells/StdCell.h"
+#include "model/std_cells/StdCellLib.h"
+#include "model/optical_graph/OpticalWaveguide.h"
+#include "model/optical_graph/OpticalDetector.h"
+#include "model/optical_graph/OpticalFilter.h"
+#include "model/timing_graph/ElectricalDriver.h"
+#include "model/timing_graph/ElectricalNet.h"
+
+namespace DSENT
+{
+    // TODOs for this model
+    // Add the other receiver topologies from [Georgas, CICC 2011]
+    // Split integ_time_ratio = SA integ time ratio
+    // Right now perfect clock gating is assumed...may not be what we want
+        
+    // Constants
+    const String RingDetector::INTEGRATINGSENSEAMP = "INTSA";
+
+    RingDetector::RingDetector(const String& instance_name_, const TechModel* tech_model_)
+        : OpticalModel(instance_name_, tech_model_), OpticalReceiver()
+    {
+        initParameters();
+        initProperties();
+    }
+
+    RingDetector::~RingDetector()
+    {}
+    
+    void RingDetector::initParameters()
+    {
+        addParameterName("DataRate");
+        addParameterName("InStart");
+        addParameterName("InEnd");
+        addParameterName("DetStart");
+        addParameterName("DetEnd");
+        addParameterName("DropAll");
+        addParameterName("Topology");
+        return;
+    }
+
+    void RingDetector::initProperties()
+    {
+        return;
+    }
+    
+    void RingDetector::constructModel()
+    {
+        // Get parameters
+        WavelengthGroup in_wavelengths = makeWavelengthGroup(getParameter("InStart"), getParameter("InEnd"));
+        WavelengthGroup det_wavelengths = makeWavelengthGroup(getParameter("DetStart"), getParameter("DetEnd"));
+        int number_wavelengths = det_wavelengths.second - det_wavelengths.first + 1;
+        bool drop_all = getParameter("DropAll");
+        const String& topology = getParameter("Topology");
+    
+        // Set some generated properties
+        getGenProperties()->set("NumberWavelengths", number_wavelengths);
+    
+        // Create device area result
+        addAreaResult(new AtomicResult("Photonic"));
+        // Create electrical results
+        createElectricalAtomicResults();
+        if (topology == INTEGRATINGSENSEAMP) addEventResult(new AtomicResult("Receive"));
+        else ASSERT(false, "[Error] " + getInstanceName() + " -> Unknown receiver topology (" + topology + ")!");
+    
+        // Create optical ports
+        createOpticalInputPort(         "In",   in_wavelengths);
+        createOpticalOutputPort(        "Out",  in_wavelengths);
+        // Create the filter and modulator
+        createFilter(                   "RingFilter",   in_wavelengths, drop_all, det_wavelengths);
+        createDetector(                 "RingDetector", det_wavelengths, this);
+        OpticalFilter* ring_filter = getFilter("RingFilter");
+        OpticalDetector* ring_detector = getDetector("RingDetector");        
+        // Connect the filter and modulator
+        getWaveguide("In")->addDownstreamNode(ring_filter);
+        ring_filter->addDownstreamNode(getWaveguide("Out"));
+        ring_filter->setDropPort(ring_detector);
+        
+        // Create electrical ports
+        createOutputPort("Out", makeNetIndex(0, number_wavelengths-1));
+        // Create net
+        createNet("OutVFO");
+        // Create output driver
+        createDriver("OutDriver", false);
+        // Connect driver
+        getDriver("OutDriver")->addDownstreamNode(getNet("OutVFO"));        
+        // Connect output
+        assignVirtualFanout("Out", "OutVFO");
+
+        // Precompute some technology values
+        precomputeTech();
+        
+        return;
+    }
+    
+    void RingDetector::updateModel()
+    {
+        // Get some generated properties
+        unsigned int number_wavelengths = getGenProperties()->get("NumberWavelengths");
+
+        // Get tech model numbers
+        double ring_area = getTechModel()->get("Ring->Area");
+        double thru_loss = getTechModel()->get("Ring->ThroughLoss");
+        double drop_loss = getTechModel()->get("Ring->DropLoss");
+        double pd_loss = getTechModel()->get("Photodetector->Loss");
+        double pd_responsivity = getTechModel()->get("Photodetector->Responsivity");
+        
+        // Design the receiver
+        designReceiver();
+        
+        // Update losses
+        // Connect the filter and modulator
+        OpticalFilter* ring_filter = getFilter("RingFilter");
+        OpticalDetector* ring_detector = getDetector("RingDetector");        
+        ring_filter->setLoss(thru_loss * number_wavelengths);
+        ring_filter->setDropLoss(drop_loss + thru_loss * number_wavelengths);
+        ring_detector->setLoss(pd_loss);
+        ring_detector->setResponsivity(pd_responsivity);
+        // Update device area
+        getAreaResult("Photonic")->setValue(ring_area * (number_wavelengths));
+
+        return;
+    }
+    
+    void RingDetector::useModel()
+    {
+        // Get parameters
+        const String& topology = getParameter("Topology");
+
+        // Get some generated properties
+        unsigned int number_wavelengths = getGenProperties()->get("NumberWavelengths");
+
+        // Get optical input transition info
+        const TransitionInfo& in_trans = getOpticalInputPort("In")->getTransitionInfo();
+        
+        // Get tech models
+        double vdd = getTechModel()->get("Vdd");
+        // Get caps
+        double unit_gate_cap = getTechModel()->get("Gate->MinWidth").toDouble() * getTechModel()->get("Gate->CapPerWidth").toDouble();
+        double unit_drain_cap = getTechModel()->get("Gate->MinWidth").toDouble() * getTechModel()->get("Drain->CapPerWidth").toDouble();
+        double inv_x1_gate_cap = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Cap->A");
+        double inv_x1_drain_cap = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Cap->Y");
+        
+        // Construct a simple sense-amp model
+        if(topology == INTEGRATINGSENSEAMP)
+        {
+            // Use ratios from the receiver published in [Georgas, ESSCIRC 2011]
+            // Note:
+            // The numbers in the paper (43fJ/b, 50 fJ/b in the cited work) is done with the clock buffer (there are 4 receivers),
+            // capacitive DAC, and extra output flops used in the physical layout, as the compared receiver is extremely conservative
+            // We simplified this model to not have the capacitive DAC, the clock buffer (since this is an individual receiver), or
+            // the extra output flops (since receiver structure is already a posedge flop functionally).
+            // Look for an upcoming paper [Georgas, JSSC 2012] (when it is published) for the power breakdown pie-chart for the receiver.
+            // This model only models the latch (sampler) and the dynamic to static (RS latch) part of the design, which is all you really
+            // need in the receiver.
+            
+            // Gate caps
+            double c_gate_sampler = unit_gate_cap * (4 * 2.0 + 2 * 1.0 + 2 * 3.0 + 2 * 5.0) + unit_gate_cap * (2 * 6.0 + 2 * 1.0) + inv_x1_gate_cap;
+            double c_gate_rslatch = unit_gate_cap * (4 * 1.0) + inv_x1_gate_cap;
+            // Drain caps
+            double c_drain_sampler = unit_drain_cap * (2 * 2.0 + 2 * 1.0 + 3 * 5.0 + 1 * 3.0) + inv_x1_drain_cap;
+            double c_drain_rslatch = unit_drain_cap * (2 * 6.0) + inv_x1_drain_cap;
+            // Sum up cap switched for the sampler
+            double c_sampler = c_gate_sampler + c_drain_sampler;
+            double c_rslatch = c_gate_rslatch + c_drain_rslatch;
+            // Average cap switched 
+            // Sampler is differential, one side will always switch (R or S in the latch) regardless of probability
+            double avg_cap = c_sampler + c_rslatch * in_trans.getProbability0() * in_trans.getProbability1();
+
+            // Get parameters corresponding to a unit-inverter
+            double unit_leak_0 = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Leakage->!A");
+            double unit_leak_1 = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Leakage->A");        
+            
+            // Approximate leakage (curve fit with design)
+            double total_leakage = 0.5 * (unit_leak_0 + unit_leak_1) * 7.43;            
+
+            // Create results
+            getEventResult("Receive")->setValue(vdd * vdd * avg_cap * number_wavelengths);
+            getNddPowerResult("Leakage")->setValue(total_leakage * number_wavelengths);
+
+        }
+        else ASSERT(false, "[Error] " + getInstanceName() + " -> Unknown receiver topology (" + topology + ")!");        
+        
+        return;
+    }
+    
+    void RingDetector::propagateTransitionInfo()
+    {
+        // Propagate probabilities from optical input to electrical output port
+        getOutputPort("Out")->setTransitionInfo(getOpticalInputPort("In")->getTransitionInfo());        
+            
+        return;        
+    }
+    
+    void RingDetector::precomputeTech()
+    {
+        // Get parameters
+        const double data_rate = getParameter("DataRate");
+        const String& topology = getParameter("Topology");
+
+        // Get tech model numbers
+        double pd_cap = getTechModel()->get("Photodetector->Cap");
+        double parasitic_cap = getTechModel()->get("Photodetector->ParasiticCap");
+        double apd = getTechModel()->get("Photodetector->AvalancheGain");
+        double vdd = getTechModel()->get("Vdd");
+
+        // Constants shortcuts
+        double pi = Constants::pi;
+        double k = Constants::k;
+        double q = Constants::q;   
+        double T = getTechModel()->get("Temperature");
+                
+        if(topology == INTEGRATINGSENSEAMP)
+        {
+            // Get more tech parameters
+            double integ_time_ratio = getTechModel()->get("Receiver->Int->IntegrationTimeRatio");
+            double BER = getTechModel()->get("SenseAmp->BER");
+            double CMRR = getTechModel()->get("SenseAmp->CMRR");
+            double offset_comp_bits = getTechModel()->get("SenseAmp->OffsetCompensationBits");
+            double offset = getTechModel()->get("SenseAmp->OffsetRatio").toDouble() * vdd;
+            double supply_noise_rand = getTechModel()->get("SenseAmp->SupplyNoiseRandRatio").toDouble() * vdd;
+            double supply_noise_det = getTechModel()->get("SenseAmp->SupplyNoiseDetRatio").toDouble() * vdd;
+            double noise_margin = getTechModel()->get("SenseAmp->NoiseMargin");
+            double jitter_ratio = getTechModel()->get("SenseAmp->JitterRatio");
+            
+            // Approximate tao using FO4
+            double unit_drain_cap = getTechModel()->get("Gate->MinWidth").toDouble() * getTechModel()->get("Drain->CapPerWidth").toDouble();
+            double c_g = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Cap->A");
+            double c_d = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Cap->Y");
+            double r_o = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->DriveRes->Y");
+            // Calculate sense amp tau from sense amp output loading
+            double tau = r_o * (c_g + c_d);
+            // Set output inverter drive strength
+            getDriver("OutDriver")->setOutputRes(r_o);
+
+            // Calculate sense amp input cap based on schematic
+            double sense_amp_cap_in = unit_drain_cap * (2.0 + 3.0 + 5.0 + 1.0);
+
+            // Residual offset
+            double v_residual = 3 * offset / pow(2, offset_comp_bits);
+            // Noise
+            double v_noise = supply_noise_rand * supply_noise_rand / (CMRR * CMRR);
+            // Sense amp voltage build-up minimum
+            double v_sense = vdd * exp(-(1 - integ_time_ratio) / (data_rate * tau)) + noise_margin + v_residual + supply_noise_det / CMRR;
+            // Sigmas corresponding to BER
+            double sigma = calcInvNormCdf(BER);
+            
+            //K_int is the time the bit is valid for evaluation
+
+            // Total input cap load
+            double input_node_cap = sense_amp_cap_in + pd_cap + parasitic_cap;
+            double z_int = integ_time_ratio / (data_rate * input_node_cap); //should use K_int
+            
+            // Store precalculated values
+            m_quad_a_ = 1 - (sigma * sigma * jitter_ratio * jitter_ratio);
+            m_quad_b1_ = - 2 * pi / 2 * sigma * sigma * q * 0.7 * data_rate;
+            m_quad_b2_ = -2 * v_sense / (z_int * apd);
+            m_quad_c_ = 1 / (z_int * z_int) * (v_sense * v_sense - sigma * sigma * (k * T / input_node_cap + v_noise));
+        }
+        else ASSERT(false, "[Error] " + getInstanceName() + " -> Unknown receiver topology (" + topology + ")!");
+
+        return;
+    }
+
+    void RingDetector::designReceiver()
+    {
+        // Get some generated properties
+        unsigned int number_wavelengths = getGenProperties()->get("NumberWavelengths");
+
+        // Get relevant properties/parameters
+        const String& topology = getParameter("Topology");
+                
+        // Construct a simple sense-amp model
+        if(topology == INTEGRATINGSENSEAMP)
+        {
+            // No really good way to estimate the area...can assume each receiver is the size of 40 inverters, which is
+            // about the right size for just the sense amp in the layout
+            double unit_area_active = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Area->Active");
+            double unit_area_metal1 = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Area->Metal1Wire");          
+            getAreaResult("Active")->setValue(unit_area_active * 40 * number_wavelengths);
+            getAreaResult("Metal1Wire")->setValue(unit_area_metal1 * 40 * number_wavelengths);
+        }
+        else ASSERT(false, "[Error] " + getInstanceName() + " -> Unknown receiver topology (" + topology + ")!");
+        
+        return;
+    }
+    
+    double RingDetector::getSensitivity(double ER_dB_) const
+    {
+        // Get parameters
+        const String& topology = getParameter("Topology");
+        // Turn extinction ratio into a ratio from dB scale
+        double ER = pow(10, ER_dB_ / 10);
+                
+        // Initialize sensitivity
+        double sensitivity = 1e99;
+        // Construct a simple sense-amp model
+        if(topology == INTEGRATINGSENSEAMP)
+        {
+            // Scale photodetector shot noise using ER, add rest of noise source
+            double b = m_quad_b1_ * (1 + ER) / (2 * (ER - 1)) + m_quad_b2_;            
+        
+            // Find sensitivity (-b + sqrt(b^2-4ac)) / 2a
+            sensitivity = ((-b + sqrt(b * b - 4 * m_quad_a_ * m_quad_c_)) / (2 * m_quad_a_));
+        }
+        else ASSERT(false, "[Error] " + getInstanceName() + " -> Unknown receiver topology (" + topology + ")!");        
+        
+        return sensitivity;
+    }
+    
+    double RingDetector::calcInvNormCdf(double num_)
+    {
+        // 53 bit precision for double FP
+        unsigned int num_iterations = 20;
+        // Upperbound the step
+        double step = 20;
+        double out = step;                
+        // Iteratively guess and check calculation
+        for (unsigned int i = 0; i < num_iterations; ++i)
+        {
+            double current = 0.5 * erfc(out / sqrt(2));
+            if (current > num_) out += step;
+            else out -= step;            
+            step = step * 0.5;
+        }
+        
+        return out;
+    }
+    
+} // namespace DSENT
+
diff --git a/ext/dsent/model/optical/RingDetector.h b/ext/dsent/model/optical/RingDetector.h
new file mode 100644 (file)
index 0000000..e18b2fe
--- /dev/null
@@ -0,0 +1,54 @@
+#ifndef __DSENT_MODEL_OPTICAL_RINGDETECTOR_H__
+#define __DSENT_MODEL_OPTICAL_RINGDETECTOR_H__
+
+#include "util/CommonType.h"
+#include "model/OpticalModel.h"
+#include "model/optical_graph/OpticalReceiver.h"
+
+namespace DSENT
+{
+    class RingDetector : public OpticalModel, public OpticalReceiver
+    {
+        public:
+            // Receiver topolgy strings
+            static const String INTEGRATINGSENSEAMP;
+    
+        public:
+            RingDetector(const String& instance_name_, const TechModel* tech_model_);
+            virtual ~RingDetector();
+
+        public:
+            // Set a list of properties' name needed to construct model
+            void initParameters();
+            // Set a list of properties' name needed to construct model
+            void initProperties();
+            // Returns the sensitivity of the receiver given an extinction ratio
+            double getSensitivity(double ER_dB_) const;
+            
+        private:
+            // Precompute values based on tech parameters
+            void precomputeTech();
+            // Design the receiver helper function
+            void designReceiver();
+            // Calculates inverse normal cdf
+            double calcInvNormCdf(double num_);
+
+        protected:
+            // Build the model
+            virtual void constructModel();
+            virtual void updateModel();
+            virtual void useModel();
+            virtual void propagateTransitionInfo();
+            
+        private:
+            // Precomputed numbers
+            double m_quad_a_;
+            double m_quad_b1_;
+            double m_quad_b2_;
+            double m_quad_c_;
+
+    }; // class RingDetector
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_OPTICAL_RINGDETECTOR_H__
+
diff --git a/ext/dsent/model/optical/RingFilter.cc b/ext/dsent/model/optical/RingFilter.cc
new file mode 100644 (file)
index 0000000..5f0bd5b
--- /dev/null
@@ -0,0 +1,77 @@
+#include "model/optical/RingFilter.h"
+
+#include "model/optical_graph/OpticalWaveguide.h"
+#include "model/optical_graph/OpticalFilter.h"
+
+namespace DSENT
+{
+    RingFilter::RingFilter(const String& instance_name_, const TechModel* tech_model_)
+        : OpticalModel(instance_name_, tech_model_)
+    {
+        initParameters();
+        initProperties();
+    }
+
+    RingFilter::~RingFilter()
+    {}
+
+    void RingFilter::initParameters()
+    {
+        addParameterName("InStart");
+        addParameterName("InEnd");
+        addParameterName("DropStart");
+        addParameterName("DropEnd");
+        addParameterName("DropAll", "TRUE");
+        return;
+    }
+
+    void RingFilter::initProperties()
+    {
+        return;
+    }
+
+    void RingFilter::constructModel()
+    {
+        //TODO: Add tuning energy/ndd-power costs?
+    
+        // Create Area result
+        Result* area_result = new AtomicResult("Photonic");
+        addAreaResult(area_result);
+    
+        // Get parameters
+        WavelengthGroup in_wavelengths = makeWavelengthGroup(getParameter("InStart"), getParameter("InEnd"));
+        WavelengthGroup drop_wavelengths = makeWavelengthGroup(getParameter("DropStart"), getParameter("DropEnd"));
+        bool drop_all = getParameter("DropAll");
+        
+        // Create optical ports
+        createOpticalInputPort(     "In", in_wavelengths);
+        createOpticalOutputPort(    "Drop", drop_wavelengths);
+        createOpticalOutputPort(    "Out", in_wavelengths);
+        // Create the filter
+        createFilter(       "RingFilter",   in_wavelengths, drop_all, drop_wavelengths);
+        OpticalFilter* ring_filter = getFilter("RingFilter");
+        // Connect the filter
+        getWaveguide("In")->addDownstreamNode(ring_filter);
+        ring_filter->addDownstreamNode(getWaveguide("Out"));
+        ring_filter->setDropPort(getWaveguide("Drop"));                
+    }
+    
+    void RingFilter::updateModel()
+    {
+        //TODO: Get numbers from tech model;
+        double ring_area = 200e-12;
+        double thru_loss = 1e-4;
+        double drop_loss = 1.0;
+        // Get parameters
+        WavelengthGroup drop_wavelengths = makeWavelengthGroup(getParameter("DropStart"), getParameter("DropEnd"));
+        int number_wavelengths = drop_wavelengths.second - drop_wavelengths.first + 1;
+        // Update losses
+        OpticalFilter* ring_filter = getFilter("RingFilter");
+        ring_filter->setLoss(thru_loss * number_wavelengths);
+        ring_filter->setDropLoss(drop_loss + thru_loss * number_wavelengths);
+        // Update area
+        getAreaResult("Photonic")->setValue(ring_area * (number_wavelengths));        
+    }
+    
+} // namespace DSENT
+
diff --git a/ext/dsent/model/optical/RingFilter.h b/ext/dsent/model/optical/RingFilter.h
new file mode 100644 (file)
index 0000000..87fcb8c
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef __DSENT_MODEL_OPTICAL_RINGFILTER_H__
+#define __DSENT_MODEL_OPTICAL_RINGFILTER_H__
+
+#include "util/CommonType.h"
+#include "model/OpticalModel.h"
+
+namespace DSENT
+{
+    class RingFilter : public OpticalModel
+    {
+        public:
+            RingFilter(const String& instance_name_, const TechModel* tech_model_);
+            virtual ~RingFilter();
+
+        public:
+            // Set a list of properties' name needed to construct model
+            void initParameters();
+            // Set a list of properties' name needed to construct model
+            void initProperties();
+
+        protected:
+            // Build the model
+            virtual void constructModel();
+            virtual void updateModel();
+
+    }; // class RingFilter
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_OPTICAL_RINGFILTER_H__
+
diff --git a/ext/dsent/model/optical/RingModulator.cc b/ext/dsent/model/optical/RingModulator.cc
new file mode 100644 (file)
index 0000000..8fe320f
--- /dev/null
@@ -0,0 +1,403 @@
+#include "model/optical/RingModulator.h"
+
+#include <cmath>
+
+#include "util/Constants.h"
+#include "model/PortInfo.h"
+#include "model/TransitionInfo.h"
+#include "model/EventInfo.h"
+#include "model/std_cells/StdCell.h"
+#include "model/std_cells/StdCellLib.h"
+#include "model/optical_graph/OpticalWaveguide.h"
+#include "model/optical_graph/OpticalModulator.h"
+#include "model/optical_graph/OpticalFilter.h"
+#include "model/optical_graph/OpticalTransmitter.h"
+#include "model/timing_graph/ElectricalNet.h"
+#include "model/timing_graph/ElectricalLoad.h"
+#include "model/timing_graph/ElectricalTimingTree.h"
+
+namespace DSENT
+{
+    using std::max;
+    using std::min;
+    
+    // TODO: Don't like the way this is written right now. Probably fix in a future version
+
+    RingModulator::RingModulator(const String& instance_name_, const TechModel* tech_model_)
+        : OpticalModel(instance_name_, tech_model_)
+    {
+        initParameters();
+        initProperties();
+    }
+
+    RingModulator::~RingModulator()
+    {}
+
+    void RingModulator::initParameters()
+    {
+        addParameterName("DataRate");
+        addParameterName("InStart");
+        addParameterName("InEnd");
+        addParameterName("ModStart");
+        addParameterName("ModEnd");
+        addParameterName("OptimizeLoss", "TRUE");
+        return;
+    }
+
+    void RingModulator::initProperties()
+    {
+        addPropertyName("ExtinctionRatio", 6);  //default properties
+        addPropertyName("InsertionLoss", 2);    //default properties
+        return;
+    }
+
+    void RingModulator::constructModel()
+    {
+        // Create electrical results
+        createElectricalAtomicResults();
+        // Create Area result
+        addAreaResult(new AtomicResult("Photonic"));
+        // Create Modulate result
+        createElectricalEventAtomicResult("Modulate");
+
+        // Get parameters
+        WavelengthGroup in_wavelengths = makeWavelengthGroup(getParameter("InStart"), getParameter("InEnd"));
+        WavelengthGroup mod_wavelengths = makeWavelengthGroup(getParameter("ModStart"), getParameter("ModEnd"));
+        int number_wavelengths = mod_wavelengths.second - mod_wavelengths.first + 1;
+        bool optimize_loss = getParameter("OptimizeLoss");
+
+        getGenProperties()->set("NumberWavelengths", number_wavelengths);
+        
+        // Create optical ports
+        createOpticalInputPort(         "In",   in_wavelengths);
+        createOpticalOutputPort(        "Out",  in_wavelengths);
+        // Create the filter and modulator
+        createFilter(                   "RingFilter",       in_wavelengths, true, mod_wavelengths);
+        createModulator(                "RingModulator",    mod_wavelengths, optimize_loss, this);
+        createWaveguide(                "RingTemp",         mod_wavelengths);
+        OpticalFilter* ring_filter = getFilter("RingFilter");
+        OpticalModulator* ring_modulator = getModulator("RingModulator");        
+        // Connect the filter and modulator
+        getWaveguide("In")->addDownstreamNode(ring_filter);
+        ring_filter->addDownstreamNode(getWaveguide("Out"));
+        ring_filter->setDropPort(ring_modulator);
+        ring_modulator->addDownstreamNode(getWaveguide("Out"));
+        
+        // Create electrical ports
+        createInputPort(                "In", makeNetIndex(0, number_wavelengths-1));
+        // Create driver
+        createNet("PredriverIn");
+        // VFI from In to PredriverIn
+        assignVirtualFanin("PredriverIn", "In");        
+        // Create input load (due to predrivers)
+        createLoad("PredriverCap");
+        getNet("PredriverIn")->addDownstreamNode(getLoad("PredriverCap"));
+        
+        // Precompute some values
+        precomputeTech();
+        
+        return;
+    }
+    
+    void RingModulator::updateModel()
+    {
+        // Get properties
+        double ER_dB = getProperty("ExtinctionRatio").toDouble();
+        double IL_dB = getProperty("InsertionLoss").toDouble();
+            
+        // Get Gen properties
+        int number_wavelengths = getGenProperties()->get("NumberWavelengths");
+
+        // Get tech model parameters
+        double ring_area = getTechModel()->get("Ring->Area").toDouble();
+        double thru_loss = getTechModel()->get("Ring->ThroughLoss").toDouble();
+        
+        // Design the modulator and the modulator driver
+        bool success = designModulator(IL_dB, ER_dB);        
+        getGenProperties()->set("Success", success);     
+
+        // If not successful, make the modulate energy extremely large
+        if (!success) getEventResult("Modulate")->setValue(1e99);
+        
+        // Update losses
+        // Connect the filter and modulator
+        OpticalFilter* ring_filter = getFilter("RingFilter");
+        ring_filter->setLoss(thru_loss * number_wavelengths);
+        ring_filter->setDropLoss(thru_loss * number_wavelengths);     // Assume worst-case through loss for a dropped wavelength
+        // Update area
+        getAreaResult("Photonic")->setValue(ring_area * (number_wavelengths));        
+    }
+    
+    void RingModulator::useModel()
+    {
+        // Propagate the transition info and get the 0->1 transtion count
+        propagateTransitionInfo();
+        double P_In = getInputPort("In")->getTransitionInfo().getProbability1();
+        double P_num_trans_01 = getInputPort("In")->getTransitionInfo().getNumberTransitions01();
+        
+        // Get Gen properties
+        int number_wavelengths = getGenProperties()->get("NumberWavelengths");
+        
+        // If I can't build it...then it is infinitely expensive!
+        bool success = getGenProperties()->get("Success");
+        double driver_size = 1e99;
+        double total_predriver_size = 1e99;
+        if (success)
+        {
+            driver_size = getGenProperties()->get("DriverSize");
+            total_predriver_size = getGenProperties()->get("TotalPredriverSize");
+        }
+
+        // Get parameters corresponding to a unit-inverter
+        double unit_leak_0 = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Leakage->!A");
+        double unit_leak_1 = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Leakage->A");        
+        
+        // Approximate leakage
+        double total_leakage = number_wavelengths * 0.5 * ((driver_size + total_predriver_size) * P_In * unit_leak_1 + 
+                                                            (driver_size + total_predriver_size) * (1 - P_In) * unit_leak_0);
+        
+        getNddPowerResult("Leakage")->setValue(total_leakage);
+        getEventResult("Modulate")->setValue(calcModulatorEnergy() * P_num_trans_01);
+        
+        return;
+    }
+    
+    void RingModulator::propagateTransitionInfo()
+    {
+        // Very simple...whatever comes in electrically is encoded optically
+        getOpticalOutputPort("Out")->setTransitionInfo(getInputPort("In")->getTransitionInfo());
+
+        return;
+    }
+        
+    void RingModulator::precomputeTech()
+    {
+        // Get parameters
+        double data_rate = getParameter("DataRate");
+                
+        // Constants shortcuts
+        double pi = Constants::pi;
+        double c = Constants::c;
+        double k = Constants::k;
+        double e0 = Constants::e0;
+        double es = Constants::es;
+        double q = Constants::q;   
+        double T = getTechModel()->get("Temperature");
+        
+        // Get modulator parameters
+        double lambda = getTechModel()->get("Ring->Lambda").toDouble();
+        double n_f = getTechModel()->get("Modulator->Ring->FCPDEffect").toDouble();
+        double NA = getTechModel()->get("Modulator->Ring->NA").toDouble();
+        double ND = getTechModel()->get("Modulator->Ring->ND").toDouble();
+        double ni = getTechModel()->get("Modulator->Ring->ni").toDouble();
+        double L_j = getTechModel()->get("Modulator->Ring->JunctionRatio").toDouble();
+        double H = getTechModel()->get("Modulator->Ring->Height").toDouble();
+        double W = getTechModel()->get("Modulator->Ring->Width").toDouble();
+        double g_c = getTechModel()->get("Modulator->Ring->ConfinementFactor").toDouble();
+        // Get ring parameters
+        double R = getTechModel()->get("Ring->Radius").toDouble();
+        double n_g = getTechModel()->get("Ring->GroupIndex").toDouble();
+        double Q_max = getTechModel()->get("Ring->MaxQualityFactor").toDouble();
+
+        // Setup calculations
+        double f0 = c / lambda;
+        double BW = data_rate;                      // Modulator bandwidth
+        double Q_f = std::min(f0 / BW, Q_max);      // Quality factor
+        double L_tot = 2 * pi * R;                  // Optical length of the ring
+
+        double V_bi = k * T / q * log(NA * ND / (ni * ni));                     // Junction Built-in voltage
+        double x_d0 = sqrt(2 * e0 * es / q * V_bi * (NA + ND) / (NA * ND));     // Junction nominal depletion width
+        double C_j0 = e0 * es * L_tot * L_j * W / x_d0;                         // Junction nominal cap        
+        double Q_0 = q * n_g * (L_tot * H * W) / (2 * n_f * Q_f * g_c);         // Charge in depletion region
+
+        // Store into precomputed values
+        m_precompute_V_bi_ = V_bi;
+        m_precompute_x_d0_ = x_d0;
+        m_precompute_C_j0_ = C_j0;
+        m_precompute_Q_0_ = Q_0;
+
+        return;        
+    }
+    
+    bool RingModulator::designModulator(double IL_dB_, double ER_dB_)
+    {
+        // Get parameters
+        double vdd = getTechModel()->get("Vdd");
+        double data_rate = getParameter("DataRate");
+        unsigned int max_predriver_stages = 20;         //TODO: Make this not hardcoded
+        // Get modulator parameters
+        double boost_ratio = getTechModel()->get("Modulator->Ring->SupplyBoostRatio");
+        double Tn = getTechModel()->get("Modulator->Ring->Tn").toDouble();;
+        double H = getTechModel()->get("Modulator->Ring->Height").toDouble();
+
+        // Get Gen properties
+        int number_wavelengths = getGenProperties()->get("NumberWavelengths");
+                
+        // Checking ASSERTions (input properties that don't make any sense)
+        ASSERT(ER_dB_ > 0, "[Error] " + getInstanceName() + " -> Extinction ratio must be > 0!");
+        ASSERT(IL_dB_ > 0, "[Error] " + getInstanceName() + " -> Insertion loss must be > 0!");        
+        
+        // Setup calculations
+        double ER = pow(10, ER_dB_ / 10);            // Extinction ratio
+        double T1 = pow(10, -IL_dB_ / 10);           // Transmisivity on
+        double T0 = T1 / ER;                        // Transmisivity off
+
+        // Get precomputed values
+        double V_bi = m_precompute_V_bi_;
+        double x_d0 = m_precompute_x_d0_;
+        double C_j0 = m_precompute_C_j0_;
+        double Q_0 = m_precompute_Q_0_;
+        
+        // Charge
+        double int_c = -2 * V_bi * C_j0;
+        // Calculate shift using lorentzian
+        double gamma = sqrt((1 - Tn)/(1 - T1) - 1) - sqrt((1 - Tn)/(1 - T0) - 1);   // gamma = delta_f / delta_f_FWHM        
+        double Q = gamma * Q_0;                                                     // Charge required to hit given Tf
+        // Voltage required
+        double V_a = V_bi * (pow( (Q - int_c)/(2 * V_bi * C_j0), 2) - 1);
+        // Calculate driver vdd
+        double hvdd = V_a * boost_ratio;
+        // Depletion region required
+        double x_d = x_d0 * sqrt((V_bi + V_a) / V_bi);
+
+        // Calculate C_eff
+        double c_eff = Q / V_a;
+        
+        // Feasibility checks
+        // Not feasible if the transmisivity when transmitting an optical 1 is greater than 1.0...
+        if (T1 >= 1) return false;
+        // Not feasible if the transmisivity when transmitting an optical 0 is smaller than the notch of the ring
+        if (T0 <= Tn) return false;
+        // Not feasible if the extinction ratio is greater than the notch of the ring
+        if (ER >= 1 / Tn) return false;
+        // Not feasible if the required depletion width is greater than the height of the junction
+        if (x_d >= H) return false;
+
+        // Analytically calculate driver sizes
+        // Get parameters corresponding to a unit-inverter
+        double unit_c_g = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Cap->A");
+        double unit_c_d = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Cap->Y");
+        double unit_r_o = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->DriveRes->Y");
+        double unit_area_active = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Area->Active");
+        double unit_area_metal1 = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Area->Metal1Wire");
+        
+        // Get device resistance/cap
+        double device_par_res = getTechModel()->get("Modulator->Ring->ParasiticRes");
+        double device_par_cap = getTechModel()->get("Modulator->Ring->ParasiticCap");
+        
+        // Use timing tree to size modulator drivers
+        // Coefficient of R*C to give a 0->V_a transition
+        double transition_scale = log(hvdd / (hvdd - V_a));             
+        double transition_required = 1 / (4 * data_rate);      // I am not sure what the factor of 4 is for...
+        
+        // Calculate inverter intrinsic transition time
+        double transition_intrinsic = transition_scale * unit_c_d * unit_r_o;
+        // Calculate minimum possible device transition time
+        double min_transition_intrinsic = transition_intrinsic + transition_scale * device_par_res * c_eff;
+        // If the minimum possible transition time is already bigger
+        // than the required transition, then this particular driver is not possible...
+        if (min_transition_intrinsic > transition_required)
+            return false;
+
+        // Calculate driver size
+        double driver_size = max(1.0, transition_scale * unit_r_o * (c_eff + device_par_cap) / (transition_required - min_transition_intrinsic));
+        // Keep track of the total multiplier of unit inverters (for area, leakage calculations)
+        double total_unit_inverters = driver_size * max(1.0, hvdd / vdd);
+        // Calculate load cap for predriver stages
+        double current_load_cap = driver_size * unit_c_g;
+        // Number of predriver stages
+        unsigned int predriver_stages = 0;
+        // Add predriver stages until the input cap is less than the unit INV_X1 gate cap or
+        // if the signal is still inverted (need an odd number of predriver stages)
+        while (current_load_cap > unit_c_g || (predriver_stages == 0) || ((predriver_stages & 0x1) == 0))
+        {
+            // Calculate the size of the current predriver stage
+            double current_predriver_size = max(1.0, unit_r_o * current_load_cap / (transition_required - transition_intrinsic));
+            // Calculate load cap for the next predriver stage
+            current_load_cap = current_predriver_size * unit_c_g;
+            // Add cap to total predriver total cap
+            total_unit_inverters += current_predriver_size;
+            // Consider this a failure if the number of predriver stages exceed some maximum
+            if (predriver_stages > max_predriver_stages)
+                return false;
+
+            ++predriver_stages;
+        }
+        // Set the input load capacitance
+        getLoad("PredriverCap")->setLoadCap(current_load_cap);
+
+        // Set generated properties
+        getGenProperties()->set("DriverSize", driver_size);
+        getGenProperties()->set("FirstPredriverSize", current_load_cap);
+        getGenProperties()->set("TotalPredriverSize", total_unit_inverters - driver_size);
+        getGenProperties()->set("Hvdd", hvdd);
+        getGenProperties()->set("Ceff", c_eff);
+        
+        // Calculate leakage, area, energy consumption
+        double area_active = total_unit_inverters * unit_area_active;
+        double area_metal1 = total_unit_inverters * unit_area_metal1;
+                
+        // Set results
+        getAreaResult("Active")->setValue(area_active * number_wavelengths);
+        getAreaResult("Metal1Wire")->setValue(area_metal1 * number_wavelengths);
+
+        // Only if everything was successful do we set the modulator specification
+        getModulator("RingModulator")->setLosses(IL_dB_, ER_dB_);
+        return true;        
+    }
+    
+    double RingModulator::calcModulatorEnergy() const
+    {
+        // Get tech parameters
+        double vdd = getTechModel()->get("Vdd");
+        double device_par_cap = getTechModel()->get("Modulator->Ring->ParasiticCap");
+
+        // Get Gen properties
+        int number_wavelengths = getGenProperties()->get("NumberWavelengths");
+        
+        bool success = getGenProperties()->get("Success");
+        if (success)
+        {
+            double driver_size = getGenProperties()->get("DriverSize");
+            double total_predriver_size = getGenProperties()->get("TotalPredriverSize");
+            double first_predriver_size = getGenProperties()->get("FirstPredriverSize");
+            double c_eff = getGenProperties()->get("Ceff");
+            double hvdd = getGenProperties()->get("Hvdd");
+            
+            // Get parameters corresponding to a unit-inverter
+            double unit_c_g = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Cap->A");
+            double unit_c_d = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Cap->Y");
+            
+            // Approximate leakage
+            double energy_predriver = number_wavelengths * vdd * vdd * ((unit_c_d * total_predriver_size + 
+                                            unit_c_g * (total_predriver_size + driver_size - first_predriver_size)));
+            double energy_driver = number_wavelengths * hvdd * std::max(hvdd, vdd) * (driver_size * unit_c_d + c_eff + device_par_cap);
+            
+            return (energy_predriver + energy_driver);
+        }
+        else
+            return 1e99;    // An infinitely expensive modulator
+    }
+    
+    bool RingModulator::setTransmitterSpec(double IL_dB_, double ER_dB_)
+    {
+        setProperty("InsertionLoss", IL_dB_);
+        setProperty("ExtinctionRatio", ER_dB_);
+        update();
+        evaluate();
+        
+        return getGenProperties()->get("Success");
+    }
+    
+    double RingModulator::getPower(double util_) const
+    {
+        // Get parameters
+        double data_rate = getParameter("DataRate");
+               // Check arguments
+        ASSERT((util_ <= 1.0) && (util_ >= 0.0), "[Error] " + getInstanceName() + " -> Modulator utilization must be between 0.0 and 1.0!");
+
+        return calcModulatorEnergy() * 0.25 * util_ * data_rate;
+    }
+    
+} // namespace DSENT
+
diff --git a/ext/dsent/model/optical/RingModulator.h b/ext/dsent/model/optical/RingModulator.h
new file mode 100644 (file)
index 0000000..bbfa7f4
--- /dev/null
@@ -0,0 +1,54 @@
+#ifndef __DSENT_MODEL_OPTICAL_RINGMODULATOR_H__
+#define __DSENT_MODEL_OPTICAL_RINGMODULATOR_H__
+
+#include "util/CommonType.h"
+#include "model/OpticalModel.h"
+#include "model/optical_graph/OpticalTransmitter.h"
+
+namespace DSENT
+{
+    class RingModulator : public OpticalModel, public OpticalTransmitter
+    {
+        public:
+            RingModulator(const String& instance_name_, const TechModel* tech_model_);
+            virtual ~RingModulator();
+
+        public:
+            // Set a list of properties' name needed to construct model
+            void initParameters();
+            // Set a list of properties' name needed to construct model
+            void initProperties();
+            // Set the transmitter specifications, returns whether it is possible
+            // to build a modulator that met those specs
+            bool setTransmitterSpec(double IL_dB_, double ER_dB_);
+            // Returns power of the transmitter at a given utilization
+            double getPower(double util_) const;
+        
+        private:
+            // Precompute values based on tech parameters
+            void precomputeTech();
+            // Design ring modulator driver
+            bool designModulator(double IL_dB_, double ER_dB_);
+            // Calculate modulator energy
+            double calcModulatorEnergy() const;
+            
+        protected:
+            // Build the model
+            virtual void constructModel();
+            virtual void updateModel();
+            virtual void useModel();
+            virtual void propagateTransitionInfo();
+
+        private:
+            // Some precomputed tech values
+            double m_precompute_V_bi_;
+            double m_precompute_x_d0_;
+            double m_precompute_C_j0_;
+            double m_precompute_Q_0_;
+            
+            
+    }; // class RingModulator
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_OPTICAL_RINGMODULATOR_H__
+
diff --git a/ext/dsent/model/optical/SWMRLink.cc b/ext/dsent/model/optical/SWMRLink.cc
new file mode 100644 (file)
index 0000000..56d2d70
--- /dev/null
@@ -0,0 +1,309 @@
+#include "model/optical/SWMRLink.h"
+
+#include "model/PortInfo.h"
+#include "model/TransitionInfo.h"
+#include "model/EventInfo.h"
+#include "model/optical_graph/OpticalGraph.h"
+#include "model/optical_graph/OpticalWaveguide.h"
+#include "model/optical/RingModulator.h"
+#include "model/optical/RingFilter.h"
+#include "model/optical/RingDetector.h"
+#include "model/optical/LaserSource.h"
+#include "model/optical/ThrottledLaserSource.h"
+
+namespace DSENT
+{
+    SWMRLink::SWMRLink(const String& instance_name_, const TechModel* tech_model_)
+        : OpticalModel(instance_name_, tech_model_)
+    {
+        initParameters();
+        initProperties();
+    }
+
+    SWMRLink::~SWMRLink()
+    {}
+
+    void SWMRLink::initParameters()
+    {
+        addParameterName("NumberReaders");
+        addParameterName("NumberWavelengths");
+        addParameterName("DataRate");
+        addParameterName("LaserType");
+        addParameterName("MaxReaders");
+        addParameterName("MinReaders");
+        addParameterName("OptimizeLoss", "TRUE");
+        return;
+    }
+
+    void SWMRLink::initProperties()
+    {
+        addPropertyName("Length");
+               addPropertyName("OptUtil", 0.5);        // default to 50% utilization (a new word 50% of the time)
+        addPropertyName("ExtinctionRatio", 6);  // default properties
+        addPropertyName("InsertionLoss", 2);    // default properties
+        return;
+    }
+
+    void SWMRLink::constructModel()
+    {
+        // Get parameters
+        unsigned int number_wavelengths = getParameter("NumberWavelengths");
+        unsigned int number_readers = getParameter("NumberReaders");
+        unsigned int number_max_readers = std::min(number_readers, getParameter("MaxReaders").toUInt());
+        unsigned int number_min_readers = std::min(number_max_readers, getParameter("MinReaders").toUInt());
+        
+        // Create electrical ports
+        createInputPort("CK");
+        createInputPort("In", makeNetIndex(0, number_wavelengths-1));
+        for (unsigned int i = 0; i < number_readers; ++i)
+            createOutputPort("Out" + (String) i, makeNetIndex(0, number_wavelengths-1));
+
+        // Create Waveguides
+        // Temporarily assume its all on one waveguide
+        createWaveguide("LaserToMod", makeWavelengthGroup(0, number_wavelengths-1));
+        for (unsigned int i = 0; i <= number_readers; ++i)
+            createWaveguide("WaveguideSegment[" + (String) i + "]", makeWavelengthGroup(0, number_wavelengths-1));        
+        
+        // Add area results
+        addAreaResult(new Result("Photonic"));
+        createElectricalResults();
+        // Setup idle event
+        getEventInfo("Idle")->setStaticTransitionInfos();
+        // Create a waveguide area result
+        addAreaResult(new AtomicResult("Waveguide"));
+        getAreaResult("Photonic")->addSubResult(getAreaResult("Waveguide"), "Waveguide", 1.0);
+        // Add results
+        addNddPowerResult(new Result("Laser"));
+        // Add event result
+        createElectricalEventResult("BroadcastFlit");
+        
+        for (unsigned int i = number_min_readers; i <= number_max_readers; ++i)
+            createElectricalEventResult("MulticastFlit" + (String) i);
+
+        buildLaser();
+        buildModulator();
+        buildDetectors();
+        
+        return;
+    }
+    
+    void SWMRLink::updateModel()
+    {
+        // Get parameters
+        double data_rate = getParameter("DataRate");
+        unsigned int number_readers = getParameter("NumberReaders");
+
+        // Get properties
+        double length = getProperty("Length");
+        const String& extinction_ratio = getProperty("ExtinctionRatio");
+        const String& insertion_loss = getProperty("InsertionLoss");
+               const double opt_util = getProperty("OptUtil");
+        
+        // Calculate loss for each waveguide segment
+        double segment_length = (double) length / number_readers;
+        double segment_loss = getTechModel()->get("Waveguide->LossPerMeter").toDouble() * segment_length;
+        // Set loss of each waveguide segment
+        for (unsigned int i = 0; i < number_readers; ++i)
+            getWaveguide("WaveguideSegment[" + (String) i + "]")->setLoss(segment_loss);
+        // Calculate waveguide area
+        double waveguide_area = length * getTechModel()->get("Waveguide->Pitch").toDouble();
+        getAreaResult("Waveguide")->setValue(waveguide_area);
+    
+        // Update the laser
+        Model* laser = getSubInstance("Laser");
+        laser->setProperty("LaserEventTime", 1.0 / data_rate);
+        laser->setProperty("OptUtil", opt_util);
+        laser->update();
+        
+        // Update the modulator
+        Model* modulator = getSubInstance("Modulator");
+        modulator->setProperty("ExtinctionRatio", extinction_ratio);
+        modulator->setProperty("InsertionLoss", insertion_loss);
+        modulator->update();        
+        
+        // Update all receivers
+        for (unsigned int i = 0; i < number_readers; ++i)
+        {
+            Model* detector = getSubInstance("Detector_" + (String) i);
+            detector->update();
+        }
+                   
+        return;
+    }
+    
+    void SWMRLink::propagateTransitionInfo()
+    {
+        // Get parameters
+        const String& laser_type = getParameter("LaserType");
+        unsigned int number_readers = getParameter("NumberReaders");
+
+        // Set transition info for the modulator
+        OpticalModel* modulator = (OpticalModel*) getSubInstance("Modulator");
+        propagatePortTransitionInfo(modulator, "In", "In");
+        modulator->use();
+        
+        // Modulator out transition info
+        const TransitionInfo& mod_out_transitions = modulator->getOpticalOutputPort("Out")->getTransitionInfo();
+        
+        // Set transition info for all receivers
+        for (unsigned int i = 0; i < number_readers; ++i)
+        {
+            OpticalModel* detector = (OpticalModel*) getSubInstance("Detector_" + (String) i);
+            detector->getOpticalInputPort("In")->setTransitionInfo(mod_out_transitions);
+            detector->use();
+            
+            // Propagate output transition info to output
+            propagatePortTransitionInfo("Out" + (String) i, detector, "Out");
+        }
+        
+        // Set enable signals for the laser, if applicable
+        if (laser_type == "Throttled")
+        {
+            // Figure out how many cycles the laser needs to be on
+            double cycles = getInputPort("In")->getTransitionInfo().getFrequencyMultiplier();
+        
+            OpticalModel* laser = (OpticalModel*) getSubInstance("Laser");
+            laser->getInputPort("LaserEnable")->setTransitionInfo(TransitionInfo(0.0, 1.0, cycles - 1.0));
+            laser->use();
+        }
+        return;
+    }
+
+    void SWMRLink::buildLaser()
+    {
+        // Get parameters
+        unsigned int number_wavelengths = getParameter("NumberWavelengths");
+        unsigned int number_readers = getParameter("NumberReaders");
+        unsigned int number_max_readers = std::min(number_readers, getParameter("MaxReaders").toUInt());
+        unsigned int number_min_readers = std::min(number_max_readers, getParameter("MinReaders").toUInt());
+        const String& laser_type = getParameter("LaserType");
+
+        // Create laser
+        OpticalModel* laser = NULL;
+        if (laser_type == "Throttled")
+            laser = new ThrottledLaserSource("Laser", getTechModel());
+        else if (laser_type == "Standard")
+            laser = new LaserSource("Laser", getTechModel());        
+        else
+            ASSERT(false, "[Error] " + getInstanceName() + " -> Unknown laser type '" + laser_type + "'!");
+        
+        laser->setParameter("OutStart", 0);
+        laser->setParameter("OutEnd", number_wavelengths-1);
+        laser->setParameter("MaxDetectors", number_max_readers);
+        laser->setParameter("MinDetectors", number_min_readers);
+        laser->construct();        
+
+        addSubInstances(laser, 1.0);
+        getAreaResult("Photonic")->addSubResult(laser->getAreaResult("Photonic"), "Laser", 1.0);
+        // Connect laser output port
+        opticalPortConnect(laser, "Out", "LaserToMod");    
+
+        // Without laser gating, laser is pure NDD power
+        if (laser_type == "Standard")
+            getNddPowerResult("Laser")->addSubResult(laser->getNddPowerResult("Laser"), "Laser", 1.0);
+        // With laser power gating, laser is an event
+        else
+        {
+            // If laser is throttled, only pay for the amount needed to reach some number of readers
+            getEventResult("BroadcastFlit")->addSubResult(laser->getEventResult("Laser" + (String) number_max_readers), "Laser", 1.0);
+            for (unsigned int i = number_min_readers; i <= number_max_readers; ++i)
+                getEventResult("MulticastFlit" + (String) i)->addSubResult(laser->getEventResult("Laser" + (String) i), "Laser", 1.0);
+        }
+        
+        return;
+    }
+    
+    void SWMRLink::buildModulator()
+    {
+        // Get parameters
+        double data_rate = getParameter("DataRate");
+        const String& optimize_loss = getParameter("OptimizeLoss");
+        unsigned int number_wavelengths = getParameter("NumberWavelengths");
+        unsigned int number_readers = getParameter("NumberReaders");
+        unsigned int number_max_readers = std::min(number_readers, getParameter("MaxReaders").toUInt());
+        unsigned int number_min_readers = std::min(number_max_readers, getParameter("MinReaders").toUInt());
+
+        // Create modulator
+        RingModulator* modulator = new RingModulator("Modulator", getTechModel());
+        modulator->setParameter("DataRate", data_rate);
+        modulator->setParameter("InStart", 0);
+        modulator->setParameter("InEnd", number_wavelengths-1);
+        modulator->setParameter("ModStart", 0);
+        modulator->setParameter("ModEnd", number_wavelengths-1);
+        modulator->setParameter("OptimizeLoss", optimize_loss);
+        modulator->construct();
+        addSubInstances(modulator, 1.0);
+        getAreaResult("Photonic")->addSubResult(modulator->getAreaResult("Photonic"), "Modulator", 1.0);
+        addElectricalSubResults(modulator, 1.0);
+
+        // Connect electrical port
+        portConnect(modulator, "In", "In");
+        // Connect modulator input, output port
+        opticalPortConnect(modulator, "In", "LaserToMod");
+        opticalPortConnect(modulator, "Out", "WaveguideSegment[0]");
+        
+        // Add modulator energy event for all broadcast events
+        getEventResult("BroadcastFlit")->addSubResult(modulator->getEventResult("Modulate"), "Modulator", 1.0);
+        for (unsigned int i = number_min_readers; i <= number_max_readers; ++i)
+            getEventResult("MulticastFlit" + (String) i)->addSubResult(modulator->getEventResult("Modulate"), "Modulator", 1.0);
+
+        return;
+    }
+    
+    void SWMRLink::buildDetectors()
+    {
+        // Get parameters
+        double data_rate = getParameter("DataRate");
+        unsigned int number_wavelengths = getParameter("NumberWavelengths");
+        unsigned int number_readers = getParameter("NumberReaders");
+        unsigned int number_max_readers = std::min(number_readers, getParameter("MaxReaders").toUInt());
+        unsigned int number_min_readers = std::min(number_max_readers, getParameter("MinReaders").toUInt());
+
+        // Create a SWMR Configuration
+        for (unsigned int i = 0; i < number_readers; ++i)
+        {
+            String n = (String) i;
+            
+            // Create resonant ring detector
+            RingDetector* detector = new RingDetector("Detector_" + n, getTechModel());
+            detector->setParameter("DataRate", data_rate);
+            detector->setParameter("InStart", 0);
+            detector->setParameter("InEnd", number_wavelengths-1);
+            detector->setParameter("DetStart", 0);
+            detector->setParameter("DetEnd", number_wavelengths-1);
+            detector->setParameter("DropAll", "FALSE");
+            detector->setParameter("Topology", RingDetector::INTEGRATINGSENSEAMP);
+            detector->construct();
+            addSubInstances(detector, 1.0);
+            getAreaResult("Photonic")->addSubResult(detector->getAreaResult("Photonic"), "Detector_" + n, 1.0);
+            addElectricalSubResults(detector, 1.0);
+
+            // connect to electrical port
+            portConnect(detector, "Out", "Out" + (String) i);
+            // connect optical input, output port           
+            opticalPortConnect(detector, "In", "WaveguideSegment[" + (String) i + "]");
+            opticalPortConnect(detector, "Out", "WaveguideSegment[" + (String) (i + 1) + "]");            
+        }
+        
+        // Add an average receiver energy for all multicast events (and broadcast)
+        Result* broadcast_event = getEventResult("BroadcastFlit");
+        for (unsigned int i = 0; i < number_readers; ++i)
+        {
+            const String detector_name = "Detector_" + (String) i;
+            broadcast_event->addSubResult(getSubInstance(detector_name)->getEventResult("Receive"), detector_name, 1.0);
+        }
+        for (unsigned int i = number_min_readers; i <= number_max_readers; ++i)
+        {
+            Result* multicast_event = getEventResult("MulticastFlit" + (String) i);
+            for (unsigned int j = 0; j < number_readers; ++j)
+            {
+                const String detector_name = "Detector_" + (String) j;
+                multicast_event->addSubResult(getSubInstance(detector_name)->getEventResult("Receive"), detector_name, (double) i / number_readers);
+            }
+        }
+
+        return;
+    }
+    
+} // namespace DSENT
+
diff --git a/ext/dsent/model/optical/SWMRLink.h b/ext/dsent/model/optical/SWMRLink.h
new file mode 100644 (file)
index 0000000..a261835
--- /dev/null
@@ -0,0 +1,38 @@
+#ifndef __DSENT_MODEL_OPTICAL_SWMRLINK_H__
+#define __DSENT_MODEL_OPTICAL_SWMRLINK_H__
+
+#include "util/CommonType.h"
+#include "model/OpticalModel.h"
+
+namespace DSENT
+{
+    class SWMRLink : public OpticalModel
+    {
+        // A SWMR Link consists of a laser, a modulator (the writer) and a variable
+        // number of readers
+        public:
+            SWMRLink(const String& instance_name_, const TechModel* tech_model_);
+            virtual ~SWMRLink();
+
+        public:
+            // Set a list of properties' name needed to construct model
+            void initParameters();
+            // Set a list of properties' name needed to construct model
+            void initProperties();
+
+        protected:
+            // Build the model
+            virtual void constructModel();
+            virtual void updateModel();
+            virtual void propagateTransitionInfo();
+            
+        private:
+            void buildLaser();
+            void buildModulator();
+            void buildDetectors();
+
+    }; // class SWMRLink
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_OPTICAL_SWMRLINK_H__
+
diff --git a/ext/dsent/model/optical/SWSRLink.cc b/ext/dsent/model/optical/SWSRLink.cc
new file mode 100644 (file)
index 0000000..88973e3
--- /dev/null
@@ -0,0 +1,328 @@
+#include "model/optical/SWSRLink.h"
+
+#include "model/ModelGen.h"
+#include "model/PortInfo.h"
+#include "model/TransitionInfo.h"
+#include "model/EventInfo.h"
+#include "model/optical_graph/OpticalGraph.h"
+#include "model/optical_graph/OpticalWaveguide.h"
+#include "model/optical/RingModulator.h"
+#include "model/optical/RingFilter.h"
+#include "model/optical/RingDetector.h"
+#include "model/optical/LaserSource.h"
+#include "model/optical/ThrottledLaserSource.h"
+
+namespace DSENT
+{
+    SWSRLink::SWSRLink(const String& instance_name_, const TechModel* tech_model_)
+        : OpticalModel(instance_name_, tech_model_)
+    {
+        initParameters();
+        initProperties();
+    }
+
+    SWSRLink::~SWSRLink()
+    {}
+
+    void SWSRLink::initParameters()
+    {
+        addParameterName("NumberBits");     
+        addParameterName("CoreDataRate");
+        addParameterName("LinkDataRate");
+
+        addParameterName("LaserType");
+        addParameterName("RingTuningMethod");
+        addParameterName("OptimizeLoss", "TRUE");
+
+        return;
+    }
+
+    void SWSRLink::initProperties()
+    {
+        addPropertyName("Length");
+               addPropertyName("OptUtil", 0.5);        // default to 50% utilization (a new word 50% of the time)
+        addPropertyName("ExtinctionRatio", 6);  // default properties
+        addPropertyName("InsertionLoss", 2);    // default properties
+        return;
+    }
+
+    void SWSRLink::constructModel()
+    {
+        // Get parameters
+        unsigned int number_bits = getParameter("NumberBits");
+        double core_data_rate = getParameter("CoreDataRate");
+        double link_data_rate = getParameter("LinkDataRate");
+        
+        // Get directly propagated parameters
+        const String& ring_tuning_method = getParameter("RingTuningMethod");
+        
+        // Calculate number of wavelengths needed
+        unsigned int number_wavelengths = (unsigned int)((double) number_bits * core_data_rate / link_data_rate);
+        
+        // Set some generated properties
+        getGenProperties()->set("NumberWavelengths", number_wavelengths);
+        
+        // Create electrical ports
+        createInputPort("LinkCK");
+        createInputPort("In", makeNetIndex(0, number_bits-1));
+        createOutputPort("Out", makeNetIndex(0, number_bits-1));
+
+        // Create Waveguides
+        // Temporarily assume its all on one waveguide
+        createWaveguide("LaserToMod", makeWavelengthGroup(0, number_wavelengths-1));
+        createWaveguide("ModToDetector", makeWavelengthGroup(0, number_wavelengths-1));        
+        
+        // Add area results
+        addAreaResult(new Result("Photonic"));
+        createElectricalResults();
+        // Setup idle event
+        getEventInfo("Idle")->setStaticTransitionInfos();
+        // Create a waveguide area result
+        addAreaResult(new AtomicResult("Waveguide"));
+        getAreaResult("Photonic")->addSubResult(getAreaResult("Waveguide"), "Waveguide", 1.0);
+        // Add results
+        addNddPowerResult(new Result("Laser"));
+        addNddPowerResult(new Result("RingTuning"));
+        // Add event result
+        createElectricalEventResult("Send");
+        
+        // Create Tx, Rx backends
+        // Create Tx electrical backend
+        ElectricalModel* tx_backend = (ElectricalModel*) ModelGen::createModel("OpticalLinkBackendTx", "OpticalLinkBackendTx", getTechModel());
+        tx_backend->setParameter("InBits", number_bits);
+        tx_backend->setParameter("CoreDataRate", core_data_rate);
+        tx_backend->setParameter("LinkDataRate", link_data_rate);
+        tx_backend->setParameter("RingTuningMethod", ring_tuning_method);
+        tx_backend->setParameter("BitDuplicate", "TRUE");
+        tx_backend->construct();
+
+        // Create Rx electrical backend
+        ElectricalModel* rx_backend = (ElectricalModel*) ModelGen::createModel("OpticalLinkBackendRx", "OpticalLinkBackendRx", getTechModel());
+        rx_backend->setParameter("OutBits", number_bits);
+        rx_backend->setParameter("CoreDataRate", core_data_rate);
+        rx_backend->setParameter("LinkDataRate", link_data_rate);
+        rx_backend->setParameter("RingTuningMethod", ring_tuning_method);
+        rx_backend->setParameter("BitDuplicate", "TRUE");
+        rx_backend->construct();
+        
+        // Connect ports
+        createNet("TxBackendToTx", makeNetIndex(0, number_wavelengths-1));
+        createNet("RxToRxBackend", makeNetIndex(0, number_wavelengths-1));
+        portConnect(tx_backend, "In", "In");
+        portConnect(tx_backend, "Out", "TxBackendToTx");
+        portConnect(tx_backend, "LinkCK", "LinkCK");
+        portConnect(rx_backend, "In", "RxToRxBackend");
+        portConnect(rx_backend, "Out", "Out");
+        portConnect(rx_backend, "LinkCK", "LinkCK");
+
+        // Add instances
+        addSubInstances(tx_backend, 1.0);
+        addSubInstances(rx_backend, 1.0);
+
+        // Add electrical results
+        addElectricalSubResults(tx_backend, 1.0);
+        addElectricalSubResults(rx_backend, 1.0);
+        
+        // Add tuning power result
+        getNddPowerResult("RingTuning")->addSubResult(tx_backend->getNddPowerResult("RingTuning"), "OpticalLinkBackendTx", 1.0);
+        getNddPowerResult("RingTuning")->addSubResult(rx_backend->getNddPowerResult("RingTuning"), "OpticalLinkBackendRx", 1.0);
+        
+        // Add event results
+        getEventInfo("Send")->setTransitionInfo("LinkCK", TransitionInfo(0.0, (double) link_data_rate / (core_data_rate * 2.0), 0.0));
+
+        getEventResult("Send")->addSubResult(tx_backend->getEventResult("ProcessBits"), "OpticalLinkBackendTx", 1.0);
+        getEventResult("Send")->addSubResult(rx_backend->getEventResult("ProcessBits"), "OpticalLinkBackendRx", 1.0);
+        
+        buildLaser();
+        buildModulator();
+        buildDetector();
+        
+        return;
+    }
+    
+    void SWSRLink::updateModel()
+    {
+        // Get parameters
+        double link_data_rate = getParameter("LinkDataRate");
+        
+        // Get properties
+        double length = getProperty("Length");
+        const String& extinction_ratio = getProperty("ExtinctionRatio");
+        const String& insertion_loss = getProperty("InsertionLoss");
+               const double opt_util = getProperty("OptUtil");
+               
+        // Calculate loss for waveguide
+        double waveguide_loss = getTechModel()->get("Waveguide->LossPerMeter").toDouble() * length;
+        // Set loss of the waveguide
+        getWaveguide("ModToDetector")->setLoss(waveguide_loss);
+        // Calculate waveguide area
+        double waveguide_area = length * getTechModel()->get("Waveguide->Pitch").toDouble();
+        getAreaResult("Waveguide")->setValue(waveguide_area);
+    
+        // Update the laser
+        Model* laser = getSubInstance("Laser");
+        laser->setProperty("LaserEventTime", 1.0 / link_data_rate);
+               laser->setProperty("OptUtil", opt_util);
+        laser->update();
+        
+        // Update the modulator
+        Model* modulator = getSubInstance("Modulator");
+        modulator->setProperty("ExtinctionRatio", extinction_ratio);
+        modulator->setProperty("InsertionLoss", insertion_loss);
+        modulator->update();        
+        
+        Model* detector = getSubInstance("Detector");
+        detector->update();
+        
+        Model* tx_backend = getSubInstance("OpticalLinkBackendTx");
+        tx_backend->update();
+                   
+        Model* rx_backend = getSubInstance("OpticalLinkBackendRx");
+        rx_backend->update();
+
+        return;
+    }
+    
+    void SWSRLink::propagateTransitionInfo()
+    {
+        // Get parameters
+        const String& laser_type = getParameter("LaserType");
+
+        // Propagate transition info to tx backend
+        OpticalModel* tx_backend = (OpticalModel*) getSubInstance("OpticalLinkBackendTx");
+        propagatePortTransitionInfo(tx_backend, "In", "In");
+        propagatePortTransitionInfo(tx_backend, "LinkCK", "LinkCK");
+        tx_backend->use();
+        
+        // Set transition info for the modulator
+        OpticalModel* modulator = (OpticalModel*) getSubInstance("Modulator");
+        propagatePortTransitionInfo(modulator, "In", tx_backend, "Out");
+        modulator->use();
+        
+        // Modulator out transition info
+        const TransitionInfo& mod_out_transitions = modulator->getOpticalOutputPort("Out")->getTransitionInfo();
+        
+        // Set transition info for the receiver
+        OpticalModel* detector = (OpticalModel*) getSubInstance("Detector");
+        detector->getOpticalInputPort("In")->setTransitionInfo(mod_out_transitions);
+        detector->use();            
+        
+        // Propagate transition info to tx backend
+        OpticalModel* rx_backend = (OpticalModel*) getSubInstance("OpticalLinkBackendRx");
+        propagatePortTransitionInfo(rx_backend, "In", detector, "Out");
+        propagatePortTransitionInfo(rx_backend, "LinkCK", "LinkCK");
+        rx_backend->use();
+
+        // Propagate output transition info to output
+        propagatePortTransitionInfo("Out", rx_backend, "Out");
+
+        // Set enable signals for the laser, if applicable
+        if (laser_type == "Throttled")
+        {
+            // Figure out how many cycles the laser needs to be on
+            double cycles = getInputPort("In")->getTransitionInfo().getFrequencyMultiplier();
+        
+            OpticalModel* laser = (OpticalModel*) getSubInstance("Laser");
+            laser->getInputPort("LaserEnable")->setTransitionInfo(TransitionInfo(0.0, 1.0, cycles - 1.0));
+            laser->use();
+        }
+        
+        
+        return;
+    }
+
+    void SWSRLink::buildLaser()
+    {
+        // Get parameters
+        unsigned int number_wavelengths = getGenProperties()->get("NumberWavelengths");
+        const String& laser_type = getParameter("LaserType");
+
+        // Create laser
+        OpticalModel* laser = NULL;
+        if (laser_type == "Throttled") laser = new ThrottledLaserSource("Laser", getTechModel());
+        else if (laser_type == "Standard") laser = new LaserSource("Laser", getTechModel());        
+        else ASSERT(false, "[Error] " + getInstanceName() + " -> Unknown laser type '" + laser_type + "'!");
+        
+        laser->setParameter("OutStart", 0);
+        laser->setParameter("OutEnd", number_wavelengths-1);
+        laser->setParameter("MaxDetectors", 1);
+        laser->setParameter("MinDetectors", 1);
+        laser->construct();        
+
+        addSubInstances(laser, 1.0);
+        getAreaResult("Photonic")->addSubResult(laser->getAreaResult("Photonic"), "Laser", 1.0);
+        // Connect laser output port
+        opticalPortConnect(laser, "Out", "LaserToMod");    
+
+        // Without laser gating, laser is pure NDD power
+        if (laser_type == "Standard") getNddPowerResult("Laser")->addSubResult(laser->getNddPowerResult("Laser"), "Laser", 1.0);
+        // With laser power gating, laser is an event
+        else getEventResult("Send")->addSubResult(laser->getEventResult("Laser1"), "Laser", 1.0);
+        
+        return;
+    }
+    
+    void SWSRLink::buildModulator()
+    {
+        // Get parameters
+        double link_data_rate = getParameter("LinkDataRate");
+        const String& optimize_loss = getParameter("OptimizeLoss");
+        unsigned int number_wavelengths = getGenProperties()->get("NumberWavelengths");
+
+        // Create modulator
+        RingModulator* modulator = new RingModulator("Modulator", getTechModel());
+        modulator->setParameter("DataRate", link_data_rate);
+        modulator->setParameter("InStart", 0);
+        modulator->setParameter("InEnd", number_wavelengths-1);
+        modulator->setParameter("ModStart", 0);
+        modulator->setParameter("ModEnd", number_wavelengths-1);
+        modulator->setParameter("OptimizeLoss", optimize_loss);
+        modulator->construct();
+        addSubInstances(modulator, 1.0);
+        getAreaResult("Photonic")->addSubResult(modulator->getAreaResult("Photonic"), "Modulator", 1.0);
+        addElectricalSubResults(modulator, 1.0);
+
+        // Connect electrical port
+        portConnect(modulator, "In", "TxBackendToTx");
+        // Connect modulator input, output port
+        opticalPortConnect(modulator, "In", "LaserToMod");
+        opticalPortConnect(modulator, "Out", "ModToDetector");
+        
+        // Add modulator energy event for send events
+        getEventResult("Send")->addSubResult(modulator->getEventResult("Modulate"), "Modulator", 1.0);
+        return;
+    }
+    
+    void SWSRLink::buildDetector()
+    {
+        // Get parameters
+        double link_data_rate = getParameter("LinkDataRate");
+        unsigned int number_wavelengths = getGenProperties()->get("NumberWavelengths");
+
+        // Create resonant ring detector
+        RingDetector* detector = new RingDetector("Detector", getTechModel());
+        detector->setParameter("DataRate", link_data_rate);
+        detector->setParameter("InStart", 0);
+        detector->setParameter("InEnd", number_wavelengths-1);
+        detector->setParameter("DetStart", 0);
+        detector->setParameter("DetEnd", number_wavelengths-1);
+        detector->setParameter("DropAll", "TRUE");
+        detector->setParameter("Topology", RingDetector::INTEGRATINGSENSEAMP);
+        detector->construct();
+        addSubInstances(detector, 1.0);
+        getAreaResult("Photonic")->addSubResult(detector->getAreaResult("Photonic"), "Detector", 1.0);
+        addElectricalSubResults(detector, 1.0);
+
+        // connect to electrical port
+        portConnect(detector, "Out", "RxToRxBackend");
+        // connect optical input, output port           
+        opticalPortConnect(detector, "In", "ModToDetector");
+        
+        // Add receiver energy
+        getEventResult("Send")->addSubResult(detector->getEventResult("Receive"), "Detector", 1.0);
+        
+        return;
+    }
+    
+} // namespace DSENT
+
diff --git a/ext/dsent/model/optical/SWSRLink.h b/ext/dsent/model/optical/SWSRLink.h
new file mode 100644 (file)
index 0000000..fd6ecca
--- /dev/null
@@ -0,0 +1,38 @@
+#ifndef __DSENT_MODEL_OPTICAL_SWSRLINK_H__
+#define __DSENT_MODEL_OPTICAL_SWSRLINK_H__
+
+#include "util/CommonType.h"
+#include "model/OpticalModel.h"
+
+namespace DSENT
+{
+    class SWSRLink : public OpticalModel
+    {
+        // A SWSR Link consists of a laser, a modulator (the writer) and a variable
+        // number of readers
+        public:
+            SWSRLink(const String& instance_name_, const TechModel* tech_model_);
+            virtual ~SWSRLink();
+
+        public:
+            // Set a list of properties' name needed to construct model
+            void initParameters();
+            // Set a list of properties' name needed to construct model
+            void initProperties();
+
+        protected:
+            // Build the model
+            virtual void constructModel();
+            virtual void updateModel();
+            virtual void propagateTransitionInfo();
+            
+        private:
+            void buildLaser();
+            void buildModulator();
+            void buildDetector();
+
+    }; // class SWSRLink
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_OPTICAL_SWSRLINK_H__
+
diff --git a/ext/dsent/model/optical/ThrottledLaserSource.cc b/ext/dsent/model/optical/ThrottledLaserSource.cc
new file mode 100644 (file)
index 0000000..e95188b
--- /dev/null
@@ -0,0 +1,137 @@
+#include "model/optical/ThrottledLaserSource.h"
+
+#include "model/PortInfo.h"
+#include "model/TransitionInfo.h"
+#include "model/EventInfo.h"
+#include "model/optical_graph/OpticalWaveguide.h"
+#include "model/optical_graph/OpticalWavelength.h"
+#include "model/optical_graph/OpticalLaser.h"
+#include "model/optical_graph/OpticalGraph.h"
+
+namespace DSENT
+{
+    ThrottledLaserSource::ThrottledLaserSource(const String& instance_name_, const TechModel* tech_model_)
+        : OpticalModel(instance_name_, tech_model_), m_wavelength_(NULL)
+    {
+        initParameters();
+        initProperties();
+    }
+
+    ThrottledLaserSource::~ThrottledLaserSource()
+    {
+        if (m_wavelength_ != NULL) delete m_wavelength_;
+    }
+
+    void ThrottledLaserSource::initParameters()
+    {
+        addParameterName("OutStart");
+        addParameterName("OutEnd");
+        addParameterName("MaxDetectors");
+        addParameterName("MinDetectors");
+        return;
+    }
+
+    void ThrottledLaserSource::initProperties()
+    {
+               addPropertyName("OptUtil", 1.0);
+        addPropertyName("LaserEventTime");
+        return;
+    }
+
+    void ThrottledLaserSource::constructModel()
+    {
+        // Get parameters
+        WavelengthGroup laser_wavelengths = makeWavelengthGroup(getParameter("OutStart"), getParameter("OutEnd"));
+        unsigned int max_detectors = getParameter("MaxDetectors").toUInt();
+        unsigned int min_detectors = getParameter("MinDetectors").toUInt();
+        
+        // Create electrical input port for laser control
+        createInputPort(    "LaserEnable");
+            
+        // Create Area result
+        addAreaResult(new AtomicResult("Photonic"));
+        // Create event result for each detector number possibility
+        for (unsigned int i = min_detectors; i <= max_detectors; ++i)
+        {
+            createElectricalEventAtomicResult("Laser" + (String) i);
+            getEventInfo("Laser" + (String) i)->setTransitionInfo("LaserEnable", TransitionInfo(0.0, 1.0, 0.0));
+        }
+
+        // Create optical ports
+        createOpticalOutputPort(    "Out",      laser_wavelengths);
+        // Create the filter
+        createLaser(                "Laser",    laser_wavelengths);
+        OpticalLaser* laser = getLaser("Laser");
+        // Connect the laser to the output
+        laser->addDownstreamNode(getWaveguide("Out"));
+    }
+    
+    void ThrottledLaserSource::updateModel()
+    {
+        // Get properties
+        double laser_efficiency = getTechModel()->get("Laser->CW->Efficiency").toDouble();
+        double laser_area = getTechModel()->get("Laser->CW->Area").toDouble();
+        double laser_diode_loss = getTechModel()->get("Laser->CW->LaserDiodeLoss");
+
+        // Get parameters
+        WavelengthGroup laser_wavelengths = makeWavelengthGroup(getParameter("OutStart"), getParameter("OutEnd"));
+        unsigned int number_wavelengths = laser_wavelengths.second - laser_wavelengths.first + 1;
+        // Update losses
+        OpticalLaser* laser = getLaser("Laser");
+        laser->setLoss(laser_diode_loss);
+        laser->setEfficiency(laser_efficiency);
+        // Update area
+        getAreaResult("Photonic")->setValue(laser_area * number_wavelengths);
+    }
+    
+    void ThrottledLaserSource::evaluateModel()
+    {    
+        // Get parameters
+        unsigned int max_detectors = getParameter("MaxDetectors");
+        WavelengthGroup laser_wavelengths = makeWavelengthGroup(getParameter("OutStart"), getParameter("OutEnd"));
+               
+               // Get properties
+               double opt_util = getProperty("OptUtil");
+               
+        // Create optical graph object
+        OpticalGraph* optical_graph = new OpticalGraph("LaserTrace", this);        
+        // Ask optical graph object to perform power optimization
+        bool success = optical_graph->performPowerOpt(getLaser("Laser"), laser_wavelengths, max_detectors, opt_util);
+        if (!success)
+        {
+            Log::printLine(std::cerr, "[Warning] " + getInstanceName() +
+                " -> Wavelengths contains data paths with no possible modulator configurations!");
+        }
+        
+        // Trace the wavelengths the laser is outputting to find the output
+        // power needed by the laser        
+        if (m_wavelength_ != NULL) delete m_wavelength_;
+        m_wavelength_ = optical_graph->traceWavelength(laser_wavelengths, getLaser("Laser"));        
+
+        delete optical_graph;
+    }
+    
+    void ThrottledLaserSource::useModel()
+    {
+        // Get parameters
+        unsigned int max_detectors = getParameter("MaxDetectors");
+        unsigned int min_detectors = getParameter("MinDetectors");
+
+        // Get properties
+        double laser_event_time = getProperty("LaserEventTime");
+        // Get laser enable information
+        const TransitionInfo& enable_info = getInputPort("LaserEnable")->getTransitionInfo();
+        
+        for (unsigned int i = min_detectors; i <= max_detectors; ++i)
+        {
+            // Calculate the power needed by the wavelength
+            double laser_power = m_wavelength_->getLaserPower(i);
+            // Calculate the laser event power by calculating the amount
+            // of time the laser is on
+            getEventResult("Laser" + (String) i)->setValue(laser_power * laser_event_time *
+                enable_info.getFrequencyMultiplier() * enable_info.getProbability1());
+        }
+    }
+    
+} // namespace DSENT
+
diff --git a/ext/dsent/model/optical/ThrottledLaserSource.h b/ext/dsent/model/optical/ThrottledLaserSource.h
new file mode 100644 (file)
index 0000000..1174654
--- /dev/null
@@ -0,0 +1,40 @@
+#ifndef __DSENT_MODEL_OPTICAL_THROTTLEDLASERSOURCE_H__
+#define __DSENT_MODEL_OPTICAL_THROTTLEDLASERSOURCE_H__
+
+#include "util/CommonType.h"
+#include "model/OpticalModel.h"
+
+namespace DSENT
+{
+    class OpticalWavelength;
+
+    // A laser source that outputs some number of wavelengths. This laser
+    // full on/off power gating, thus all power are event-based energies
+    class ThrottledLaserSource : public OpticalModel
+    {
+        public:
+            ThrottledLaserSource(const String& instance_name_, const TechModel* tech_model_);
+            virtual ~ThrottledLaserSource();
+
+        public:
+            // Set a list of properties' name needed to construct model
+            void initParameters();
+            // Set a list of properties' name needed to construct model
+            void initProperties();
+
+        protected:
+            // Build the model
+            void constructModel();
+            void updateModel();
+            void evaluateModel();
+            void useModel();
+            
+        private:
+            // Data structure containing the wavelengths that this laser outputs
+            OpticalWavelength* m_wavelength_;
+            
+    }; // class ThrottledLaserSource
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_OPTICAL_THROTTLEDLASERSOURCE_H__
+
diff --git a/ext/dsent/model/optical_graph/OpticalDetector.cc b/ext/dsent/model/optical_graph/OpticalDetector.cc
new file mode 100644 (file)
index 0000000..8de0050
--- /dev/null
@@ -0,0 +1,32 @@
+
+#include "model/optical_graph/OpticalDetector.h"
+#include "model/optical_graph/OpticalReceiver.h"
+
+namespace DSENT
+{
+    OpticalDetector::OpticalDetector(const String& instance_name_, OpticalModel* model_, const WavelengthGroup& wavelengths_, OpticalReceiver* receiver_)
+        : OpticalNode(OpticalNode::DETECTOR, instance_name_, model_, wavelengths_), m_receiver_(receiver_), m_responsivity_(0)
+    {
+        m_sensitivity_ = 0.0;
+    }
+
+    OpticalDetector::~OpticalDetector()
+    {
+
+    }
+    
+    void OpticalDetector::setResponsivity(double responsivity_)
+    {
+        m_responsivity_ = responsivity_;
+        return;
+    }
+    
+    double OpticalDetector::getSensitivity(double ER_dB_) const
+    {
+        // Get responsivity (in Amps) of the receiver, divide by responsivity to get sensitivity in Watts
+        return m_receiver_->getSensitivity(ER_dB_) / m_responsivity_;
+    }
+                
+} // namespace DSENT
+
+
diff --git a/ext/dsent/model/optical_graph/OpticalDetector.h b/ext/dsent/model/optical_graph/OpticalDetector.h
new file mode 100644 (file)
index 0000000..e3994f1
--- /dev/null
@@ -0,0 +1,45 @@
+#ifndef __DSENT_MODEL_OPTICALGRAPH_OPTICALDETECTOR_H__
+#define __DSENT_MODEL_OPTICALGRAPH_OPTICALDETECTOR_H__
+
+#include "model/optical_graph/OpticalNode.h"
+#include "util/CommonType.h"
+
+namespace DSENT
+{
+    class OpticalReceiver;
+
+    class OpticalDetector : public OpticalNode
+    {
+        public:
+            OpticalDetector(const String& instance_name_, OpticalModel* model_, const WavelengthGroup& wavelengths_, OpticalReceiver* receiver_);
+            ~OpticalDetector();
+
+        public:
+            // Set the responsitivity of the photodetector
+            void setResponsivity(double responsivity_);
+            
+            // Get the detector sensitivity given an extinction ratio (in Watts)
+            double getSensitivity(double ER_dB_) const;
+            
+            // Ask the receiver for its power (ONLY use for power optimization, as this
+            // assumes an activity of 1.0)
+            double getPower() const;
+        
+        private:
+            // Disable copy constructor
+            OpticalDetector(const OpticalDetector& node_);            
+        
+        private:
+            // The required laser power
+            double m_sensitivity_;
+            // The receiver connected to this detector
+            OpticalReceiver* m_receiver_;
+            // Responsivity of the photodetector
+            double m_responsivity_;
+        
+    };
+    
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_OPTICALGRAPH_OPTICALDETECTOR_H__
+
diff --git a/ext/dsent/model/optical_graph/OpticalFilter.cc b/ext/dsent/model/optical_graph/OpticalFilter.cc
new file mode 100644 (file)
index 0000000..1bac9a8
--- /dev/null
@@ -0,0 +1,65 @@
+
+#include "model/optical_graph/OpticalFilter.h"
+
+namespace DSENT
+{
+    OpticalFilter::OpticalFilter(const String& instance_name_, OpticalModel* model_, const WavelengthGroup& wavelengths_, bool drop_all_, const WavelengthGroup& drop_wavelengths_)
+        : OpticalNode(OpticalNode::FILTER, instance_name_, model_, wavelengths_), m_drop_all_(drop_all_), m_drop_wavelengths_(drop_wavelengths_)
+    {
+        m_drop_loss_ = 0.0;
+        m_drop_port_ = NULL;
+    }
+
+    OpticalFilter::~OpticalFilter()
+    {
+
+    }
+    
+    bool OpticalFilter::getDropAll() const
+    {
+        return m_drop_all_;
+    }
+
+    WavelengthGroup OpticalFilter::getDropWavelengths() const
+    {
+        return m_drop_wavelengths_;
+    }
+
+    void OpticalFilter::setDropLoss(double drop_loss_)
+    {
+        m_drop_loss_ = drop_loss_;
+        return;
+    }
+    
+    double OpticalFilter::getDropLoss() const
+    {
+        return m_drop_loss_;
+    }
+
+    void OpticalFilter::setDropPort(OpticalNode* drop_port_)
+    {
+        m_drop_port_ = drop_port_;
+    }
+    
+    OpticalNode* OpticalFilter::getDropPort()
+    {
+        return m_drop_port_;
+    }
+    
+    bool OpticalFilter::isDropped(const WavelengthGroup& wavelengths_) const
+    {
+        // Check that the lower limits are within bounds
+        bool lower_match = (wavelengths_.first >= getDropWavelengths().first);
+        // Check that the upper limits are within bounds
+        bool upper_match = (wavelengths_.second <= getDropWavelengths().second);
+        // Assert that there are no misalignments
+        ASSERT(lower_match == upper_match, "[Error] " + getInstanceName() +
+            " -> Wavelength group misalignment!" + 
+            " InWavelength" + toString(wavelengths_) + 
+            ", DropWavelength" + toString(getDropWavelengths()));
+        // Both upper and lower bounds must match
+        return (upper_match && lower_match);
+    }
+} // namespace DSENT
+
+
diff --git a/ext/dsent/model/optical_graph/OpticalFilter.h b/ext/dsent/model/optical_graph/OpticalFilter.h
new file mode 100644 (file)
index 0000000..e908618
--- /dev/null
@@ -0,0 +1,48 @@
+#ifndef __DSENT_MODEL_OPTICALGRAPH_OPTICALFILTER_H__
+#define __DSENT_MODEL_OPTICALGRAPH_OPTICALFILTER_H__
+
+#include "model/optical_graph/OpticalNode.h"
+#include "util/CommonType.h"
+
+namespace DSENT
+{
+    class OpticalFilter : public OpticalNode
+    {
+        public:
+            OpticalFilter(const String& instance_name_, OpticalModel* model_, const WavelengthGroup& wavelengths_, bool drop_all_, const WavelengthGroup& drop_wavelengths_);
+            ~OpticalFilter();
+
+        public:
+            // Get the drop all flag
+            bool getDropAll() const;
+            // Get drop wavelengths
+            WavelengthGroup getDropWavelengths() const;
+            // Set and get the drop loss
+            void setDropLoss(double drop_loss_);
+            double getDropLoss() const;
+            // Set and get drop port
+            void setDropPort(OpticalNode* drop_port_);
+            OpticalNode* getDropPort();
+            // Checks to see if a set of wavelengths will be dropped
+            bool isDropped(const WavelengthGroup& wavelengths_) const;
+            
+        private:
+            // Disable copy constructor
+            OpticalFilter(const OpticalFilter& node_);
+
+        private:
+            // Whether to drop all the optical signal for the drop wavelengths
+            // i.e. so that the drop wavelengths are not traced anymore
+            const bool m_drop_all_;
+            // The loss incurred from in to drop port
+            double m_drop_loss_;
+            // The wavelengths that are dropped
+            const WavelengthGroup m_drop_wavelengths_;
+            // The node at the drop port
+            OpticalNode* m_drop_port_;
+    };
+    
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_OPTICALGRAPH_OPTICALFILTER_H__
+
diff --git a/ext/dsent/model/optical_graph/OpticalGraph.cc b/ext/dsent/model/optical_graph/OpticalGraph.cc
new file mode 100644 (file)
index 0000000..424f2bc
--- /dev/null
@@ -0,0 +1,216 @@
+
+#include "model/optical_graph/OpticalGraph.h"
+
+#include "model/OpticalModel.h"
+#include "model/optical_graph/OpticalNode.h"
+#include "model/optical_graph/OpticalLaser.h"
+#include "model/optical_graph/OpticalModulator.h"
+#include "model/optical_graph/OpticalFilter.h"
+#include "model/optical_graph/OpticalDetector.h"
+#include "model/optical_graph/OpticalWavelength.h"
+
+namespace DSENT
+{
+    // Initialize the next visited number to be one above the initial number
+    // used by OpticalNode
+    int OpticalGraph::msTreeNum = OpticalNode::OPTICAL_NODE_INIT_VISITED_NUM + 1;
+
+    OpticalGraph::OpticalGraph(const String& instance_name_, OpticalModel* model_)
+        : m_instance_name_(instance_name_), m_model_(model_)
+    {
+
+    }
+
+    OpticalGraph::~OpticalGraph()
+    {
+
+    }
+
+    const String& OpticalGraph::getInstanceName() const
+    {
+        return m_instance_name_;
+    }
+        
+    //-------------------------------------------------------------------------
+    // Perform Datapath power optimization
+    //-------------------------------------------------------------------------
+    bool OpticalGraph::performPowerOpt(OpticalNode* node_, const WavelengthGroup& wavelengths_, unsigned int number_detectors_, double util_)
+    {
+        // Total number of iterations
+        unsigned int number_iterations = 1250;
+        // Maximum IL + ER
+        double IL_ER_max = 10;  
+        // Figure out the step size used in the sweep
+        double step = (double) (IL_ER_max / sqrt(2 * number_iterations));
+
+        // Assume it is possible
+        bool possible = true;
+
+        // Begin optical data path power optimization
+        Log::printLine(getInstanceName() + " -> Beginning optical data path power optimization");
+        
+        // Trace the specified wavelengths
+        OpticalWavelength* wavelength = traceWavelength(wavelengths_, node_);                
+
+        // For each data path found in the wavelength
+        const vector<OpticalDataPath>* data_paths = wavelength->getDataPaths();
+        for (unsigned int i = 0; i < data_paths->size(); ++i)
+        {
+            const OpticalDataPath& data_path = data_paths->at(i);
+            // Default to worst possible modulator
+            double best_power = 1e99;
+            double best_IL = IL_ER_max - step;
+            double best_ER = step;
+            
+            // Perform power optimization for this data path
+            Log::printLine(getInstanceName() + " -> Optimize data path - Laser = " + data_path.laser->getInstanceName()
+                + ", Modulator = " + data_path.modulator->getInstanceName());
+
+            if (data_path.modulator->canOptimizeLoss())
+            {
+                // Iterate over IL and ER to find optimal set of IL and ER
+                for (double IL = step; IL < IL_ER_max; IL += step)
+                {
+                    for (double ER = step; ER <= (IL_ER_max - IL); ER += step)
+                    {
+                        // Ask the modulator to try this new ER and IL
+                        bool success = data_path.modulator->setModulatorSpec(IL, ER);
+                        // If the modulator was successful
+                        if (success)
+                        {
+                            double laser_power = wavelength->getLaserPower(number_detectors_);
+                            double modulator_power = data_path.modulator->getPower(util_);                         
+                            double total_power = laser_power + modulator_power;
+                            // If this is the new lowest power point
+                            if (total_power < best_power)
+                            {    
+                                best_power = total_power;
+                                best_IL = IL;
+                                best_ER = ER;                                                          
+                            }
+                        }
+                    }
+                }
+
+                // Set IL and ER to the best ones we found
+                bool success = data_path.modulator->setModulatorSpec(best_IL, best_ER);
+                // If the best one we found was still not possible...
+                possible = possible && success;
+                
+                // Print best IL and ER
+                Log::printLine(getInstanceName() + " -> Best IL=" + (String) best_IL + ", Best ER=" + (String) best_ER + 
+                    ", Best Laser/Mod Power=" + (String) best_power);
+            }
+            else
+            {
+                // Perform power optimization for this data path
+                Log::printLine(getInstanceName() + " -> Data path not set to allow optimization");                
+            }
+        }
+
+        // End optical data path power optimization
+        Log::printLine(getInstanceName() + " -> End optical data path power optimization");
+
+        delete wavelength;
+        return possible;
+    }
+
+
+    //-------------------------------------------------------------------------
+    // Trace wavelength(s), returning a wavelength data structure
+    //-------------------------------------------------------------------------
+    OpticalWavelength* OpticalGraph::traceWavelength(const WavelengthGroup& wavelengths_, OpticalNode* node_)
+    {
+        setTreeNum(getTreeNum() + 1);
+        OpticalWavelength* wavelength = new OpticalWavelength("TraceWavelength", wavelengths_); 
+        return traceWavelength(wavelength, node_, NULL, NULL, 0.0);
+    }
+
+    OpticalWavelength* OpticalGraph::traceWavelength(OpticalWavelength* wavelength_, OpticalNode* node_, OpticalLaser* laser_, OpticalModulator* modulator_, double loss_)
+    {        
+        // If the node has already been visited, don't do anything!
+        if (node_->getVisitedNum() != getTreeNum())
+        {
+            // Set the new parity for this node
+            node_->setVisitedNum(getTreeNum());
+            
+            // Calculate the loss of the current path
+            double current_loss = loss_ + node_->getLoss();
+            // Check if the current node is a laser, modulator or detector
+            if(node_->getType() == OpticalNode::LASER)
+            {
+                // Set the laser lighting up the wavelength
+                ASSERT(laser_ == NULL, "[Error] " + getInstanceName() + " -> Multiple " +
+                    "Lasers lighting up the wavelength!");
+                laser_ = (OpticalLaser*) node_;
+            }
+            else if (node_->getType() == OpticalNode::MODULATOR)
+            {
+                // Check that the path already lit up by a laser and there are no
+                // modulators already driving data
+                ASSERT(laser_ != NULL, "[Error] " + getInstanceName() + " -> Wavelength reaches a " +
+                    "modulator (" + node_->getInstanceName() + ") prior to being lit up by a laser!");
+                ASSERT(modulator_ == NULL, "[Error] " + getInstanceName() + " -> Two modulators are driving" +
+                    " the same optical data path (" + node_->getInstanceName() + ")!");
+                modulator_ = (OpticalModulator*) node_;
+            }
+            else if (node_->getType() == OpticalNode::DETECTOR)
+            {
+                // Check that the path is both lit up by a laser and there is
+                // a modulator driving data
+                ASSERT(laser_ != NULL, "[Error] " + getInstanceName() + " -> Wavelength reaches a " +
+                    "detector (" + node_->getInstanceName() + ") prior to being lit up by a laser!");
+                ASSERT(modulator_ != NULL, "[Error] " + getInstanceName() + " -> Wavelength reaches a " +
+                    "detector (" + node_->getInstanceName() + ") prior to being driven by a modulator!");
+                // Add a detector to the wavelength
+                wavelength_->addDataPath(laser_, modulator_, (OpticalDetector*) node_, current_loss);
+            }
+
+            // Traverse downstream nodes to calculate the delay through each downstream path
+            vector<OpticalNode*>* d_nodes = node_->getDownstreamNodes();
+            bool trace_downstream = (node_->getType() != OpticalNode::DETECTOR);
+            // Do special things when traversing filters
+            if (node_->getType() == OpticalNode::FILTER)
+            {
+                OpticalFilter* filter_node = (OpticalFilter*) node_;
+                if (filter_node->isDropped(wavelength_->getWavelengths()))
+                    traceWavelength(wavelength_, filter_node->getDropPort(), laser_, modulator_, loss_ + filter_node->getDropLoss());
+
+                // If the filter is not modeled as a complete drop, continue tracing downstream
+                trace_downstream = !filter_node->getDropAll();
+            }
+            
+            if (trace_downstream)
+            {
+                // Trace downstream nodes
+                for (unsigned int i = 0; i < d_nodes->size(); ++i)
+                    traceWavelength(wavelength_, d_nodes->at(i), laser_, modulator_, current_loss);
+            }
+        }
+        return wavelength_;
+    }
+
+    //-------------------------------------------------------------------------
+    OpticalGraph::OpticalGraph(const OpticalGraph& /* graph_ */)
+    {
+        // Disabled
+    }
+    
+    OpticalModel* OpticalGraph::getModel()
+    {
+        return m_model_;
+    }
+
+    void OpticalGraph::setTreeNum(int tree_num_)
+    {
+        msTreeNum = tree_num_;
+        return;
+    }
+
+    int OpticalGraph::getTreeNum()
+    {
+        return msTreeNum;
+    }
+    
+} // namespace DSENT
+
diff --git a/ext/dsent/model/optical_graph/OpticalGraph.h b/ext/dsent/model/optical_graph/OpticalGraph.h
new file mode 100644 (file)
index 0000000..43dab1b
--- /dev/null
@@ -0,0 +1,62 @@
+#ifndef __DSENT_MODEL_OPTICALGRAPH_OPTICALGRAPH_H__
+#define __DSENT_MODEL_OPTICALGRAPH_OPTICALGRAPH_H__
+
+#include <vector>
+
+#include "util/CommonType.h"
+#include "model/optical_graph/OpticalNode.h"
+
+namespace DSENT
+{
+    class OpticalNode;
+    class OpticalWavelength;
+            
+    class OpticalGraph
+    {    
+        public:
+            // The visited number for the next timing run. This needs to be
+            // global because several timing trees may be created to evaluate
+            // a single timing path, causing problems
+            static int msTreeNum;
+        
+        public:
+            // Construct timing tree that watches over model_
+            OpticalGraph(const String& instance_name_, OpticalModel* model_);
+            ~OpticalGraph();
+            
+        public:
+            // Get graph name
+            const String& getInstanceName() const;
+            // Perform datapath power optimization by balancing insertion loss and extinction
+            // ratio with modulator/receiver and laser power, returns false if there are no
+            // designs that are possible
+            bool performPowerOpt(OpticalNode* node_, const WavelengthGroup& wavelengths_, unsigned int number_detectors_, double util_);
+            // Recursively trace a wavelength starting from an OpticalLaser
+            // source finding all lasers, modulators and detectors that a
+            // wavelength group hits.
+            OpticalWavelength* traceWavelength(const WavelengthGroup& wavelengths_, OpticalNode* node_);
+            OpticalWavelength* traceWavelength(OpticalWavelength* wavelength_, OpticalNode* node_, OpticalLaser* laser_, OpticalModulator* modulator_, double loss_);
+            // Return the model
+            OpticalModel* getModel();
+
+        private:
+
+            // Disable the use of copy constructor
+            OpticalGraph(const OpticalGraph& graph_);
+        
+        public:
+            // Set the sequence number of the optical graph
+            static void setTreeNum(int tree_num_);
+            static int getTreeNum();
+            
+        private:
+            // Name of the optical graph
+            const String m_instance_name_;
+            // A pointer to the model that contains this node
+            OpticalModel* m_model_;
+
+    }; // class OpticalGraph
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_OPTICALGRAPH_OPTICALGRAPH_H__
+
diff --git a/ext/dsent/model/optical_graph/OpticalLaser.cc b/ext/dsent/model/optical_graph/OpticalLaser.cc
new file mode 100644 (file)
index 0000000..8b25f90
--- /dev/null
@@ -0,0 +1,31 @@
+
+#include "model/optical_graph/OpticalLaser.h"
+
+namespace DSENT
+{
+    OpticalLaser::OpticalLaser(const String& instance_name_, OpticalModel* model_, const WavelengthGroup& wavelengths_)
+        : OpticalNode(OpticalNode::LASER, instance_name_, model_, wavelengths_), m_efficiency_(0)
+    {
+        
+    }
+
+    void OpticalLaser::setEfficiency(double efficiency_)
+    {
+        m_efficiency_ = efficiency_;
+        return;
+    }
+    
+    double OpticalLaser::getEfficiency() const
+    {
+        return m_efficiency_;
+    }
+    
+    OpticalLaser::~OpticalLaser()
+    {
+
+    }
+
+            
+} // namespace DSENT
+
+
diff --git a/ext/dsent/model/optical_graph/OpticalLaser.h b/ext/dsent/model/optical_graph/OpticalLaser.h
new file mode 100644 (file)
index 0000000..911517e
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef __DSENT_MODEL_OPTICALGRAPH_OPTICALLASER_H__
+#define __DSENT_MODEL_OPTICALGRAPH_OPTICALLASER_H__
+
+#include "model/optical_graph/OpticalNode.h"
+#include "util/CommonType.h"
+
+namespace DSENT
+{
+    class OpticalLaser : public OpticalNode
+    {
+        public:
+            OpticalLaser(const String& instance_name_, OpticalModel* model_, const WavelengthGroup& wavelengths_);
+            ~OpticalLaser();
+
+        public:
+            void setEfficiency(double efficiency_);
+            double getEfficiency() const;
+        
+        private:
+            // Disable copy constructor
+            OpticalLaser(const OpticalLaser& node_);            
+        
+        private:
+            // Laser efficiency
+            double m_efficiency_;
+        
+    };
+    
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_OPTICALGRAPH_OPTICALLASER_H__
+
diff --git a/ext/dsent/model/optical_graph/OpticalModulator.cc b/ext/dsent/model/optical_graph/OpticalModulator.cc
new file mode 100644 (file)
index 0000000..6625603
--- /dev/null
@@ -0,0 +1,54 @@
+
+#include "model/optical_graph/OpticalModulator.h"
+#include "model/optical_graph/OpticalTransmitter.h"
+
+namespace DSENT
+{
+    OpticalModulator::OpticalModulator(const String& instance_name_, OpticalModel* model_, const WavelengthGroup& wavelengths_, bool opt_loss_, OpticalTransmitter* transmitter_)
+        : OpticalNode(OpticalNode::MODULATOR, instance_name_, model_, wavelengths_), m_transmitter_(transmitter_), m_insertion_loss_(0), m_extinction_ratio_(0), m_opt_loss_(opt_loss_)
+    {
+
+    }
+
+    OpticalModulator::~OpticalModulator()
+    {
+
+    }
+
+    bool OpticalModulator::canOptimizeLoss() const
+    {
+        return m_opt_loss_;
+    }
+    
+    void OpticalModulator::setLosses(double IL_dB_, double ER_dB_)
+    {
+        m_insertion_loss_ = IL_dB_;
+        m_extinction_ratio_ = ER_dB_;
+        
+        return;
+    }
+
+    bool OpticalModulator::setModulatorSpec(double IL_dB_, double ER_dB_)
+    {
+        // Ask the transmitter to design to those specs, returns success or fail
+        return m_transmitter_->setTransmitterSpec(IL_dB_, ER_dB_);
+    }
+    
+    double OpticalModulator::getPower(double util_) const
+    {
+        return m_transmitter_->getPower(util_);
+    }
+        
+    double OpticalModulator::getInsertionLoss() const
+    {
+        return m_insertion_loss_;
+    }
+
+    double OpticalModulator::getExtinctionRatio() const
+    {
+        return m_extinction_ratio_;
+    }
+            
+} // namespace DSENT
+
+
diff --git a/ext/dsent/model/optical_graph/OpticalModulator.h b/ext/dsent/model/optical_graph/OpticalModulator.h
new file mode 100644 (file)
index 0000000..416c2a0
--- /dev/null
@@ -0,0 +1,51 @@
+#ifndef __DSENT_MODEL_OPTICALGRAPH_OPTICALMODULATOR_H__
+#define __DSENT_MODEL_OPTICALGRAPH_OPTICALMODULATOR_H__
+
+#include "model/optical_graph/OpticalNode.h"
+#include "util/CommonType.h"
+
+namespace DSENT
+{
+    class OpticalTransmitter;
+    
+    class OpticalModulator : public OpticalNode
+    {
+        public:
+            OpticalModulator(const String& instance_name_, OpticalModel* model_, const WavelengthGroup& wavelengths_, bool opt_loss_, OpticalTransmitter* transmitter_);
+            ~OpticalModulator();
+
+        public:
+            // Set losses
+            void setLosses(double IL_dB_, double ER_dB_);        
+            // Tell the modulator to set a new insertion loss and extinction ratio
+            bool setModulatorSpec(double IL_dB_, double ER_dB_);
+            // Get modulator insertion loss
+            double getInsertionLoss() const;
+            // Get modulator extinction ratio
+            double getExtinctionRatio() const;
+            // Ask whether the model is able to optimize for insertion loss
+            // and extinction ratios
+            bool canOptimizeLoss() const;
+            // Ask the modulator for its power at a given utilization
+            double getPower(double util_) const;
+        
+        private:
+            // Disable copy constructor
+            OpticalModulator(const OpticalModulator& node_);
+        
+        private:
+            // Optical sender of the modulator
+            OpticalTransmitter* m_transmitter_;
+            // Insertion loss of the modulator
+            double m_insertion_loss_;
+            // Extinction ratio of the modulator
+            double m_extinction_ratio_;
+            // Whether the modulator can be optimized
+            bool m_opt_loss_;
+        
+    };
+    
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_OPTICALGRAPH_OPTICALMODULATOR_H__
+
diff --git a/ext/dsent/model/optical_graph/OpticalNode.cc b/ext/dsent/model/optical_graph/OpticalNode.cc
new file mode 100644 (file)
index 0000000..89e034b
--- /dev/null
@@ -0,0 +1,96 @@
+
+#include "model/optical_graph/OpticalNode.h"
+
+namespace DSENT
+{
+    // Set the optical node initial visited num
+    const int OpticalNode::OPTICAL_NODE_INIT_VISITED_NUM = 0;
+
+    OpticalNode::OpticalNode(Type type_, const String& instance_name_, OpticalModel* model_, const WavelengthGroup& wavelengths_)
+        :m_type_(type_), m_instance_name_(instance_name_), m_model_(model_), m_wavelengths_(wavelengths_)
+    {
+        m_loss_ = 0.0;
+        setVisitedNum(OpticalNode::OPTICAL_NODE_INIT_VISITED_NUM);
+        m_downstream_nodes_ = new vector<OpticalNode*>;
+    }
+
+    OpticalNode::~OpticalNode()
+    {
+
+    }
+    
+    OpticalNode::Type OpticalNode::getType() const
+    {
+        return m_type_;
+    }
+    
+    vector<OpticalNode*>* OpticalNode::getDownstreamNodes() const
+    {
+        return m_downstream_nodes_;
+    }
+
+    const String& OpticalNode::getInstanceName() const
+    {
+        return m_instance_name_;
+    }
+    
+    OpticalModel* OpticalNode::getModel()
+    {
+        return m_model_;
+    }
+    
+    const OpticalModel* OpticalNode::getModel() const
+    {
+        return (const OpticalModel*) m_model_;
+    }
+
+    void OpticalNode::addDownstreamNode(OpticalNode* node_)
+    {
+        ASSERT(node_->isExpected(getWavelengths()), "[Error] " + getInstanceName() +
+            " -> Downstream node not expecting a superset of the current wavelengths");
+        m_downstream_nodes_->push_back(node_);
+    }    
+    
+    WavelengthGroup OpticalNode::getWavelengths() const
+    {
+        return m_wavelengths_;
+    }
+
+    bool OpticalNode::isExpected(const WavelengthGroup& wavelengths_) const
+    {
+        // Check that the lower limits are within bounds
+        bool lower_match = (wavelengths_.first >= getWavelengths().first);
+        // Check that the upper limits are within bounds
+        bool upper_match = (wavelengths_.second <= getWavelengths().second);
+        // Assert that there are no misalignments
+        ASSERT(lower_match == upper_match, "[Error] " + getInstanceName() +
+            " -> Wavelength group misalignment!");
+        // Both upper and lower bounds must match
+        return (upper_match && lower_match);
+    }    
+
+    //-------------------------------------------------------------------------
+    void OpticalNode::setLoss(double loss_)
+    {
+        m_loss_ = loss_;
+    }
+    
+    double OpticalNode::getLoss() const
+    {
+        return m_loss_;
+    }
+
+    void OpticalNode::setVisitedNum(int visited_num_)
+    {
+        m_visited_num_ = visited_num_;
+    }
+    
+    int OpticalNode::getVisitedNum() const
+    {
+        return m_visited_num_;
+    }
+    //-------------------------------------------------------------------------
+        
+} // namespace DSENT
+
+
diff --git a/ext/dsent/model/optical_graph/OpticalNode.h b/ext/dsent/model/optical_graph/OpticalNode.h
new file mode 100644 (file)
index 0000000..bb88d2d
--- /dev/null
@@ -0,0 +1,92 @@
+#ifndef __DSENT_MODEL_OPTICALGRAPH_OPTICALNODE_H__
+#define __DSENT_MODEL_OPTICALGRAPH_OPTICALNODE_H__
+
+#include "model/OpticalModel.h"
+#include "util/CommonType.h"
+
+namespace DSENT
+{
+    class OpticalNode;
+
+    //TODO: Change to detector
+    typedef std::pair<OpticalNode*, double> DetectorEntry;
+    typedef std::vector<DetectorEntry> DetectorTable;
+
+    class OpticalNode
+    {
+        public:
+            // The starting visited number flag of all optical nodes
+            static const int OPTICAL_NODE_INIT_VISITED_NUM;
+            
+            // The types of optical nodes that can exist
+            enum Type
+            {
+                WAVEGUIDE,
+                LASER,
+                MODULATOR,
+                FILTER,
+                DETECTOR
+            };
+    
+        public:
+            OpticalNode(Type type_, const String& instance_name_, OpticalModel* model_, const WavelengthGroup& wavelengths_);
+            ~OpticalNode();
+
+        public:
+            // Get the type of optical node            
+            Type getType() const;
+            // Return instance name
+            const String& getInstanceName() const;
+            // Get the downstream optical nodes
+            vector<OpticalNode*>* getDownstreamNodes() const;
+            // Connect the downstream optical node
+            void addDownstreamNode(OpticalNode* node_);
+            // Return the node's parent model
+            OpticalModel* getModel();
+            const OpticalModel* getModel() const;                                    
+            // Get wavelength groups
+            WavelengthGroup getWavelengths() const;
+            // Returns whether the node is expecting a set of wavelengths
+            bool isExpected(const WavelengthGroup& wavelengths_) const;
+            
+            // Trace wavelengths, find and put all found lasers, modulators, and detectors
+            //virtual void traceWavelengths(const WavelengthGroup& wavelengths_, OpticalNode* laser_,
+            //    OpticalNode* modulator_, DetectorTable* detectors_, double current_loss_) const;
+            
+            //-----------------------------------------------------------------
+            // Node variables for wavelength tracing
+            //-----------------------------------------------------------------
+            // Loss incurred at this optical node
+            void setLoss(double loss_);
+            double getLoss() const;
+            // Visited number marker
+            void setVisitedNum(int visited_num_);
+            int getVisitedNum() const;
+            //-----------------------------------------------------------------
+
+        
+        private:
+            // Disable copy constructor
+            OpticalNode(const OpticalNode& node_);
+
+        private:
+            // The type of optical node
+            const Type m_type_;
+            // Name of this instance
+            String m_instance_name_;
+            // A pointer to the model that contains this node
+            OpticalModel* m_model_;
+            // Downstream optical node
+            vector<OpticalNode*>* m_downstream_nodes_;
+            // Path visited count (so that you don't have to clear it)
+            int m_visited_num_;
+            // The amount of loss incurred at this optical node
+            double m_loss_;
+            // The wavelengths this optical node is supposed to see
+            const WavelengthGroup m_wavelengths_;
+    };
+    
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_OPTICALGRAPH_OPTICALNODE_H__
+
diff --git a/ext/dsent/model/optical_graph/OpticalReceiver.h b/ext/dsent/model/optical_graph/OpticalReceiver.h
new file mode 100644 (file)
index 0000000..11c9405
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef __DSENT_MODEL_OPTICALGRAPH_OPTICALRECEIVER_H__
+#define __DSENT_MODEL_OPTICALGRAPH_OPTICALRECEIVER_H__
+
+#include "model/OpticalModel.h"
+#include "util/CommonType.h"
+
+namespace DSENT
+{
+    // The job of an optical receiver interface is to provide a function to
+    // return a sensitivity (in Amps)
+    class OpticalReceiver
+    {
+        public:
+            OpticalReceiver(){};
+            virtual ~OpticalReceiver(){};
+
+        public:
+            // Returns the sensitivity of the receiver given an extinction ratio
+            virtual double getSensitivity(double ER_dB_) const = 0;
+    };
+    
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_OPTICALGRAPH_OPTICALRECEIVER_H__
+
diff --git a/ext/dsent/model/optical_graph/OpticalTransmitter.h b/ext/dsent/model/optical_graph/OpticalTransmitter.h
new file mode 100644 (file)
index 0000000..235d888
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef __DSENT_MODEL_OPTICALGRAPH_OPTICALTRANSMITTER_H__
+#define __DSENT_MODEL_OPTICALGRAPH_OPTICALTRANSMITTER_H__
+
+#include "model/OpticalModel.h"
+#include "util/CommonType.h"
+
+namespace DSENT
+{
+    // The job of a optical sender interface is to provide a function to
+    // allow the insertion loss and extinction ratio to be changed
+    class OpticalTransmitter
+    {
+        public:
+            OpticalTransmitter(){};
+            virtual ~OpticalTransmitter(){};
+
+        public:
+            // Set the transmitter specifications, returns whether it is possible
+            // to build a modulator that met those specs
+            virtual bool setTransmitterSpec(double IL_dB_, double ER_dB_) = 0;
+            // Returns power of the transmitter at a given utilization
+            virtual double getPower(double util_) const = 0;
+    }; // class OpticalTransmitter
+    
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_OPTICALGRAPH_OPTICALTRANSMITTER_H__
+
diff --git a/ext/dsent/model/optical_graph/OpticalWaveguide.cc b/ext/dsent/model/optical_graph/OpticalWaveguide.cc
new file mode 100644 (file)
index 0000000..7e35a18
--- /dev/null
@@ -0,0 +1,20 @@
+
+#include "model/optical_graph/OpticalWaveguide.h"
+
+namespace DSENT
+{
+    OpticalWaveguide::OpticalWaveguide(const String& instance_name_, OpticalModel* model_, const WavelengthGroup& wavelengths_)
+        : OpticalNode(OpticalNode::WAVEGUIDE, instance_name_, model_, wavelengths_)
+    {
+        
+    }
+
+    OpticalWaveguide::~OpticalWaveguide()
+    {
+
+    }
+
+            
+} // namespace DSENT
+
+
diff --git a/ext/dsent/model/optical_graph/OpticalWaveguide.h b/ext/dsent/model/optical_graph/OpticalWaveguide.h
new file mode 100644 (file)
index 0000000..6fd03bc
--- /dev/null
@@ -0,0 +1,27 @@
+#ifndef __DSENT_MODEL_OPTICALGRAPH_OPTICALWAVEGUIDE_H__
+#define __DSENT_MODEL_OPTICALGRAPH_OPTICALWAVEGUIDE_H__
+
+#include "model/optical_graph/OpticalNode.h"
+#include "util/CommonType.h"
+
+namespace DSENT
+{
+    class OpticalWaveguide : public OpticalNode
+    {
+        public:
+            OpticalWaveguide(const String& instance_name_, OpticalModel* model_, const WavelengthGroup& wavelengths_);
+            ~OpticalWaveguide();
+
+        public:
+            // Nothing here...
+        
+        private:
+            // Disable copy constructor
+            OpticalWaveguide(const OpticalWaveguide& node_);            
+        
+    };
+    
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_OPTICALGRAPH_OPTICALWAVEGUIDE_H__
+
diff --git a/ext/dsent/model/optical_graph/OpticalWavelength.cc b/ext/dsent/model/optical_graph/OpticalWavelength.cc
new file mode 100644 (file)
index 0000000..fa5e36f
--- /dev/null
@@ -0,0 +1,129 @@
+
+#include "model/optical_graph/OpticalWavelength.h"
+#include "model/optical_graph/OpticalNode.h"
+#include "model/optical_graph/OpticalLaser.h"
+#include "model/optical_graph/OpticalModulator.h"
+#include "model/optical_graph/OpticalFilter.h"
+#include "model/optical_graph/OpticalDetector.h"
+#include "model/optical_graph/OpticalWavelength.h"
+#include <list>
+#include <cmath>
+
+namespace DSENT
+{
+    using std::list;
+    using std::min;
+
+    OpticalWavelength::OpticalWavelength(const String& instance_name_, const WavelengthGroup& wavelengths_)
+        : m_instance_name_(instance_name_), m_wavelengths_(wavelengths_)
+    {
+        m_data_paths_ = new vector<OpticalDataPath>;
+    }
+
+    OpticalWavelength::~OpticalWavelength()
+    {
+        delete m_data_paths_;
+    }
+
+    const String& OpticalWavelength::getInstanceName() const
+    {
+        return m_instance_name_;
+    }
+    
+    void OpticalWavelength::addDataPath(OpticalLaser* laser_, OpticalModulator* modulator_, OpticalDetector* detector_, double loss_)
+    {
+        // Expected wavelengths check
+        ASSERT(laser_->isExpected(getWavelengths()), "[Error] " + getInstanceName() +
+            " -> " + laser_->getInstanceName() + " is not expecting the set wavelengths!");        
+        ASSERT(modulator_->isExpected(getWavelengths()), "[Error] " + getInstanceName() +
+            " -> " + modulator_->getInstanceName() + " is not expecting the set wavelengths!");       
+        ASSERT(detector_->isExpected(getWavelengths()), "[Error] " + getInstanceName() +
+            " -> " + detector_->getInstanceName() + " is not expecting the set wavelengths!");       
+        
+        // Check to see if the modulator and laser already have a data path entry
+        bool entry_exists = false;
+        for (unsigned int i = 0; i < m_data_paths_->size(); ++i)
+        {
+            OpticalDataPath& current = m_data_paths_->at(i);
+            bool current_laser = current.laser == laser_;
+            bool current_modulator = current.modulator == modulator_;            
+
+            ASSERT((current_modulator && current_laser) || !current_modulator, "[Error] " +
+                getInstanceName() + " -> Modulator is the same, but laser is different?");
+            
+            // If it is already in the table
+            if (current_modulator)
+            {
+                entry_exists = true;                
+                current.detectors.push_back(detector_);
+                current.losses.push_back(loss_);
+            }
+        }
+        
+        // If it wasn't found, add the entry
+        if (!entry_exists)
+            m_data_paths_->push_back(OpticalDataPath(laser_, modulator_, detector_, loss_));
+        return;
+    }
+    
+    const vector<OpticalDataPath>* OpticalWavelength::getDataPaths() const
+    {
+        return (const vector<OpticalDataPath>*) m_data_paths_;
+    }
+    
+    WavelengthGroup OpticalWavelength::getWavelengths() const
+    {
+        return m_wavelengths_;
+    }
+    
+    double OpticalWavelength::getLaserPower(unsigned int number_detectors_) const
+    {
+        ASSERT(number_detectors_ > 0, "[Error] " + getInstanceName() +
+            " -> Number of detectors must be non-zero!");
+        // Find the number of actual wavelengths
+        int number_wavelengths = getWavelengths().second - getWavelengths().first + 1;
+        // Laser power sum
+        double laser_power_sum = 0;        
+        // Loop through all data paths
+        for (unsigned int i = 0; i < getDataPaths()->size(); ++i)
+        {
+            // Get the current data_path
+            const OpticalDataPath& current_path = getDataPaths()->at(i);        
+            // Create data structure holding the worstcase detectors
+            list<double>* detectors = new list<double>();
+            // Get the extinction ratio of the modulator
+            double ER_dB = current_path.modulator->getExtinctionRatio();
+            // Get the insertion loss of the modulator
+            double IR_dB = current_path.modulator->getInsertionLoss();
+            // Walk through all detectors in a data path
+            for (unsigned int j = 0; j < current_path.detectors.size(); ++j)
+            {
+                // Convert sensitivity, extinction ratio, and path loss to a required laser power
+                double current_laser_power = current_path.detectors[j]->getSensitivity(ER_dB) *
+                    std::pow(10.0, (current_path.losses[j] + IR_dB) / 10.0) * 
+                    1.0 / (1.0 - pow(10, -ER_dB / 10));
+                    
+                // Add the laser power
+                detectors->push_back(current_laser_power);
+            }
+            // Cap the number of detectors
+            number_detectors_ = std::min(number_detectors_, (unsigned int) current_path.detectors.size());        
+            // Sort the detectors list in ascending order, only necessary if the number
+            // of detectors is < total number of detectors
+            if (number_detectors_ < detectors->size())
+                detectors->sort();
+            // Sum up the laser power from the worst-case detectors 
+            list<double>::reverse_iterator iter = detectors->rbegin();
+            for (unsigned int j = 0; j < number_detectors_; ++j)
+            {
+                laser_power_sum += (*iter) / current_path.laser->getEfficiency();
+                ++iter;
+            }                    
+            delete detectors;
+        }
+        return number_wavelengths * laser_power_sum;        
+    }
+            
+} // namespace DSENT
+
+
diff --git a/ext/dsent/model/optical_graph/OpticalWavelength.h b/ext/dsent/model/optical_graph/OpticalWavelength.h
new file mode 100644 (file)
index 0000000..6a5f31e
--- /dev/null
@@ -0,0 +1,57 @@
+#ifndef __DSENT_MODEL_OPTICALGRAPH_OPTICALWAVELENGTH_H__
+#define __DSENT_MODEL_OPTICALGRAPH_OPTICALWAVELENGTH_H__
+
+#include "model/OpticalModel.h"
+#include "util/CommonType.h"
+
+namespace DSENT
+{
+    // Optical datapath structure storing a detector table consisting of a
+    // detector, the loss to that detector, and the modulator driving
+    // the wavelength for that detector
+    struct OpticalDataPath
+    {
+        OpticalLaser* laser;
+        OpticalModulator* modulator;
+        vector<OpticalDetector*> detectors;
+        vector<double> losses;
+        
+        OpticalDataPath(OpticalLaser* laser_, OpticalModulator* modulator_, OpticalDetector* detector_, double loss_)
+            : laser(laser_), modulator(modulator_), detectors(1, detector_), losses(1, loss_) {}
+    };
+
+    class OpticalWavelength
+    {
+        // A data structure of a wavelength (or a group of wavelengths). This
+        // keeps track of all lasers sources, modulators, and detectors that
+        // the wavelength hits.
+        public:
+            OpticalWavelength(const String& instance_name_, const WavelengthGroup& wavelengths_);
+            ~OpticalWavelength();
+
+        public:
+            // Get tree name
+            const String& getInstanceName() const;
+            // Get wavelength groups
+            WavelengthGroup getWavelengths() const;
+            // Add a datapath for this wavelength
+            void addDataPath(OpticalLaser* laser_, OpticalModulator* modulator_, OpticalDetector* detector_, double loss_);
+            const vector<OpticalDataPath>* getDataPaths() const;
+            // Calculate required wavelength power to reach some number of detectors
+            // If number_detectors < the number of total detectors this wavelength hits then
+            // it simply returns the laser power required to reach the worst-case detectors
+            double getLaserPower(unsigned int number_detectors_) const;
+        
+        private:
+            // Name of the wavelength
+            const String m_instance_name_;
+            // Keeps track of the wavelengths
+            const WavelengthGroup m_wavelengths_;
+            // Keeps track of a table of laser, detector, modulator mappings
+            vector<OpticalDataPath>* m_data_paths_;            
+    };
+    
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_OPTICALGRAPH_OPTICALWAVEGUIDE_H__
+
diff --git a/ext/dsent/model/std_cells/ADDF.cc b/ext/dsent/model/std_cells/ADDF.cc
new file mode 100644 (file)
index 0000000..99ebcdb
--- /dev/null
@@ -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 (file)
index 0000000..03bae5d
--- /dev/null
@@ -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 (file)
index 0000000..2113c23
--- /dev/null
@@ -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 (file)
index 0000000..67fe36b
--- /dev/null
@@ -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 (file)
index 0000000..61c7dac
--- /dev/null
@@ -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 (file)
index 0000000..1c85b2a
--- /dev/null
@@ -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 (file)
index 0000000..5b24394
--- /dev/null
@@ -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 (file)
index 0000000..ce4b544
--- /dev/null
@@ -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 (file)
index 0000000..9080a72
--- /dev/null
@@ -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 (file)
index 0000000..699e486
--- /dev/null
@@ -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 (file)
index 0000000..a6ea6c4
--- /dev/null
@@ -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 (file)
index 0000000..d81d207
--- /dev/null
@@ -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 (file)
index 0000000..b2548d0
--- /dev/null
@@ -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 (file)
index 0000000..7dcb26f
--- /dev/null
@@ -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 (file)
index 0000000..73f18f7
--- /dev/null
@@ -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 (file)
index 0000000..63df686
--- /dev/null
@@ -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 (file)
index 0000000..2599f85
--- /dev/null
@@ -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 (file)
index 0000000..75a6436
--- /dev/null
@@ -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 (file)
index 0000000..dd201b9
--- /dev/null
@@ -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 (file)
index 0000000..b437407
--- /dev/null
@@ -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 (file)
index 0000000..1271ad0
--- /dev/null
@@ -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 (file)
index 0000000..8e08131
--- /dev/null
@@ -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 (file)
index 0000000..bc95f97
--- /dev/null
@@ -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 (file)
index 0000000..25a6576
--- /dev/null
@@ -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 (file)
index 0000000..dfe3201
--- /dev/null
@@ -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 (file)
index 0000000..74c0914
--- /dev/null
@@ -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 (file)
index 0000000..5b57b55
--- /dev/null
@@ -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 (file)
index 0000000..95f9a54
--- /dev/null
@@ -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__
+
diff --git a/ext/dsent/model/timing_graph/ElectricalDelay.cc b/ext/dsent/model/timing_graph/ElectricalDelay.cc
new file mode 100644 (file)
index 0000000..e87a77b
--- /dev/null
@@ -0,0 +1,55 @@
+
+#include "model/timing_graph/ElectricalDelay.h"
+#include "model/timing_graph/ElectricalLoad.h"
+
+namespace DSENT
+{
+    //-------------------------------------------------------------------------
+    // Electrical Delay
+    //-------------------------------------------------------------------------
+
+    ElectricalDelay::ElectricalDelay(const String& instance_name_, ElectricalModel* model_)
+        : ElectricalTimingNode(instance_name_, model_), m_delay_(0.0)
+    {
+
+    }
+
+    ElectricalDelay::~ElectricalDelay()
+    {
+
+    }
+
+    void ElectricalDelay::setDelay(double delay_)
+    {
+        m_delay_ = delay_;
+        return;
+    }
+
+    double ElectricalDelay::getDelay() const
+    {
+        return m_delay_;
+    }
+    
+    double ElectricalDelay::calculateDelay() const
+    {
+        return m_delay_;
+    }
+
+    double ElectricalDelay::calculateTransition() const
+    {
+        return 1.386 * getMaxUpstreamRes() * getTotalDownstreamCap();
+    }
+
+    double ElectricalDelay::getMaxUpstreamRes() const
+    {
+        return ElectricalTimingNode::getMaxUpstreamRes();
+    }
+    
+    double ElectricalDelay::getTotalDownstreamCap() const
+    {
+        return ElectricalTimingNode::getTotalDownstreamCap();
+    }
+    
+} // namespace DSENT
+
+
diff --git a/ext/dsent/model/timing_graph/ElectricalDelay.h b/ext/dsent/model/timing_graph/ElectricalDelay.h
new file mode 100644 (file)
index 0000000..d3d3d3a
--- /dev/null
@@ -0,0 +1,43 @@
+#ifndef __DSENT_MODEL_ELECTRICAL_DELAY_H__
+#define __DSENT_MODEL_ELECTRICAL_DELAY_H__
+
+#include "util/CommonType.h"
+#include "model/timing_graph/ElectricalTimingNode.h"
+
+namespace DSENT
+{
+    class ElectricalLoad;
+
+    class ElectricalDelay : public ElectricalTimingNode
+    {
+        public:
+            ElectricalDelay(const String& instance_name_, ElectricalModel* model_);
+            virtual ~ElectricalDelay();
+
+        public:
+            // Specify an ideal delay
+            void setDelay(double delay_);
+            // Get the ideal delay
+            double getDelay() const;
+            // Calculate delay
+            double calculateDelay() const;
+            // Calculate transition
+            double calculateTransition() const;
+            // get maximum of upstream drive resistance
+            double getMaxUpstreamRes() const;
+            // get total amount of downstream load capacitance 
+            double getTotalDownstreamCap() const;
+            
+        private:
+            // Disable copy constructor
+            ElectricalDelay(const ElectricalDelay& net_);
+
+        private:
+            // The amount of ideal delay
+            double m_delay_;
+    };
+    
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_ELECTRICAL_DELAY_H__
+
diff --git a/ext/dsent/model/timing_graph/ElectricalDriver.cc b/ext/dsent/model/timing_graph/ElectricalDriver.cc
new file mode 100644 (file)
index 0000000..9456ef0
--- /dev/null
@@ -0,0 +1,95 @@
+
+#include "model/timing_graph/ElectricalDriver.h"
+#include "model/timing_graph/ElectricalNet.h"
+#include "model/ElectricalModel.h"
+
+namespace DSENT
+{
+    ElectricalDriver::ElectricalDriver(const String& instance_name_, ElectricalModel* model_, bool sizable_)
+        : ElectricalTimingNode(instance_name_, model_), m_output_res_(0.0), m_sizable_(sizable_)
+    {
+
+    }
+
+    ElectricalDriver::~ElectricalDriver()
+    {
+
+    }
+    
+    void ElectricalDriver::setOutputRes(double output_res_)
+    {
+        m_output_res_ = output_res_;
+        return;
+    }
+
+    double ElectricalDriver::getOutputRes() const
+    {        
+        return m_output_res_;
+    }
+
+    double ElectricalDriver::calculateDelay() const
+    {
+        return 0.693 * m_output_res_ * getTotalDownstreamCap();
+    }    
+
+    double ElectricalDriver::calculateTransition() const
+    {
+        return 1.386 * getMaxUpstreamRes() * getTotalDownstreamCap();
+    }
+
+    double ElectricalDriver::getMaxUpstreamRes() const
+    {
+        return m_output_res_;
+    }
+
+    bool ElectricalDriver::isSizable() const
+    {
+        return m_sizable_;
+    }
+    
+    bool ElectricalDriver::hasMaxDrivingStrength() const
+    {
+        if (!isSizable())
+        {
+            return true;
+        }
+        return (getModel() == NULL) || (getModel()->hasMaxDrivingStrength());
+    }
+
+    bool ElectricalDriver::hasMinDrivingStrength() const
+    {
+        if (!isSizable())
+        {
+            return true;
+        }
+        return (getModel() == NULL) || (getModel()->hasMinDrivingStrength());
+    }
+    
+    void ElectricalDriver::increaseDrivingStrength()
+    {
+        ASSERT(isSizable(), "[Error] " + getInstanceName() + 
+            " -> Attempted to size up unsizable driver!");
+        if(!hasMaxDrivingStrength())
+        {
+            getModel()->increaseDrivingStrength();
+        }
+        return;
+    }
+
+    void ElectricalDriver::decreaseDrivingStrength()
+    {
+        ASSERT(isSizable(), "[Error] " + getInstanceName() + 
+            " -> Attempted to size down unsizable driver!");
+        if(!hasMinDrivingStrength())
+        {
+            getModel()->decreaseDrivingStrength();
+        }
+        return;
+    }
+    
+    bool ElectricalDriver::isDriver() const
+    {
+        return true;
+    }    
+} // namespace DSENT
+
diff --git a/ext/dsent/model/timing_graph/ElectricalDriver.h b/ext/dsent/model/timing_graph/ElectricalDriver.h
new file mode 100644 (file)
index 0000000..604206b
--- /dev/null
@@ -0,0 +1,57 @@
+#ifndef __DSENT_MODEL_ELECTRICAL_DRIVER_H__
+#define __DSENT_MODEL_ELECTRICAL_DRIVER_H__
+
+#include "util/CommonType.h"
+#include "model/timing_graph/ElectricalTimingNode.h"
+
+namespace DSENT
+{
+    class ElectricalModel;
+
+    class ElectricalDriver : public ElectricalTimingNode
+    {
+        public:
+            ElectricalDriver(const String& instance_name_, ElectricalModel* model_, bool sizable_);
+            virtual ~ElectricalDriver();
+
+        public:
+            // Set the output resistance of this driver
+            void setOutputRes(double output_res_);            
+            // Get the output resistance of this driver
+            double getOutputRes() const;
+            // Calculate delay due to total load capacitance
+            double calculateDelay() const;
+            // Calculate transition
+            double calculateTransition() const;
+            // get maximum of upstream drive resistance
+            double getMaxUpstreamRes() const;
+            
+            // Get whether the driver is sizable
+            bool isSizable() const;
+            // Return true if the instance has minimum driving strength
+            bool hasMinDrivingStrength() const;
+            // Return true if the instance has maximum driving strength
+            bool hasMaxDrivingStrength() const;
+            // Increase driving strength index by 1
+            void increaseDrivingStrength();
+            // Decrease driving strength index by 1
+            void decreaseDrivingStrength();
+                        
+            bool isDriver() const;                        
+                        
+        private:
+            // Disable copy constructor
+            ElectricalDriver(const ElectricalDriver& port_);
+
+        private:
+            // Name of this instance
+            String m_instance_name_;
+            // Output resistance
+            double m_output_res_;
+            // Sizable flag
+            bool m_sizable_;
+    };
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_ELECTRICAL_DRIVER_H__
+
diff --git a/ext/dsent/model/timing_graph/ElectricalDriverMultiplier.cc b/ext/dsent/model/timing_graph/ElectricalDriverMultiplier.cc
new file mode 100644 (file)
index 0000000..bf8600f
--- /dev/null
@@ -0,0 +1,53 @@
+
+#include "model/timing_graph/ElectricalDriverMultiplier.h"
+#include "model/timing_graph/ElectricalLoad.h"
+
+namespace DSENT
+{
+    //-------------------------------------------------------------------------
+    // Electrical Net
+    //-------------------------------------------------------------------------
+
+    ElectricalDriverMultiplier::ElectricalDriverMultiplier(const String& instance_name_, ElectricalModel* model_)
+        : ElectricalTimingNode(instance_name_, model_)
+    {
+
+    }
+
+    ElectricalDriverMultiplier::~ElectricalDriverMultiplier()
+    {
+
+    }
+
+    double ElectricalDriverMultiplier::calculateDriveRes( double input_drive_res_) const
+    {
+        return input_drive_res_;
+    }
+
+    double ElectricalDriverMultiplier::calculateDelay() const
+    {
+        // This is just a model helper element, it does not contribute delay
+        return 0;
+    }
+
+    double ElectricalDriverMultiplier::calculateTransition() const
+    {
+        return getMaxUpstreamRes() * getTotalDownstreamCap();
+    }
+    
+    double ElectricalDriverMultiplier::getTotalDownstreamCap() const
+    {
+        // Finds the max of the load caps (as opposed to summing)
+        double max_cap = 0;
+        vector<ElectricalTimingNode*>* downstream_nodes = ElectricalTimingNode::getDownstreamNodes();
+        for (unsigned int i = 0; i < downstream_nodes->size(); ++i)
+        {
+            max_cap = std::max(max_cap, downstream_nodes->at(i)->getTotalDownstreamCap());
+        }
+        
+        return max_cap;
+    }    
+    
+} // namespace DSENT
+
+
diff --git a/ext/dsent/model/timing_graph/ElectricalDriverMultiplier.h b/ext/dsent/model/timing_graph/ElectricalDriverMultiplier.h
new file mode 100644 (file)
index 0000000..62b1456
--- /dev/null
@@ -0,0 +1,42 @@
+#ifndef __DSENT_MODEL_ELECTRICAL_DRIVER_MULTIPLIER_H__
+#define __DSENT_MODEL_ELECTRICAL_DRIVER_MULTIPLIER_H__
+
+#include "util/CommonType.h"
+#include "model/timing_graph/ElectricalTimingNode.h"
+
+namespace DSENT
+{
+    // Simple class that can be used to mimic the presence of multiple drivers
+    // output drivers (each driving one of the downstream loads) when only one
+    // such driver has been instantiated (such as models that take advantage of
+    // bit duplicattion). When the downsream loads differ in load cap, it
+    // just returns the largest of the caps
+    class ElectricalDriverMultiplier : public ElectricalTimingNode
+    {
+        public:
+            ElectricalDriverMultiplier(const String& instance_name_, ElectricalModel* model_);
+            virtual ~ElectricalDriverMultiplier();
+
+        public:
+            // Calculate drive resistance of this node;
+            double calculateDriveRes(double input_drive_res_) const;
+            // Calculate wiring delay (or net delay)
+            double calculateDelay() const;
+            // Calculate transition
+            double calculateTransition() const;
+            // get total amount of downstream load capacitance 
+            double getTotalDownstreamCap() const;
+            
+        private:
+            // Disable copy constructor
+            ElectricalDriverMultiplier(const ElectricalDriverMultiplier& net_);
+
+        private:
+            // Name of this instance
+            String m_instance_name_;
+    };
+    
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_ELECTRICAL_DRIVER_MULTIPLIER_H__
+
diff --git a/ext/dsent/model/timing_graph/ElectricalLoad.cc b/ext/dsent/model/timing_graph/ElectricalLoad.cc
new file mode 100644 (file)
index 0000000..a20d645
--- /dev/null
@@ -0,0 +1,49 @@
+
+#include "model/timing_graph/ElectricalLoad.h"
+#include "model/ElectricalModel.h"
+#include "model/timing_graph/ElectricalDriver.h"
+
+namespace DSENT
+{
+    ElectricalLoad::ElectricalLoad(const String& instance_name_, ElectricalModel* model_)
+        : ElectricalTimingNode(instance_name_, model_), m_load_cap_(0.0)
+    {
+    }
+
+    ElectricalLoad::~ElectricalLoad()
+    {
+    }
+
+    void ElectricalLoad::setLoadCap(double load_cap_)
+    {
+        m_load_cap_ = load_cap_;
+        return;
+    }
+    
+    double ElectricalLoad::getLoadCap() const
+    {
+        return m_load_cap_;
+    }
+    
+    bool ElectricalLoad::isLoad() const
+    {
+        return true;
+    }    
+    
+    double ElectricalLoad::calculateDelay() const
+    {
+        return 0;
+    }
+
+    double ElectricalLoad::calculateTransition() const
+    {
+        return 1.386 * getMaxUpstreamRes() * getTotalDownstreamCap();
+    }
+
+    double ElectricalLoad::getTotalDownstreamCap() const
+    {
+        return m_load_cap_;
+    }
+
+} // namespace DSENT
+
diff --git a/ext/dsent/model/timing_graph/ElectricalLoad.h b/ext/dsent/model/timing_graph/ElectricalLoad.h
new file mode 100644 (file)
index 0000000..551eccf
--- /dev/null
@@ -0,0 +1,43 @@
+#ifndef __DSENT_MODEL_ELECTRICAL_LOAD_H__
+#define __DSENT_MODEL_ELECTRICAL_LOAD_H__
+
+#include "util/CommonType.h"
+#include "model/timing_graph/ElectricalTimingNode.h"
+
+namespace DSENT
+{
+    class ElectricalModel;
+    class ElectricalDriver;
+    
+    class ElectricalLoad : public ElectricalTimingNode
+    {
+        public:
+            ElectricalLoad(const String& instance_name_, ElectricalModel* model_);
+            virtual ~ElectricalLoad();
+
+        public:
+            // Set the input capacitance of this input port
+            void setLoadCap(double load_cap_);
+            // Get the load capacitance
+            double getLoadCap() const;
+            // Get total load capacitance
+            double getTotalDownstreamCap() const;
+            // Calculate delay due to total load capacitance
+            double calculateDelay() const;
+            // Calculate transition
+            double calculateTransition() const;
+
+            bool isLoad() const;
+            
+        private:
+            // Disable copy constructor
+            ElectricalLoad(const ElectricalLoad& load_);
+
+        private:
+            // Load capacitance
+            double m_load_cap_;
+    };
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_ELECTRICAL_LOAD_H__
+
diff --git a/ext/dsent/model/timing_graph/ElectricalNet.cc b/ext/dsent/model/timing_graph/ElectricalNet.cc
new file mode 100644 (file)
index 0000000..09baa77
--- /dev/null
@@ -0,0 +1,73 @@
+
+#include "model/timing_graph/ElectricalNet.h"
+#include "model/timing_graph/ElectricalLoad.h"
+
+namespace DSENT
+{
+    //-------------------------------------------------------------------------
+    // Electrical Net
+    //-------------------------------------------------------------------------
+
+    ElectricalNet::ElectricalNet(const String& instance_name_, ElectricalModel* model_)
+        : ElectricalTimingNode(instance_name_, model_), m_distributed_res_(0), m_distributed_cap_(0)
+    {
+
+    }
+
+    ElectricalNet::~ElectricalNet()
+    {
+
+    }
+
+    double ElectricalNet::calculateDelay() const
+    {
+        // Remember that this is a pi model, delay is distributed cap * distributed_res / 2 +
+        // distributed res * (other downstream caps)
+        return 0.693 * (getTotalDownstreamCap() - m_distributed_cap_ / 2) * m_distributed_res_;
+    }
+
+    double ElectricalNet::calculateTransition() const
+    {
+        return 1.386 * getMaxUpstreamRes() * (m_distributed_cap_ * 0.2 + ElectricalTimingNode::getTotalDownstreamCap());
+    }
+
+    double ElectricalNet::getMaxUpstreamRes() const
+    {
+        return m_distributed_res_ + ElectricalTimingNode::getMaxUpstreamRes();
+    }
+    
+    double ElectricalNet::getTotalDownstreamCap() const
+    {
+        return m_distributed_cap_ + ElectricalTimingNode::getTotalDownstreamCap();
+    }
+    
+    void ElectricalNet::setDistributedCap(double distributed_cap_)
+    {
+        m_distributed_cap_ = distributed_cap_;
+        return;
+    }
+
+    void ElectricalNet::setDistributedRes(double distributed_res_)
+    {
+        m_distributed_res_ = distributed_res_;
+        return;
+    }
+
+    double ElectricalNet::getDistributedCap() const
+    {
+        return m_distributed_cap_;
+    }
+
+    double ElectricalNet::getDistributedRes() const
+    {
+        return m_distributed_res_;
+    }
+    
+    bool ElectricalNet::isNet() const
+    {
+        return true;
+    }    
+    
+} // namespace DSENT
+
+
diff --git a/ext/dsent/model/timing_graph/ElectricalNet.h b/ext/dsent/model/timing_graph/ElectricalNet.h
new file mode 100644 (file)
index 0000000..b96bfea
--- /dev/null
@@ -0,0 +1,50 @@
+#ifndef __DSENT_MODEL_ELECTRICAL_NET_H__
+#define __DSENT_MODEL_ELECTRICAL_NET_H__
+
+#include "util/CommonType.h"
+#include "model/timing_graph/ElectricalTimingNode.h"
+
+namespace DSENT
+{
+    class ElectricalLoad;
+
+    class ElectricalNet : public ElectricalTimingNode
+    {
+        public:
+            ElectricalNet(const String& instance_name_, ElectricalModel* model_);
+            virtual ~ElectricalNet();
+
+        public:
+            // Set distributed res/cap
+            void setDistributedRes(double distributed_res_);
+            void setDistributedCap(double distributed_cap_);
+            // Get distributed res/cap
+            double getDistributedRes() const;
+            double getDistributedCap() const;
+            // Calculate wiring delay (or net delay)
+            double calculateDelay() const;
+            // Calculate transition
+            double calculateTransition() const;
+            // get maximum of upstream drive resistance
+            double getMaxUpstreamRes() const;
+            // get total amount of downstream load capacitance 
+            double getTotalDownstreamCap() const;
+
+            virtual bool isNet() const;
+            
+        private:
+            // Disable copy constructor
+            ElectricalNet(const ElectricalNet& net_);
+
+        private:
+            // Name of this instance
+            String m_instance_name_;
+            // Distributed capacitance and resistance of the net
+            double m_distributed_res_;            
+            double m_distributed_cap_;
+    };
+    
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_ELECTRICAL_NET_H__
+
diff --git a/ext/dsent/model/timing_graph/ElectricalTimingNode.cc b/ext/dsent/model/timing_graph/ElectricalTimingNode.cc
new file mode 100644 (file)
index 0000000..d8b2bfd
--- /dev/null
@@ -0,0 +1,174 @@
+
+#include "model/timing_graph/ElectricalTimingNode.h"
+#include "model/timing_graph/ElectricalLoad.h"
+
+namespace DSENT
+{
+    // Set the optical node initial visited num
+    const int ElectricalTimingNode::TIMING_NODE_INIT_VISITED_NUM = 0;
+
+    ElectricalTimingNode::ElectricalTimingNode(const String& instance_name_, ElectricalModel* model_)
+        : m_instance_name_(instance_name_), m_model_(model_), m_false_path_(false), m_crit_path_(-1),
+        m_visited_num_(ElectricalTimingNode::TIMING_NODE_INIT_VISITED_NUM), m_delay_left_(0.0)
+    {
+        m_upstream_nodes_ = new vector<ElectricalTimingNode*>();
+        m_downstream_nodes_ = new vector<ElectricalTimingNode*>();
+    }
+
+    ElectricalTimingNode::~ElectricalTimingNode()
+    {
+        delete m_upstream_nodes_;
+        delete m_downstream_nodes_;
+    }
+
+    double ElectricalTimingNode::getMaxUpstreamRes() const
+    {
+        double max_res = 0.0;
+
+        for(unsigned int i = 0; i < m_upstream_nodes_->size(); ++i)
+        {
+            double res = m_upstream_nodes_->at(i)->getMaxUpstreamRes();
+            if(max_res < res)
+            {
+                max_res = res;
+            }
+        }
+        return max_res;
+    }
+    
+    double ElectricalTimingNode::getTotalDownstreamCap() const
+    {
+        double cap_sum = 0;
+        
+        for(unsigned int i = 0; i < m_downstream_nodes_->size(); ++i)
+        {
+            cap_sum += m_downstream_nodes_->at(i)->getTotalDownstreamCap();
+        }
+        
+        return cap_sum;    
+    }
+
+    vector<ElectricalTimingNode*>* ElectricalTimingNode::getUpstreamNodes() const
+    {
+        return m_upstream_nodes_;
+    }
+    
+    vector<ElectricalTimingNode*>* ElectricalTimingNode::getDownstreamNodes() const
+    {
+        return m_downstream_nodes_;
+    }
+
+    const String& ElectricalTimingNode::getInstanceName() const
+    {
+        return m_instance_name_;
+    }
+    
+    ElectricalModel* ElectricalTimingNode::getModel()
+    {
+        return m_model_;
+    }
+    
+    bool ElectricalTimingNode::isDriver() const
+    {
+        return false;
+    }
+
+    bool ElectricalTimingNode::isNet() const
+    {
+        return false;
+    }
+
+    bool ElectricalTimingNode::isLoad() const
+    {
+        return false;
+    }
+    
+
+    const ElectricalModel* ElectricalTimingNode::getModel() const
+    {
+        return (const ElectricalModel*) m_model_;
+    }
+
+    void ElectricalTimingNode::addDownstreamNode(ElectricalTimingNode* node_)
+    {
+        m_downstream_nodes_->push_back(node_);
+        node_->m_upstream_nodes_->push_back(this);
+        return;
+    }
+    
+    void ElectricalTimingNode::setFalsePath(bool false_path_)
+    {
+        m_false_path_ = false_path_;
+        return;
+    }
+    
+    bool ElectricalTimingNode::getFalsePath() const
+    {
+        return m_false_path_;
+    }
+
+
+    //-------------------------------------------------------------------------
+    // Functions for delay optimization
+    //-------------------------------------------------------------------------
+    // By default, electrical timing nodes cannot be sized up/down
+    bool ElectricalTimingNode::hasMaxDrivingStrength() const
+    {
+        return true;
+    }
+
+    bool ElectricalTimingNode::hasMinDrivingStrength() const
+    {
+        return true;
+    }
+    
+    void ElectricalTimingNode::increaseDrivingStrength()
+    {
+        return;
+    }
+
+    void ElectricalTimingNode::decreaseDrivingStrength()
+    {
+        return;
+    }
+    //-------------------------------------------------------------------------
+    
+    //-------------------------------------------------------------------------
+    // Node variables for critical path delay calculations
+    //-------------------------------------------------------------------------
+    void ElectricalTimingNode::setCritPath(int crit_path_)
+    {
+        m_crit_path_ = crit_path_;
+        return;
+    }
+    
+    int ElectricalTimingNode::getCritPath() const
+    {
+        return m_crit_path_;
+    }
+
+    void ElectricalTimingNode::setVisitedNum(int visited_num_)
+    {
+        m_visited_num_ = visited_num_;
+        return;
+    }
+    
+    int ElectricalTimingNode::getVisitedNum() const
+    {
+        return m_visited_num_;
+    }
+    
+    void ElectricalTimingNode::setDelayLeft(double delay_left_)
+    {
+        m_delay_left_ = delay_left_;
+    }
+    
+    double ElectricalTimingNode::getDelayLeft() const
+    {
+        return m_delay_left_;
+    }    
+    //-------------------------------------------------------------------------
+        
+} // namespace DSENT
+
+
diff --git a/ext/dsent/model/timing_graph/ElectricalTimingNode.h b/ext/dsent/model/timing_graph/ElectricalTimingNode.h
new file mode 100644 (file)
index 0000000..01c6497
--- /dev/null
@@ -0,0 +1,104 @@
+#ifndef __DSENT_MODEL_ELECTRICAL_TIMING_NODE_H__
+#define __DSENT_MODEL_ELECTRICAL_TIMING_NODE_H__
+
+#include "util/CommonType.h"
+
+namespace DSENT
+{
+    class ElectricalModel;
+    
+    class ElectricalTimingNode
+    {
+        public:
+            // The starting visited number flag of all timing nodes
+            static const int TIMING_NODE_INIT_VISITED_NUM;
+
+        public:
+            ElectricalTimingNode(const String& instance_name_, ElectricalModel* model_);
+            virtual ~ElectricalTimingNode();
+
+        public:
+
+            // Calculate the delay this node contributes
+            virtual double calculateDelay() const = 0;
+            // Calculate the transition at this node 
+            virtual double calculateTransition() const = 0;
+            // get maximum of upstream drive resistance
+            virtual double getMaxUpstreamRes() const;
+            // get total amount of downstream load capacitance 
+            virtual double getTotalDownstreamCap() const;
+            // Return instance name
+            const String& getInstanceName() const;            
+            // get upstream timing nodes
+            vector<ElectricalTimingNode*>* getUpstreamNodes() const;
+            // get downstream timing nodes
+            vector<ElectricalTimingNode*>* getDownstreamNodes() const;
+            // Connect a downstream timing node
+            void addDownstreamNode(ElectricalTimingNode* node_);
+            // Return the node's parent model
+            ElectricalModel* getModel();
+            const ElectricalModel* getModel() const;
+            // Set/get false path marker
+            void setFalsePath(bool false_path_);
+            bool getFalsePath() const;
+            
+            virtual bool isDriver() const;
+            virtual bool isNet() const;
+            virtual bool isLoad() const;
+            
+            
+            //-----------------------------------------------------------------
+            // Functions for delay optimization
+            //-----------------------------------------------------------------
+            // Return true if the instance has minimum driving strength
+            virtual bool hasMinDrivingStrength() const;
+            // Return true if the instance has maximum driving strength
+            virtual bool hasMaxDrivingStrength() const;
+            // Increase driving strength index by 1
+            virtual void increaseDrivingStrength();
+            // Decrease driving strength index by 1
+            virtual void decreaseDrivingStrength();
+            //-----------------------------------------------------------------
+
+            //-----------------------------------------------------------------
+            // Node variables for critical path delay calculations
+            //-----------------------------------------------------------------
+            // Critical path marker
+            void setCritPath(int crit_path_);
+            int getCritPath() const; 
+            // Visited parity marker
+            void setVisitedNum(int visited_parity_);
+            int getVisitedNum() const;
+            // Delay left in this path
+            void setDelayLeft(double delay_left_);
+            double getDelayLeft() const;
+            //-----------------------------------------------------------------
+
+        
+        private:
+            // Disable copy constructor
+            ElectricalTimingNode(const ElectricalTimingNode& node_);
+
+        private:
+            // Name of this instance
+            String m_instance_name_;
+            // A pointer to the model that contains this node
+            ElectricalModel* m_model_;
+            // Upstream electrical nets
+            vector<ElectricalTimingNode*>* m_upstream_nodes_;
+            // Downstream electrical nets
+            vector<ElectricalTimingNode*>* m_downstream_nodes_;
+            // False path marker
+            bool m_false_path_;
+            // Critical path index (to next downstream node)
+            int m_crit_path_;
+            // Odd / even path visited (so that you don't have to clear it)
+            int m_visited_num_;
+            // The amount of delay left to the end of the timing path
+            double m_delay_left_;
+    };
+    
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_ELECTRICAL_TIMING_NODE_H__
+
diff --git a/ext/dsent/model/timing_graph/ElectricalTimingOptimizer.cc b/ext/dsent/model/timing_graph/ElectricalTimingOptimizer.cc
new file mode 100644 (file)
index 0000000..dd7b433
--- /dev/null
@@ -0,0 +1,73 @@
+#include "model/timing_graph/ElectricalTimingOptimizer.h"
+
+#include "model/PortInfo.h"
+#include "model/ModelGen.h"
+#include "model/std_cells/StdCell.h"
+#include "model/std_cells/StdCellLib.h"
+#include "model/timing_graph/ElectricalNet.h"
+#include "model/timing_graph/ElectricalTimingTree.h"
+
+namespace DSENT
+{
+    ElectricalTimingOptimizer::ElectricalTimingOptimizer(const String& instance_name_, const TechModel* tech_model_)
+        : ElectricalModel(instance_name_, tech_model_), m_model_(NULL)
+    {}
+
+    ElectricalTimingOptimizer::~ElectricalTimingOptimizer()
+    {}
+
+    void ElectricalTimingOptimizer::setModel(ElectricalModel* model_)
+    {
+        m_model_ = model_;
+        return;
+    }
+
+    ElectricalModel* ElectricalTimingOptimizer::getModel()
+    {
+        return m_model_;
+    }
+
+    void ElectricalTimingOptimizer::constructModel()
+    {
+        if(getModel() == NULL)
+        {
+            return;
+        }
+
+        const Map<PortInfo*>* port_info = getModel()->getInputs();
+        Map<PortInfo*>::ConstIterator it_begin = port_info->begin();
+        Map<PortInfo*>::ConstIterator it_end = port_info->end();
+        Map<PortInfo*>::ConstIterator it;
+
+        for(it = it_begin; it != it_end; ++it)
+        {
+            const String& port_name = it->first;
+            const PortInfo* port_info = it->second;
+            StdCell* inv0 = getTechModel()->getStdCellLib()->createStdCell("INV", port_name + "Driver0");
+            inv0->construct();
+            StdCell* inv1 = getTechModel()->getStdCellLib()->createStdCell("INV", port_name + "Driver1");
+            inv1->construct();
+
+            addSubInstances(inv0, 1.0);
+            addSubInstances(inv1, 1.0);
+
+            createInputPort(port_name, port_info->getNetIndex());
+            createNet(port_name + "Driver0In");
+            createNet(port_name + "Driver0Out");
+            createNet(port_name + "Driver1Out");
+            assignVirtualFanin(port_name + "Driver0In", port_name);
+            portConnect(inv0, "A", port_name + "Driver0In");
+            portConnect(inv0, "Y", port_name + "Driver0Out");
+            portConnect(inv1, "A", port_name + "Driver0Out");
+            portConnect(inv1, "Y", port_name + "Driver1Out");
+
+            createNet(port_name + "In", port_info->getNetIndex());
+            assignVirtualFanout(port_name + "In", port_name + "Driver1Out");
+
+            portConnect(getModel(), port_name, port_name + "In");
+        }
+
+        return;
+    }
+}// namespace DSENT
+
diff --git a/ext/dsent/model/timing_graph/ElectricalTimingOptimizer.h b/ext/dsent/model/timing_graph/ElectricalTimingOptimizer.h
new file mode 100644 (file)
index 0000000..c0c850e
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef __DSENT_MODEL_TIMING_GRAPH_ELECTRICAL_TIMING_OPTIMIZER_H__
+#define __DSENT_MODEL_TIMING_GRAPH_ELECTRICAL_TIMING_OPTIMIZER_H__
+
+#include "util/CommonType.h"
+#include "model/ElectricalModel.h"
+
+namespace DSENT
+{
+    // This model is only used to optimize the timing
+    class ElectricalTimingOptimizer : public ElectricalModel
+    {
+        public:
+            ElectricalTimingOptimizer(const String& instance_name_, const TechModel* tech_model_);
+            virtual ~ElectricalTimingOptimizer();
+
+        public:
+            void setModel(ElectricalModel* model_);
+            ElectricalModel* getModel();
+
+        protected:
+            // Build the optimizer
+            virtual void constructModel();
+
+        private:
+            ElectricalModel* m_model_;
+    }; // class ElectricalTimingOptimizer
+} // namespace
+
+#endif // __DSENT_MODEL_TIMING_GRAPH_ELECTRICAL_TIMING_OPTIMIZER_H__
+
diff --git a/ext/dsent/model/timing_graph/ElectricalTimingTree.cc b/ext/dsent/model/timing_graph/ElectricalTimingTree.cc
new file mode 100644 (file)
index 0000000..83d583c
--- /dev/null
@@ -0,0 +1,247 @@
+
+#include "model/timing_graph/ElectricalTimingTree.h"
+
+#include "model/ElectricalModel.h"
+#include "model/timing_graph/ElectricalTimingNode.h"
+#include "model/timing_graph/ElectricalDriver.h"
+#include "model/timing_graph/ElectricalNet.h"
+
+namespace DSENT
+{
+    // Initialize the next visited number to be one above the initial number
+    // used by ElectricalTimingNode
+    int ElectricalTimingTree::msTreeNum = ElectricalTimingNode::TIMING_NODE_INIT_VISITED_NUM + 1;
+
+    ElectricalTimingTree::ElectricalTimingTree(const String& instance_name_, ElectricalModel* model_)
+        : m_instance_name_(instance_name_), m_model_(model_)
+    {
+        //setTreeNum(1);
+    }
+
+    ElectricalTimingTree::~ElectricalTimingTree()
+    {
+
+    }
+
+    const String& ElectricalTimingTree::getInstanceName() const
+    {
+        return m_instance_name_;
+    }
+        
+    bool ElectricalTimingTree::performTimingOpt(ElectricalTimingNode* node_, double required_delay_)
+    {
+        // Extract the critical path from all timing paths branching out from the starting node
+        double delay = performCritPathExtract(node_);
+        double min_delay = delay;
+                
+        unsigned int iteration = 0;
+        unsigned int crit_path_iteration = 0;
+        unsigned int max_iterations = 8000;                     //TODO: make this not hard-coded
+        unsigned int max_iterations_single_crit_path = 400;     //TODO: make this not hard-coded
+
+        Log::printLine(getInstanceName() + " -> Beginning Incremental Timing Optimization");
+        
+        // Size up the nodes if timing is not met
+        while(required_delay_ < delay)
+        {
+            Log::printLine(getInstanceName() + " -> Timing Optimization Iteration " + (String) iteration + 
+                    ": Required delay = " + (String) required_delay_ + ", Delay = " +
+                    (String) delay + ", Slack = " + (String) (required_delay_ - delay));
+
+            ElectricalTimingNode* node_for_timing_opt = NULL;
+            // Go into the less expensive critical path delay calculation
+            // While the timing is not met for this critical path
+            while (required_delay_ < delay)
+            {
+                // Find the node to optimize timing for, it would return a node to size up
+                node_for_timing_opt = findNodeForTimingOpt(node_);
+                // Give up if there are no appropriate nodes to size up or 
+                // max number of iterations has been reached
+                // Size up the chosen node if there is an appropriate node to size up
+                if(node_for_timing_opt == NULL || iteration > max_iterations || crit_path_iteration > max_iterations_single_crit_path)
+                    break;
+                else
+                    node_for_timing_opt->increaseDrivingStrength();
+
+                // Re-evaluate the delay of the critical path
+                delay = calculateCritPathDelay(node_);
+                iteration++;
+                crit_path_iteration++;
+                Log::printLine(getInstanceName() + " -> Critical Path Slack: " + (String) (required_delay_ - delay));
+            }            
+            // Give up if there are no appropriate nodes to size up or
+            // max number of iterations has been reached
+            if (node_for_timing_opt == NULL || iteration > max_iterations || crit_path_iteration > max_iterations_single_crit_path)
+                break;
+                
+            crit_path_iteration = 0;
+            // Once the critical path timing is met, extract a new critical path from
+            // all timing paths branching out from the starting node
+            delay = performCritPathExtract(node_);
+            min_delay = (min_delay > delay) ? delay : min_delay;
+        }
+        Log::printLine(getInstanceName() + " -> Timing Optimization Ended after Iteration: " + (String) iteration + 
+                ": Required delay = " + (String) required_delay_ + ", Delay = " +
+                (String) delay + ", Slack = " + (String) (required_delay_ - delay));            
+                
+        min_delay = (min_delay > delay) ? delay : min_delay;
+        
+        // Check if the timing meets the required delay
+        if(required_delay_ < delay)
+        {
+            // Timing not met. Return false and print out a warning message
+            const String& warning_msg = "[Warning] " + getInstanceName() + " -> Timing not met: Required delay = " + 
+                (String) required_delay_ + ", Minimum Delay = " + (String) min_delay + ", Slack = " +
+                (String) (required_delay_ - delay);
+            Log::printLine(std::cerr, warning_msg);
+            return false;
+        }
+        return true;
+    }
+    //-------------------------------------------------------------------------
+    // Extract Crit Path Delay (and marks the crit path)
+    //-------------------------------------------------------------------------
+    double ElectricalTimingTree::performCritPathExtract(ElectricalTimingNode* node_)
+    {
+        setTreeNum(getTreeNum() + 1);
+        return extractCritPathDelay(node_);
+    }
+
+    double ElectricalTimingTree::extractCritPathDelay(ElectricalTimingNode* node_)
+    {
+        //TODO: Replace with a stack data structure instead of recursion to prevent
+        //stack overflow problems with long chains of logic (4000+ nodes) and/or better
+        //performance. Nvm, stack data structure version seems to run much slower
+
+        // If the node has already been visited, return the delay!
+        if (node_->getVisitedNum() == getTreeNum())
+            return node_->getDelayLeft();        
+        // If the node has been marked as a false path, return 0.0
+        else if (node_->getFalsePath())
+            return 0.0;
+
+        // Set the new parity for this node
+        node_->setVisitedNum(getTreeNum());
+        node_->setDelayLeft(0.0);
+
+        double max_delay = 0;
+        double current_delay = 0;
+
+        // Traverse downstream nodes to calculate the delay through each downstream path
+        vector<ElectricalTimingNode*>* d_nodes = node_->getDownstreamNodes();        
+        for (unsigned int i = 0; i < d_nodes->size(); ++i)
+        {
+            current_delay = extractCritPathDelay(d_nodes->at(i));
+            // Update the critical path
+            if (current_delay > max_delay)
+            {
+                node_->setCritPath(i);
+                max_delay = current_delay;
+            }
+        }        
+        // Calculate the delay left from this node
+        double delay_left = node_->calculateDelay() + max_delay;
+        node_->setDelayLeft(delay_left);
+
+        return delay_left;
+
+    }
+
+    double ElectricalTimingTree::calculateCritPathDelay(ElectricalTimingNode* node_) const
+    {
+        // Simplest case where theres nothing to optimize
+        if (node_ == NULL)
+            return 0.0;
+
+        double delay = 0.0;
+        int crit_path = 0;
+
+        // Traverse the critical path and sum up delays
+        while (crit_path >= 0)
+        {
+            delay += node_->calculateDelay();
+            //Move on to the next node in the critical path
+            crit_path = node_->getCritPath();
+            if (crit_path >= 0)
+                node_ = node_->getDownstreamNodes()->at(crit_path);
+        }
+        return delay;
+    }
+    //-------------------------------------------------------------------------
+
+    //-------------------------------------------------------------------------
+    // Find Worst Slew Helpers
+    //-------------------------------------------------------------------------
+    ElectricalTimingNode* ElectricalTimingTree::findNodeForTimingOpt(ElectricalTimingNode* node_) const
+    {
+        // Simplest case where theres nothing to optimize
+        if (node_ == NULL)
+            return NULL;
+
+        double max_transition_ratio = -10.0;
+        double current_transition_ratio = 0.0;
+        double previous_transition = 1e3 * node_->getTotalDownstreamCap();
+        double current_transition = 0.0;
+        ElectricalTimingNode* worst = NULL;        
+        int crit_path = 0;
+
+        // Find the node with the highest max_transition_ratio to return
+        while (crit_path >= 0)
+        {
+            current_transition = node_->calculateDelay();
+
+            //If the node is not yet at max size, it is a potential choice for size up
+            if (!node_->hasMaxDrivingStrength())
+            {            
+                current_transition_ratio = current_transition / previous_transition;                
+
+                if (current_transition_ratio > max_transition_ratio)
+                {
+                    worst = node_;
+                    max_transition_ratio = current_transition_ratio;
+                }
+            }
+
+            if (node_->isDriver())
+                previous_transition = 0.0;            
+            previous_transition += current_transition;
+
+            //Move on to the next node in the critical path
+            crit_path = node_->getCritPath();
+
+            if (crit_path >= 0)
+                node_ = node_->getDownstreamNodes()->at(crit_path);
+        }
+
+        return worst;
+    }
+    //-------------------------------------------------------------------------
+
+    double ElectricalTimingTree::calculateNodeTransition(ElectricalTimingNode* node_) const
+    {
+        return node_->calculateTransition();
+    }
+
+    ElectricalTimingTree::ElectricalTimingTree(const ElectricalTimingTree& /* graph_ */)
+    {
+        // Disabled
+    }
+
+    ElectricalModel* ElectricalTimingTree::getModel()
+    {
+        return m_model_;
+    }
+
+    void ElectricalTimingTree::setTreeNum(int tree_num_)
+    {
+        msTreeNum = tree_num_;
+        return;
+    }
+
+    int ElectricalTimingTree::getTreeNum()
+    {
+        return msTreeNum;
+    }
+
+} // namespace DSENT
+
diff --git a/ext/dsent/model/timing_graph/ElectricalTimingTree.h b/ext/dsent/model/timing_graph/ElectricalTimingTree.h
new file mode 100644 (file)
index 0000000..4dfbff8
--- /dev/null
@@ -0,0 +1,73 @@
+#ifndef __DSENT_MODEL_ELECTRICAL_TIMING_TREE_H__
+#define __DSENT_MODEL_ELECTRICAL_TIMING_TREE_H__
+
+#include <vector>
+
+#include "util/CommonType.h"
+#include "model/timing_graph/ElectricalTimingNode.h"
+
+namespace DSENT
+{
+    using std::vector;
+    
+    class ElectricalDriver;
+
+    class ElectricalTimingTree
+    {
+        public:
+            // The visited number for the next timing run. This needs to be
+            // global because several timing trees may be created to evaluate
+            // a single timing path, causing problems
+            static int msTreeNum;
+        
+        public:
+            // Construct timing tree that watches over model_
+            ElectricalTimingTree(const String& instance_name_, ElectricalModel* model_);
+            ~ElectricalTimingTree();
+            
+        public:
+            // Get tree name
+            const String& getInstanceName() const;
+
+            // A wrapper for extractCritPathDelay
+            // Update the tree num before do extract critical path delay recursively
+            double performCritPathExtract(ElectricalTimingNode* node_);
+            // Calculate the delay of the marked critical path from a starting node
+            double calculateCritPathDelay(ElectricalTimingNode* node_) const;            
+            // Calculate the transition at a node
+            double calculateNodeTransition(ElectricalTimingNode* node_) const;
+            // Returns the optimal node to optimize timing (by sizing up) in the critical
+            // path to reduce critical path delay
+            ElectricalTimingNode* findNodeForTimingOpt(ElectricalTimingNode* node_) const;
+            // Perform incremental timing optimization to guarantee that all timing paths from a
+            // starting node meets a required delay
+            // Return false if the timing optimization fails to meet the required delay
+            bool performTimingOpt(ElectricalTimingNode* node_, double required_delay_);
+            
+            // Return the model
+            ElectricalModel* getModel();
+
+        private:
+            // Disable the use of copy constructor
+            ElectricalTimingTree(const ElectricalTimingTree& graph_);
+        
+            // Recursively calculate delay from a starting node, finding and marking the 
+            // critical path along the way and returns the delay of the critical path
+            double extractCritPathDelay(ElectricalTimingNode* node_);            
+
+        public:
+            // Set the sequence number of the timing tree
+            static void setTreeNum(int tree_num_);
+            static int getTreeNum();
+            
+        private:
+            // Name of the timing tree
+            const String m_instance_name_;
+            // A pointer to the model that contains this node
+            ElectricalModel* m_model_;
+
+    }; // class ElectricalTimingTree
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_ELECTRICAL_TIMING_TREE_H__
+
diff --git a/ext/dsent/tech/TechModel.cc b/ext/dsent/tech/TechModel.cc
new file mode 100644 (file)
index 0000000..5922177
--- /dev/null
@@ -0,0 +1,320 @@
+#include "tech/TechModel.h"
+
+#include <cmath>
+
+#include "model/std_cells/StdCellLib.h"
+
+namespace DSENT
+{
+    TechModel::TechModel()
+        : Config(), m_std_cell_lib_(NULL), m_available_wire_layers_(NULL)
+    {}
+
+    TechModel::~TechModel()
+    {}
+
+    void TechModel::setStdCellLib(const StdCellLib* std_cell_lib_)
+    {
+        m_std_cell_lib_ = std_cell_lib_;
+        return;
+    }
+
+    const StdCellLib* TechModel::getStdCellLib() const
+    {
+        return m_std_cell_lib_;
+    }
+
+    TechModel* TechModel::clone() const
+    {
+        return new TechModel(*this);
+    }
+
+    void TechModel::readFile(const String& filename_)
+    {
+        // Read the main technology file
+        LibUtil::Config::readFile(filename_);
+
+        // Search for "INCLUDE" to include more technology files
+        StringMap::ConstIterator it;
+        for(it = begin(); it != end(); ++it)
+        {
+            const String& key = it->first;
+            if(key.compare(0, 8, "INCLUDE_") == 0)
+            {
+                const String& include_filename = it->second;
+                LibUtil::Config::readFile(include_filename);
+            }
+        }
+
+        // Set the available wire layers
+        const vector<String>& available_wire_layer_vector = get("Wire->AvailableLayers").split("[,]");
+        m_available_wire_layers_ = new std::set<String>;
+        for(unsigned int i = 0; i < available_wire_layer_vector.size(); ++i)
+        {
+            m_available_wire_layers_->insert(available_wire_layer_vector[i]);
+        }
+        return;
+    }
+
+    //-------------------------------------------------------------------------
+    // Transistor Related Functions
+    //-------------------------------------------------------------------------
+    //Returns the leakage current of NMOS transistors, given the transistor stakcing, transistor widths, and input combination
+    double TechModel::calculateNmosLeakageCurrent(unsigned int num_stacks_, double uni_stacked_mos_width_, unsigned int input_vector_) const
+    {
+        vector<double> stacked_mos_widths_(num_stacks_, uni_stacked_mos_width_);
+        return calculateNmosLeakageCurrent(num_stacks_, stacked_mos_widths_, input_vector_);
+    }
+
+    //Returns the leakage current of NMOS transistors, given the transistor stakcing, transistor widths, and input combination
+    double TechModel::calculateNmosLeakageCurrent(unsigned int num_stacks_, const vector<double>& stacked_mos_widths_, unsigned int input_vector_) const
+    {
+        // Get technology parameters
+        double vdd = get("Vdd");
+        double temp = get("Temperature");
+        double char_temp = get("Nmos->CharacterizedTemperature");
+        double min_off_current = get("Nmos->MinOffCurrent");
+        double off_current = get("Nmos->OffCurrent");
+        double subthreshold_swing = get("Nmos->SubthresholdSwing");
+        double dibl = get("Nmos->DIBL");
+        double temp_swing = get("Nmos->SubthresholdTempSwing");
+
+        // Map dibl to a swing value for easier calculation
+        double dibl_swing = subthreshold_swing / dibl;
+        
+        //Calculate the leakage current factor
+        double leakage_current_factor = calculateLeakageCurrentFactor(num_stacks_, stacked_mos_widths_, input_vector_, vdd, subthreshold_swing, dibl_swing);
+
+        // Calcualte actual leakage current at characterized temperature
+        double leakage_current_char_tmp = stacked_mos_widths_[0] * off_current * std::pow(10.0, leakage_current_factor);
+        leakage_current_char_tmp = std::max(min_off_current, leakage_current_char_tmp);
+
+        // Calculate actual leakage current at temp
+        double leakage_current = leakage_current_char_tmp * std::pow(10.0, (temp - char_temp) / temp_swing);
+
+        return leakage_current;
+    }
+
+    double TechModel::calculatePmosLeakageCurrent(unsigned int num_stacks_, double uni_stacked_mos_width_, unsigned int input_vector_) const
+    {
+        vector<double> stacked_mos_widths_(num_stacks_, uni_stacked_mos_width_);
+        return calculatePmosLeakageCurrent(num_stacks_, stacked_mos_widths_, input_vector_);
+    }
+
+    //Returns the leakage current of PMOS transistors, given the transistor stakcing, transistor widths, and input combination
+    double TechModel::calculatePmosLeakageCurrent(unsigned int num_stacks_, const vector<double>& stacked_mos_widths_, unsigned int input_vector_) const
+    {
+        // Get technology parameters
+        double vdd = get("Vdd");
+        double temp = get("Temperature");
+        double char_temp = get("Pmos->CharacterizedTemperature");
+        double min_off_current = get("Pmos->MinOffCurrent");
+        double off_current = get("Pmos->OffCurrent");
+        double dibl = get("Pmos->DIBL");
+        double subthreshold_swing = get("Pmos->SubthresholdSwing");
+        double temp_swing = get("Nmos->SubthresholdTempSwing");
+
+        // Map dibl to a swing value for easier calculation
+        double dibl_swing = subthreshold_swing / dibl;
+        
+        //Calculate the leakage current factor
+        double leakage_current_factor = calculateLeakageCurrentFactor(num_stacks_, stacked_mos_widths_, input_vector_, vdd, subthreshold_swing, dibl_swing);
+
+        // Calcualte actual leakage current at characterized temperature
+        double leakage_current_char_tmp = stacked_mos_widths_[0] * off_current * std::pow(10.0, leakage_current_factor);
+        leakage_current_char_tmp = std::max(min_off_current, leakage_current_char_tmp);
+
+        // Calculate actual leakage current at temp
+        double leakage_current = leakage_current_char_tmp * std::pow(10.0, (temp - char_temp) / temp_swing);
+
+        return leakage_current;
+    }
+
+    //Returns the leakage current, given the transistor stakcing, transistor widths, input combination,
+    //and technology information (vdd, subthreshold swing, subthreshold dibl swing)
+    double TechModel::calculateLeakageCurrentFactor(unsigned int num_stacks_, const vector<double>& stacked_mos_widths_, unsigned int input_vector_, double vdd_, double subthreshold_swing_, double dibl_swing_) const
+    {
+        // check everything is valid
+        ASSERT(num_stacks_ >= 1, "[Error] Number of stacks must be >= 1!");
+        ASSERT(stacked_mos_widths_.size() == num_stacks_, "[Error] Mismatch in number of stacks and the widths specified!");
+
+        //Use short name in this method
+        const double s1 = subthreshold_swing_;
+        const double s2 = dibl_swing_;
+
+        // Decode input combinations from input_vector_
+        std::vector<double> vs(num_stacks_, 0.0);
+        for(int i = 0; i < (int)num_stacks_; ++i)
+        {
+            double current_input = (double(input_vector_ & 0x1))*vdd_;
+            vs[i] = (current_input);
+            input_vector_ >>= 1;
+        }
+        // If the widths pointer is NULL, width is set to 1 by default
+        vector<double> ws = stacked_mos_widths_;
+
+        //Solve voltages at internal nodes of stacked transistors
+        // v[0] = 0
+        // v[num_stacks_] = vdd_
+        // v[i] = (1.0/(2*s1 + s2))*((s1 + s2)*v[i - 1] + s1*v[i + 1] 
+        //                 + s2*(vs[i + 1] - vs[i]) + s1*s2*log10(ws[i + 1]/ws[i]))
+        //Use tri-matrix solver to solve the above linear system
+
+        double A = -(s1 + s2);
+        double B = 2*s1 + s2;
+        double C = -s1;
+        std::vector<double> a(num_stacks_ - 1, 0);
+        std::vector<double> b(num_stacks_ - 1, 0);
+        std::vector<double> c(num_stacks_ - 1, 0);
+        std::vector<double> d(num_stacks_ - 1, 0);
+        std::vector<double> v(num_stacks_ + 1, 0);
+        unsigned int eff_num_stacks = num_stacks_;
+        bool is_found_valid_v = false;
+        do
+        {
+            //Set boundary condition
+            v[0] = 0;
+            v[eff_num_stacks] = vdd_;
+
+            //If the effective number of stacks is 1, no matrix needs to be solved
+            if(eff_num_stacks == 1)
+            {
+                break;
+            }
+
+            //----------------------------------------------------------------------
+            //Setup the tri-matrix
+            //----------------------------------------------------------------------
+            for(int i = 0; i < (int)eff_num_stacks-2; ++i)
+            {
+                a[i + 1] = A;
+                c[i] = C;
+            }
+            for(int i = 0; i < (int)eff_num_stacks-1; ++i)
+            {
+                b[i] = B;
+                d[i] = s2*(vs[i + 1] - vs[i]) + s1*s2*std::log10(ws[i + 1]/ws[i]);
+                if(i == ((int)eff_num_stacks - 2))
+                {
+                    d[i] -= C*vdd_;
+                }
+            }
+            //----------------------------------------------------------------------
+
+            //----------------------------------------------------------------------
+            //Solve the tri-matrix
+            //----------------------------------------------------------------------
+            for(int i = 1; i < (int)eff_num_stacks-1; ++i)
+            {
+                double m = a[i]/b[i - 1];
+                b[i] -= m*c[i - 1];
+                d[i] -= m*d[i - 1];
+            }
+
+            v[eff_num_stacks - 1] = d[eff_num_stacks - 2]/b[eff_num_stacks - 2];
+            for(int i = eff_num_stacks - 3; i >= 0; --i)
+            {
+                v[i + 1] = (d[i] - c[i]*v[i + 2])/b[i];
+            }
+            //----------------------------------------------------------------------
+
+            //Check if the internal voltages are in increasing order
+            is_found_valid_v = true;
+            for(int i = 1; i <= (int)eff_num_stacks; ++i)
+            {
+                //If the ith internal voltage is not in increasing order
+                //(i-1)th transistor is in triode region
+                //Remove the transistors in triode region as it does not exist
+                if(v[i] < v[i - 1])
+                {
+                    is_found_valid_v = false;
+                    eff_num_stacks--;
+                    vs.erase(vs.begin() + i - 1);
+                    ws.erase(ws.begin() + i - 1);
+                    break;
+                }
+            }
+        } while(!is_found_valid_v);
+
+        //Calculate the leakage current of the bottom transistor (first not in triode region)
+        double vgs = vs[0] - v[0];
+        double vds = v[1] - v[0];
+        double leakage_current_factor = vgs/s1 + (vds - vdd_)/s2;
+        //TODO - Check if the leakage current calculate for other transistors is identical
+
+        return leakage_current_factor;
+    }
+    //-------------------------------------------------------------------------
+
+    //-------------------------------------------------------------------------
+    // Wire Related Functions
+    //-------------------------------------------------------------------------
+    bool TechModel::isWireLayerExist(const String& layer_name_) const
+    {
+        std::set<String>::const_iterator it;
+        it = m_available_wire_layers_->find(layer_name_);
+        return (it != m_available_wire_layers_->end());
+    }
+
+    const std::set<String>* TechModel::getAvailableWireLayers() const
+    {
+        return m_available_wire_layers_;
+    }
+
+    double TechModel::calculateWireCapacitance(const String& layer_name_, double width_, double spacing_, double length_) const
+    {
+        // Get technology parameter
+        double min_width = get("Wire->" + layer_name_ + "->MinWidth").toDouble();
+        double min_spacing = get("Wire->" + layer_name_ + "->MinSpacing").toDouble();
+        double metal_thickness = get("Wire->" + layer_name_ + "->MetalThickness").toDouble();
+        double dielec_thickness = get("Wire->" + layer_name_ + "->DielectricThickness").toDouble();
+        double dielec_const = get("Wire->" + layer_name_ + "->DielectricConstant").toDouble();
+
+        ASSERT(width_ >= min_width, "[Error] Wire width must be >= " + (String) min_width + "!");
+        ASSERT(spacing_ >= min_spacing, "[Error] Wire spacing must be >= " + (String) min_spacing + "!");
+        ASSERT(length_ >= 0, "[Error] Wire length must be >= 0!");
+
+        double A, B, C;
+        // Calculate ground capacitance
+        A = width_ / dielec_thickness;
+        B = 2.04*std::pow((spacing_ / (spacing_ + 0.54 * dielec_thickness)), 1.77);
+        C = std::pow((metal_thickness / (metal_thickness + 4.53 * dielec_thickness)), 0.07);
+        double unit_gnd_cap = dielec_const * 8.85e-12 * (A + B * C);
+
+        A = 1.14 * (metal_thickness / spacing_) * std::exp(-4.0 * spacing_ / (spacing_ + 8.01 * dielec_thickness));
+        B = 2.37 * std::pow((width_ / (width_ + 0.31 * spacing_)), 0.28);
+        C = std::pow((dielec_thickness / (dielec_thickness + 8.96 * spacing_)), 0.76) * 
+                std::exp(-2.0 * spacing_ / (spacing_ + 6.0 * dielec_thickness));
+        double unit_coupling_cap = dielec_const * 8.85e-12 * (A + B * C);
+
+        double total_cap = 2 * (unit_gnd_cap + unit_coupling_cap) * length_;
+        return total_cap;
+    }
+
+    double TechModel::calculateWireResistance(const String& layer_name_, double width_, double length_) const
+    {
+        // Get technology parameter
+        double min_width = get("Wire->" + layer_name_ + "->MinWidth");
+        //double barrier_thickness = get("Wire->" + layer_name_ + "->BarrierThickness");
+        double resistivity = get("Wire->" + layer_name_ + "->Resistivity");
+        double metal_thickness = get("Wire->" + layer_name_ + "->MetalThickness");
+
+        ASSERT(width_ >= min_width, "[Error] Wire width must be >= " + (String) min_width + "!");
+        ASSERT(length_ >= 0, "[Error] Wire length must be >= 0!");
+
+        // Calculate Rho
+        // double rho = 2.202e-8 + (1.030e-15 / (width_ - 2.0 * barrier_thickness));
+
+        double unit_res = resistivity / (width_ * metal_thickness);
+        //double unit_res = rho / ((width_ - 2.0 * barrier_thickness) * (metal_thickness - barrier_thickness));
+
+        double total_res = unit_res * length_;
+        return total_res;
+    }
+    //-------------------------------------------------------------------------
+
+    TechModel::TechModel(const TechModel& tech_model_)
+        : Config(tech_model_), m_std_cell_lib_(tech_model_.m_std_cell_lib_)
+    {}
+} // namespace DSENT
+
diff --git a/ext/dsent/tech/TechModel.h b/ext/dsent/tech/TechModel.h
new file mode 100644 (file)
index 0000000..92e5a30
--- /dev/null
@@ -0,0 +1,71 @@
+#ifndef __DSENT_TECH_TECH_MODEL_H__
+#define __DSENT_TECH_TECH_MODEL_H__
+
+#include <vector>
+#include <set>
+
+#include "libutil/Config.h"
+#include "libutil/String.h"
+
+namespace DSENT
+{
+    class StdCellLib;
+
+    using std::set;
+    using std::vector;
+    using LibUtil::String;
+
+    class TechModel : public LibUtil::Config
+    {
+        public:
+            typedef std::set<String>::const_iterator ConstWireLayerIterator;
+
+        public:
+            TechModel();
+            virtual ~TechModel();
+
+        public:
+            // Set the pointer to a standard cell library
+            void setStdCellLib(const StdCellLib* std_cell_lib_);
+            // Get the pointer to the standard cell library
+            const StdCellLib* getStdCellLib() const;
+
+            // Return a cloned copy of this instance
+            virtual TechModel* clone() const;
+            // Override readFile function to include multiple technology files
+            virtual void readFile(const String& filename_);
+
+            // Transistor
+            // Returns the leakage current of NMOS transistors, given the transistor stakcing, transistor widths, and input combination
+            double calculateNmosLeakageCurrent(unsigned int num_stacks_, double uni_stacked_mos_width_, unsigned int input_vector_) const;
+            double calculateNmosLeakageCurrent(unsigned int num_stacks_, const vector<double>& stacked_mos_widths_, unsigned int input_vector_) const;
+            // Returns the leakage current of PMOS transistors, given the transistor stakcing, transistor widths, and input combination
+            double calculatePmosLeakageCurrent(unsigned int num_stacks_, double uni_stacked_mos_width_, unsigned int input_vector_) const;
+            double calculatePmosLeakageCurrent(unsigned int num_stacks_, const vector<double>& stacked_mos_widths_, unsigned int input_vector_) const;
+            // Returns the leakage current, given the transistor stakcing, transistor widths, input combination,
+            // and technology information (vdd, subthreshold swing, subthreshold dibl swing)
+            double calculateLeakageCurrentFactor(unsigned int num_stacks_, const vector<double>& stacked_mos_widths_, unsigned int input_vector_, double vdd_, double subthreshold_swing_, double dibl_swing_) const;
+
+            // Wire
+            // Check if the wire layer exist
+            bool isWireLayerExist(const String& layer_name_) const;
+            const std::set<String>* getAvailableWireLayers() const;
+            // Return wire capacitance for given wire layer, wire width, wire spacing, and wire length
+            double calculateWireCapacitance(const String& layer_name_, double width_, double spacing_, double length_) const;
+            // Return wire resistance for given wire layer, wire width, and wire length
+            double calculateWireResistance(const String& layer_name_, double width_, double length_) const;
+
+        private:
+            // Private copy constructor. Use clone to perform copy operation
+            TechModel(const TechModel& tech_model_);
+
+        private:
+            // A pointer to a standard cell library
+            const StdCellLib* m_std_cell_lib_;
+            // A set of available wire layers
+            std::set<String>* m_available_wire_layers_;
+    }; // class TechModel
+} // namespace DSENT
+
+#endif // __DSENT_TECH_TECH_MODEL_H__
+
diff --git a/ext/dsent/tech/tech_models/Bulk22LVT.model b/ext/dsent/tech/tech_models/Bulk22LVT.model
new file mode 100644 (file)
index 0000000..e2087a1
--- /dev/null
@@ -0,0 +1,179 @@
+# WARNING: Most commercial fabs will not be happy if you release their exact
+# process information! If you derive these numbers through SPICE models,
+# the process design kit, or any other confidential material, please round-off
+# the values and leave the process name unidentifiable by fab (i.e. call it
+# Bulk90LVT instead of TSMC90LVT) if you release parameters publicly. This
+# rule may not apply for open processes, but you may want to check.
+
+# All units are in SI, (volts, meters, kelvin, farads, ohms, amps, etc.)
+
+# This file contains the model for a bulk 22nm LVT process
+Name = Bulk22LVT
+
+# Supply voltage used in the circuit and for characterizations (V)
+Vdd = 0.8
+# Temperature (K)
+Temperature = 340
+
+# =============================================================================
+# Parameters for transistors
+# =============================================================================
+
+# Contacted gate pitch (m)
+Gate->PitchContacted = 0.120e-6
+
+# Min gate width (m)
+Gate->MinWidth = 0.100e-6
+
+# Gate cap per unit width (F/m)
+Gate->CapPerWidth = 0.900e-9
+# Source/Drain cap per unit width (F/m)
+Drain->CapPerWidth = 0.620e-9
+
+# Parameters characterization temperature (K)
+Nmos->CharacterizedTemperature = 300.0
+Pmos->CharacterizedTemperature = 300.0
+
+#------------------------------------------------------------------------------
+# I_Eff definition in Na, IEDM 2002
+#       I_EFF = (I(VG = 0.5, VD = 1.0) + I(VG = 1.0, VD = 0.5))/2
+#       R_EFF = VDD / I_EFF * 1 / (2 ln(2))
+# This is generally accurate for when input and output transition times
+# are similar, which is a reasonable case after timing optimization
+#------------------------------------------------------------------------------
+# Effective resistance (Ohm-m)
+Nmos->EffResWidth = 0.700e-3
+Pmos->EffResWidth = 0.930e-3
+
+#------------------------------------------------------------------------------
+# The ratio of extra effective resistance with each additional stacked
+# transistor
+#       EffResStackRatio = (R_EFF_NAND2 - R_EFF_INV) / R_EFF_INV)
+# For example, inverter has an normalized effective drive resistance of 1.0.
+# A NAND2 (2-stack) will have an effective drive of 1.0 + 0.7, a NAND3 (3-stack)
+# will have an effective drive of 1.0 + 2 * 0.7. Use NORs for Pmos. This fit
+# works relatively well up to 4 stacks. This value will change depending on the
+# VDD used. 
+#------------------------------------------------------------------------------
+# Effective resistance stack ratio
+Nmos->EffResStackRatio = 0.800
+Pmos->EffResStackRatio = 0.680
+
+#------------------------------------------------------------------------------
+# I_OFF defined as |I_DS| for |V_DS| = V_DD and |V_GS| = 0.0
+#       Minimum off current is used in technologies where I_OFF stops scaling
+#       with transistor width below some threshold
+#------------------------------------------------------------------------------
+# Off current per width (A/m)
+Nmos->OffCurrent = 100.0e-3
+Pmos->OffCurrent = 100.0e-3
+# Minimum off current (A)
+Nmos->MinOffCurrent = 60e-9
+Pmos->MinOffCurrent = 60e-9
+
+# Subthreshold swing (V/dec)        
+Nmos->SubthresholdSwing = 0.100
+Pmos->SubthresholdSwing = 0.100
+# DIBL factor (V/V)
+Nmos->DIBL = 0.150
+Pmos->DIBL = 0.150
+# Subthreshold temperature swing (K/dec)
+Nmos->SubthresholdTempSwing = 100.0
+Pmos->SubthresholdTempSwing = 100.0
+#------------------------------------------------------------------------------
+
+# =============================================================================
+# Parameters for interconnect
+# =============================================================================
+
+Wire->AvailableLayers = [Metal1,Local,Intermediate,Semiglobal,Global]
+
+# Metal 1 Wire (used for std cell routing only)
+# Min width (m)
+Wire->Metal1->MinWidth = 32e-9
+# Min spacing (m)
+Wire->Metal1->MinSpacing = 32e-9
+# Resistivity (Ohm-m)
+Wire->Metal1->Resistivity = 5.00e-8
+# Metal thickness (m)
+Wire->Metal1->MetalThickness = 60.0e-9
+# Dielectric thickness (m)
+Wire->Metal1->DielectricThickness = 60.0e-9
+# Dielectric constant
+Wire->Metal1->DielectricConstant = 3.00
+
+# Local wire, 1.0X of the M1 pitch
+# Min width (m)
+Wire->Local->MinWidth = 32e-9
+# Min spacing (m)
+Wire->Local->MinSpacing = 32e-9
+# Resistivity (Ohm-m)
+Wire->Local->Resistivity = 5.00e-8
+# Metal thickness (m)
+Wire->Local->MetalThickness = 60.0e-9
+# Dielectric thickness (m)
+Wire->Local->DielectricThickness = 60.0e-9
+# Dielectric constant
+Wire->Local->DielectricConstant = 3.00
+
+# Intermediate wire, 2.0X the M1 pitch
+# Min width (m)
+Wire->Intermediate->MinWidth = 55e-9
+# Min spacing (m)
+Wire->Intermediate->MinSpacing = 55e-9
+# Resistivity (Ohm-m)
+Wire->Intermediate->Resistivity = 4.00e-8
+# Metal thickness (m)
+Wire->Intermediate->MetalThickness = 100.0e-9
+# Dielectric thickness (m)
+Wire->Intermediate->DielectricThickness = 100.0e-9
+# Dielectric constant
+Wire->Intermediate->DielectricConstant = 2.8
+
+# Semiglobal wire, 4.0X the M1 pitch
+# Min width (m)
+Wire->Semiglobal->MinWidth = 110e-9
+# Min spacing (m)
+Wire->Semiglobal->MinSpacing = 110e-9
+# Resistivity (Ohm-m)
+Wire->Semiglobal->Resistivity = 2.60e-8
+# Metal thickness (m)
+Wire->Semiglobal->MetalThickness = 200e-9
+# Dielectric thickness (m)
+Wire->Semiglobal->DielectricThickness = 170e-9
+# Dielectric constant
+Wire->Semiglobal->DielectricConstant = 2.80        
+
+# Global wire, 6.0X the M1 pitch
+# Min width (m)
+Wire->Global->MinWidth = 160e-9
+# Min spacing (m)
+Wire->Global->MinSpacing = 160e-9
+# Resistivity (Ohm-m)
+Wire->Global->Resistivity = 2.30e-8
+# Metal thickness (m)
+Wire->Global->MetalThickness = 280e-9
+# Dielectric thickness (m)
+Wire->Global->DielectricThickness = 250e-9
+# Dielectric constant
+Wire->Global->DielectricConstant = 2.60
+
+# =============================================================================
+# Parameters for Standard Cells
+# =============================================================================
+
+# The height of the standard cell is usually a multiple of the vertical
+# M1 pitch (tracks). By definition, an X1 size cell has transistors
+# that fit exactly in the given cell height without folding, or leaving
+# any wasted vertical area
+
+# Reasonable values for the number of M1 tracks that we have seen are 8-14
+StdCell->Tracks = 11
+# Height overhead due to supply rails, well spacing, etc. Note that this will grow
+# if the height of the standard cell decreases!
+StdCell->HeightOverheadFactor = 1.400
+
+# Sets the available sizes of each standard cell. Keep in mind that
+# 1.0 is the biggest cell without any transistor folding
+StdCell->AvailableSizes = [1.0, 1.4, 2.0, 3.0, 4.0, 6.0, 8.0, 10.0, 12.0, 16.0]
+
diff --git a/ext/dsent/tech/tech_models/Bulk32LVT.model b/ext/dsent/tech/tech_models/Bulk32LVT.model
new file mode 100644 (file)
index 0000000..9a90bda
--- /dev/null
@@ -0,0 +1,168 @@
+# WARNING: Most commercial fabs will not be happy if you release their exact\r
+# process information! If you derive these numbers through SPICE models,\r
+# the process design kit, or any other confidential material, please round-off\r
+# the values and leave the process name unidentifiable by fab (i.e. call it\r
+# Bulk90LVT instead of TSMC90LVT) if you release parameters publicly. This\r
+# rule may not apply for open processes, but you may want to check.\r
+\r
+# All units are in SI, (volts, meters, kelvin, farads, ohms, amps, etc.)\r
+\r
+# This file contains the model for a bulk 32nm LVT process\r
+Name = Bulk32LVT\r
+\r
+# Supply voltage used in the circuit and for characterizations (V)\r
+Vdd = 0.9\r
+# Temperature (K)\r
+Temperature = 340\r
+\r
+# =============================================================================\r
+# Parameters for transistors\r
+# =============================================================================\r
+\r
+# Contacted gate pitch (m)\r
+Gate->PitchContacted = 0.160e-6\r
+\r
+# Min gate width (m)\r
+Gate->MinWidth = 0.120e-6\r
+\r
+# Gate cap per unit width (F/m)\r
+Gate->CapPerWidth = 0.950e-9\r
+# Source/Drain cap per unit width (F/m)\r
+Drain->CapPerWidth = 0.640e-9\r
+\r
+# Parameters characterization temperature (K)\r
+Nmos->CharacterizedTemperature = 300.0\r
+Pmos->CharacterizedTemperature = 300.0\r
+\r
+#------------------------------------------------------------------------------\r
+# I_Eff definition in Na, IEDM 2002\r
+#       I_EFF = (I(VG = 0.5, VD = 1.0) + I(VG = 1.0, VD = 0.5))/2\r
+#       R_EFF = VDD / I_EFF * 1 / (2 ln(2))\r
+# This is generally accurate for when input and output transition times\r
+# are similar, which is a reasonable case after timing optimization\r
+#------------------------------------------------------------------------------\r
+# Effective resistance (Ohm-m)\r
+Nmos->EffResWidth = 0.890e-3               \r
+Pmos->EffResWidth = 1.270e-3\r
+\r
+#------------------------------------------------------------------------------\r
+# The ratio of extra effective resistance with each additional stacked\r
+# transistor\r
+#       EffResStackRatio = (R_EFF_NAND2 - R_EFF_INV) / R_EFF_INV)\r
+# For example, inverter has an normalized effective drive resistance of 1.0.\r
+# A NAND2 (2-stack) will have an effective drive of 1.0 + 0.7, a NAND3 (3-stack)\r
+# will have an effective drive of 1.0 + 2 * 0.7. Use NORs for Pmos. This fit\r
+# works relatively well up to 4 stacks. This value will change depending on the\r
+# VDD used. \r
+#------------------------------------------------------------------------------\r
+# Effective resistance stack ratio\r
+Nmos->EffResStackRatio = 0.78\r
+Pmos->EffResStackRatio = 0.66\r
+\r
+#------------------------------------------------------------------------------\r
+# I_OFF defined as |I_DS| for |V_DS| = V_DD and |V_GS| = 0.0\r
+#       Minimum off current is used as a second fit point, since I_OFF often\r
+#       stops scaling with transistor width below some threshold\r
+#------------------------------------------------------------------------------\r
+# Off current per width (A/m)\r
+Nmos->OffCurrent = 100e-3\r
+Pmos->OffCurrent = 100e-3\r
+\r
+# Minimum off current (A)\r
+Nmos->MinOffCurrent = 100e-9\r
+Pmos->MinOffCurrent = 20e-9\r
+\r
+# Subthreshold swing (V/dec)        \r
+Nmos->SubthresholdSwing = 0.100\r
+Pmos->SubthresholdSwing = 0.100\r
+\r
+# DIBL factor (V/V)\r
+Nmos->DIBL = 0.150\r
+Pmos->DIBL = 0.150\r
+\r
+# Subthreshold leakage temperature swing (K/dec)\r
+Nmos->SubthresholdTempSwing = 100\r
+Pmos->SubthresholdTempSwing = 100\r
+#------------------------------------------------------------------------------\r
+\r
+# =============================================================================\r
+# Parameters for interconnect\r
+# =============================================================================\r
+\r
+Wire->AvailableLayers = [Metal1,Local,Intermediate,Global]\r
+\r
+# Metal 1 Wire (used for std cell routing only)\r
+# Min width (m)\r
+Wire->Metal1->MinWidth = 55e-9\r
+# Min spacing (m)\r
+Wire->Metal1->MinSpacing = 55e-9\r
+# Resistivity (Ohm-m)\r
+Wire->Metal1->Resistivity = 4.00e-8\r
+# Metal thickness (m)\r
+Wire->Metal1->MetalThickness = 100.0e-9\r
+# Dielectric thickness (m)\r
+Wire->Metal1->DielectricThickness = 100.0e-9\r
+# Dielectric constant\r
+Wire->Metal1->DielectricConstant = 3.2\r
+\r
+# Local wire, 1.0X of the M1 pitch\r
+# Min width (m)\r
+Wire->Local->MinWidth = 55e-9\r
+# Min spacing (m)\r
+Wire->Local->MinSpacing = 55e-9\r
+# Resistivity (Ohm-m)\r
+Wire->Local->Resistivity = 4.00e-8\r
+# Metal thickness (m)\r
+Wire->Local->MetalThickness = 100.0e-9\r
+# Dielectric thickness (m)\r
+Wire->Local->DielectricThickness = 100.0e-9\r
+# Dielectric constant\r
+Wire->Local->DielectricConstant = 3.2\r
+\r
+# Intermediate wire, 2.0X the M1 pitch\r
+# Min width (m)\r
+Wire->Intermediate->MinWidth = 110e-9\r
+# Min spacing (m)\r
+Wire->Intermediate->MinSpacing = 110e-9\r
+# Resistivity (Ohm-m)\r
+Wire->Intermediate->Resistivity = 2.60e-8\r
+# Metal thickness (m)\r
+Wire->Intermediate->MetalThickness = 200e-9\r
+# Dielectric thickness (m)\r
+Wire->Intermediate->DielectricThickness = 170e-9\r
+# Dielectric constant\r
+Wire->Intermediate->DielectricConstant = 3.00\r
+\r
+# Global wire, 3.0X the M1 pitch\r
+# Min width (m)\r
+Wire->Global->MinWidth = 160e-9\r
+# Min spacing (m)\r
+Wire->Global->MinSpacing = 160e-9\r
+# Resistivity (Ohm-m)\r
+Wire->Global->Resistivity = 2.30e-8\r
+# Metal thickness (m)\r
+Wire->Global->MetalThickness = 280e-9\r
+# Dielectric thickness (m)\r
+Wire->Global->DielectricThickness = 250e-9\r
+# Dielectric constant\r
+Wire->Global->DielectricConstant = 2.80\r
+\r
+# =============================================================================\r
+# Parameters for Standard Cells\r
+# =============================================================================\r
+\r
+# The height of the standard cell is usually a multiple of the vertical\r
+# M1 pitch (tracks). By definition, an X1 size cell has transistors\r
+# that fit exactly in the given cell height without folding, or leaving\r
+# any wasted vertical area\r
+\r
+# Reasonable values for the number of M1 tracks that we have seen are 8-14\r
+StdCell->Tracks = 11\r
+# Height overhead due to supply rails, well spacing, etc. Note that this will grow\r
+# if the height of the standard cell decreases!\r
+StdCell->HeightOverheadFactor = 1.400\r
+\r
+# Sets the available sizes of each standard cell. Keep in mind that\r
+# 1.0 is the biggest cell without any transistor folding\r
+StdCell->AvailableSizes = [1.0, 1.4, 2.0, 3.0, 4.0, 6.0, 8.0, 10.0, 12.0, 16.0]\r
+\r
diff --git a/ext/dsent/tech/tech_models/Bulk45LVT.model b/ext/dsent/tech/tech_models/Bulk45LVT.model
new file mode 100644 (file)
index 0000000..d8015c5
--- /dev/null
@@ -0,0 +1,168 @@
+# WARNING: Most commercial fabs will not be happy if you release their exact
+# process information! If you derive these numbers through SPICE models,
+# the process design kit, or any other confidential material, please round-off
+# the values and leave the process name unidentifiable by fab (i.e. call it
+# Bulk90LVT instead of TSMC90LVT) if you release parameters publicly. This
+# rule may not apply for open processes, but you may want to check.
+
+# All units are in SI, (volts, meters, kelvin, farads, ohms, amps, etc.)
+
+# This file contains the model for a bulk 45nm LVT process
+Name = Bulk45LVT
+
+# Supply voltage used in the circuit and for characterizations (V)
+Vdd = 1.0
+# Temperature (K)
+Temperature = 340
+
+# =============================================================================
+# Parameters for transistors
+# =============================================================================
+
+# Contacted gate pitch (m)
+Gate->PitchContacted = 0.200e-6
+
+# Min gate width (m)
+Gate->MinWidth = 0.160e-6
+
+# Gate cap per unit width (F/m)
+Gate->CapPerWidth = 1.000e-9
+# Source/Drain cap per unit width (F/m)
+Drain->CapPerWidth = 0.600e-9
+
+# Parameters characterization temperature (K)
+Nmos->CharacterizedTemperature = 300.0
+Pmos->CharacterizedTemperature = 300.0
+
+#------------------------------------------------------------------------------
+# I_Eff definition in Na, IEDM 2002
+#       I_EFF = (I(VG = 0.5, VD = 1.0) + I(VG = 1.0, VD = 0.5))/2
+#       R_EFF = VDD / I_EFF * 1 / (2 ln(2))
+# This is generally accurate for when input and output transition times
+# are similar, which is a reasonable case after timing optimization
+#------------------------------------------------------------------------------
+# Effective resistance (Ohm-m)
+Nmos->EffResWidth = 1.100e-3               
+Pmos->EffResWidth = 1.500e-3
+
+#------------------------------------------------------------------------------
+# The ratio of extra effective resistance with each additional stacked
+# transistor
+#       EffResStackRatio = (R_EFF_NAND2 - R_EFF_INV) / R_EFF_INV)
+# For example, inverter has an normalized effective drive resistance of 1.0.
+# A NAND2 (2-stack) will have an effective drive of 1.0 + 0.7, a NAND3 (3-stack)
+# will have an effective drive of 1.0 + 2 * 0.7. Use NORs for Pmos. This fit
+# works relatively well up to 4 stacks. This value will change depending on the
+# VDD used. 
+#------------------------------------------------------------------------------
+# Effective resistance stack ratio
+Nmos->EffResStackRatio = 0.7
+Pmos->EffResStackRatio = 0.6
+
+#------------------------------------------------------------------------------
+# I_OFF defined as |I_DS| for |V_DS| = V_DD and |V_GS| = 0.0
+#       Minimum off current is used as a second fit point, since I_OFF often
+#       stops scaling with transistor width below some threshold
+#------------------------------------------------------------------------------
+# Off current per width (A/m)
+Nmos->OffCurrent = 100e-3
+Pmos->OffCurrent = 100e-3
+
+# Minimum off current (A)
+Nmos->MinOffCurrent = 100e-9
+Pmos->MinOffCurrent = 20e-9
+
+# Subthreshold swing (V/dec)        
+Nmos->SubthresholdSwing = 0.100
+Pmos->SubthresholdSwing = 0.100
+
+# DIBL factor (V/V)
+Nmos->DIBL = 0.150
+Pmos->DIBL = 0.150
+
+# Subthreshold leakage temperature swing (K/dec)
+Nmos->SubthresholdTempSwing = 100
+Pmos->SubthresholdTempSwing = 100
+#------------------------------------------------------------------------------
+
+# =============================================================================
+# Parameters for interconnect
+# =============================================================================
+
+Wire->AvailableLayers = [Metal1,Local,Intermediate,Global]
+
+# Metal 1 Wire (used for std cell routing only)
+# Min width (m)
+Wire->Metal1->MinWidth = 80e-9
+# Min spacing (m)
+Wire->Metal1->MinSpacing = 80e-9
+# Resistivity (Ohm-m)
+Wire->Metal1->Resistivity = 3.00e-8
+# Metal thickness (m)
+Wire->Metal1->MetalThickness = 140.0e-9
+# Dielectric thickness (m)
+Wire->Metal1->DielectricThickness = 130.0e-9
+# Dielectric constant
+Wire->Metal1->DielectricConstant = 3.2
+
+# Local wire, 1.0X of the M1 pitch
+# Min width (m)
+Wire->Metal1->MinWidth = 80e-9
+# Min spacing (m)
+Wire->Metal1->MinSpacing = 80e-9
+# Resistivity (Ohm-m)
+Wire->Metal1->Resistivity = 3.00e-8
+# Metal thickness (m)
+Wire->Metal1->MetalThickness = 140.0e-9
+# Dielectric thickness (m)
+Wire->Metal1->DielectricThickness = 130.0e-9
+# Dielectric constant
+Wire->Metal1->DielectricConstant = 3.2
+
+# Intermediate wire, 1.4X the M1 pitch
+# Min width (m)
+Wire->Intermediate->MinWidth = 110e-9
+# Min spacing (m)
+Wire->Intermediate->MinSpacing = 110e-9
+# Resistivity (Ohm-m)
+Wire->Intermediate->Resistivity = 2.60e-8
+# Metal thickness (m)
+Wire->Intermediate->MetalThickness = 200e-9
+# Dielectric thickness (m)
+Wire->Intermediate->DielectricThickness = 170e-9
+# Dielectric constant
+Wire->Intermediate->DielectricConstant = 3.00
+
+# Global wire, 2.0X the M1 pitch
+# Min width (m)
+Wire->Global->MinWidth = 160e-9
+# Min spacing (m)
+Wire->Global->MinSpacing = 160e-9
+# Resistivity (Ohm-m)
+Wire->Global->Resistivity = 2.30e-8
+# Metal thickness (m)
+Wire->Global->MetalThickness = 280e-9
+# Dielectric thickness (m)
+Wire->Global->DielectricThickness = 250e-9
+# Dielectric constant
+Wire->Global->DielectricConstant = 2.80
+
+# =============================================================================
+# Parameters for Standard Cells
+# =============================================================================
+
+# The height of the standard cell is usually a multiple of the vertical
+# M1 pitch (tracks). By definition, an X1 size cell has transistors
+# that fit exactly in the given cell height without folding, or leaving
+# any wasted vertical area
+
+# Reasonable values for the number of M1 tracks that we have seen are 8-14
+StdCell->Tracks = 11
+# Height overhead due to supply rails, well spacing, etc. Note that this will grow
+# if the height of the standard cell decreases!
+StdCell->HeightOverheadFactor = 1.400
+
+# Sets the available sizes of each standard cell. Keep in mind that
+# 1.0 is the biggest cell without any transistor folding
+StdCell->AvailableSizes = [1.0, 1.4, 2.0, 3.0, 4.0, 6.0, 8.0, 10.0, 12.0, 16.0]
+
diff --git a/ext/dsent/tech/tech_models/Photonics.model b/ext/dsent/tech/tech_models/Photonics.model
new file mode 100644 (file)
index 0000000..335e1e8
--- /dev/null
@@ -0,0 +1,89 @@
+# This file contains the model for photonic devices/circuits
+PhotonicsName = Photonics
+
+# ALL PARAMETERS IN SI UNITS!!! (J, W, m, F, dB, A)
+
+# -----------------------------------------------------------------------------
+# Waveguide
+# -----------------------------------------------------------------------------
+Waveguide->LossPerMeter                     = 100       # dB/m
+Waveguide->Pitch                            = 4e-6      # m
+Splitter->Loss                              = 1.00      # dB
+Coupler->Loss                               = 1.00      # dB
+
+# -----------------------------------------------------------------------------
+# Laser
+# -----------------------------------------------------------------------------
+
+# Continuous wave off-chip (always on) laser
+Laser->CW->Efficiency                       = 0.25      # P_Laser/P_Electrical
+Laser->CW->LaserDiodeLoss                   = 1.00      # Laser diode loss
+Laser->CW->Area                             = 0
+
+# Gated on-chip (data-dependent) laser
+Laser->GatedCW->Efficiency                  = 0.25      # P_Laser/P_Electrical
+Laser->GatedCW->LaserDiodeLoss              = 1.00      # Laser diode loss
+Laser->GatedCW->Area                        = 200e-12
+
+# -----------------------------------------------------------------------------
+# Modulators
+# -----------------------------------------------------------------------------
+# Ring Modulator
+Modulator->Ring->SupplyBoostRatio           = 1.2       # Boost the supply voltage above required reverse bias voltage by this ratio
+Modulator->Ring->ParasiticRes               = 100       # ohm
+Modulator->Ring->ParasiticCap               = 5e-15     # F
+Modulator->Ring->FCPDEffect                 = 3e-27     # Free carrier plasma dispersion effect, delta_n/delta_c (m^-3)
+Modulator->Ring->Tn                         = 0.01      # Transmisivity at the bottom of the notch
+Modulator->Ring->NA                         = 3e24      # m^3, p doping
+Modulator->Ring->ND                         = 1e24      # m^3, n doping
+Modulator->Ring->ni                         = 1e16      # m^3, intrinsic free carriers
+Modulator->Ring->JunctionRatio              = 0.8       # Junction ratio to total optical length
+Modulator->Ring->Height                     = 500e-9    # Height of the junction (m)
+Modulator->Ring->Width                      = 500e-9    # Modulator width (m)
+Modulator->Ring->ConfinementFactor          = 0.3       # Modulator confinement factor
+
+# -----------------------------------------------------------------------------
+# Ring Resonator
+# -----------------------------------------------------------------------------
+Ring->Area                                  = 100e-12   # m2
+Ring->Lambda                                = 1300e-9   # Resonant wavelength range
+Ring->GroupIndex                            = 4         # Group index
+Ring->Radius                                = 3e-6      # Bend radius of the ring
+Ring->ConfinementFactor                     = 0.3       # Confinement factor
+Ring->ThroughLoss                           = 0.01             # [dB]
+Ring->DropLoss                              = 1.0       # [dB]
+Ring->MaxQualityFactor                      = 150e3     # Maximum quality factor
+Ring->HeatingEfficiency                     = 100000    # Ring heating efficiency [K/W]
+Ring->TuningEfficiency                      = 10e9      # Ring tuning efficiency [Hz/K]
+Ring->LocalVariationSigma                   = 40e9      # Ring resonance frequency local mismatch sigma [Hz]
+Ring->SystematicVariationSigma              = 200e9     # Ring resonance frequency systematic mismatch sigma [Hz]
+Ring->TemperatureMax                        = 380       # Maximum temperature that the tuning mechanism must still be able to work at [K]
+Ring->TemperatureMin                        = 280       # Minimum temperature that the tuning mechanism must still be able to work at [K]
+Ring->MaxElectricallyTunableFreq            = 50e9      # Maximum electrically tunable range when allowing for electrically assisted tuning [Hz]
+
+# -----------------------------------------------------------------------------
+# Photodetector
+# -----------------------------------------------------------------------------
+Photodetector->Responsivity                 = 1.1           #(A/W)
+Photodetector->Area                         = 10e-12        # m2
+Photodetector->Cap                          = 0             # F
+Photodetector->ParasiticCap                 = 5e-15         # F
+Photodetector->Loss                         = 1.00          # dB
+Photodetector->MinExtinctionRatio           = 3             # dB
+Photodetector->AvalancheGain                = 1             # avalanche gain
+
+# -----------------------------------------------------------------------------
+# Receivers
+# -----------------------------------------------------------------------------
+
+# Sense amplifier (common to all receivers)
+SenseAmp->BER                               = 1e-15     # Target bit error rate
+SenseAmp->CMRR                              = 5         # Common-mode rejection ratio
+SenseAmp->OffsetCompensationBits            = 5         # Number of bits used for fine-tuning offset compensation
+SenseAmp->OffsetRatio                       = 0.04      # Offset mismatch (as a fraction of VDD)
+SenseAmp->SupplyNoiseRandRatio              = 0.01      # Random supply noise (as a fraction VDD)
+SenseAmp->SupplyNoiseDetRatio               = 0.05      # Deterministic supply noise (as a fraction VDD)
+SenseAmp->NoiseMargin                       = 0.02      # Extra noise margin
+SenseAmp->JitterRatio                       = 0.01      # Jitter (as a fraction of Tbit)
+
+Receiver->Int->IntegrationTimeRatio         = 0.7       # Integration time (as a fraction of Tbit)
diff --git a/ext/dsent/tech/tech_models/TG11LVT.model b/ext/dsent/tech/tech_models/TG11LVT.model
new file mode 100644 (file)
index 0000000..292e40a
--- /dev/null
@@ -0,0 +1,181 @@
+# WARNING: Most commercial fabs will not be happy if you release their exact
+# process information! If you derive these numbers through SPICE models,
+# the process design kit, or any other confidential material, please round-off
+# the values and leave the process name unidentifiable by fab (i.e. call it
+# Bulk90LVT instead of TSMC90LVT) if you release parameters publicly. This
+# rule may not apply for open processes, but you may want to check.
+
+# All units are in SI, (volts, meters, kelvin, farads, ohms, amps, etc.)
+
+# This file contains the model for a Tri-Gate (Multi-Gate) 11nm LVT process
+Name = TG11LVT
+
+# Supply voltage used in the circuit and for characterizations (V)
+Vdd = 0.6
+# Temperature (K)
+Temperature = 340
+
+# =============================================================================
+# Parameters for transistors
+# =============================================================================
+
+# Contacted gate pitch (m)
+Gate->PitchContacted = 0.080e-6
+
+# Min gate width (m)
+Gate->MinWidth = 0.080e-6
+
+# Gate cap per unit width (F/m)
+Gate->CapPerWidth = 0.61e-9
+# Source/Drain cap per unit width (F/m)
+Drain->CapPerWidth = 0.56e-9
+
+# Parameters characterization temperature (K)
+Nmos->CharacterizedTemperature = 300.0
+Pmos->CharacterizedTemperature = 300.0
+
+#------------------------------------------------------------------------------
+# I_Eff definition in Na, IEDM 2002
+#       I_EFF = (I(VG = 0.5, VD = 1.0) + I(VG = 1.0, VD = 0.5))/2
+#       R_EFF = VDD / I_EFF * 1 / (2 ln(2))
+# This is generally more accurate for when the delay is input transition time
+# limited
+#------------------------------------------------------------------------------
+# Effective resistance (Ohm-m)
+Nmos->EffResWidth = 1.16e-3
+Pmos->EffResWidth = 1.28e-3
+
+#------------------------------------------------------------------------------
+# The ratio of extra effective resistance with each additional stacked
+# transistor
+#       EffResStackRatio = (R_EFF_NAND2 - R_EFF_INV) / R_EFF_INV)
+# For example, inverter has an normalized effective drive resistance of 1.0.
+# A NAND2 (2-stack) will have an effective drive of 1.0 + 0.7, a NAND3 (3-stack)
+# will have an effective drive of 1.0 + 2 * 0.7. Use NORs for Pmos. This fit
+# works relatively well up to 4 stacks. This value will change depending on the
+# VDD used. 
+#------------------------------------------------------------------------------
+# Effective resistance stack ratio
+Nmos->EffResStackRatio = 0.89
+Pmos->EffResStackRatio = 0.86
+
+#------------------------------------------------------------------------------
+# I_OFF defined as |I_DS| for |V_DS| = V_DD and |V_GS| = 0.0
+#       Minimum off current is used in technologies where I_OFF stops scaling
+#       with transistor width below some threshold
+#------------------------------------------------------------------------------
+# Off current per width (A/m)
+Nmos->OffCurrent = 100.0e-3
+Pmos->OffCurrent = 100.0e-3
+# Minimum off current (A)
+Nmos->MinOffCurrent = 40e-9
+Pmos->MinOffCurrent = 4e-9
+
+# Subthreshold swing (V/dec)        
+Nmos->SubthresholdSwing = 0.080
+Pmos->SubthresholdSwing = 0.080
+# DIBL factor (V/V)
+Nmos->DIBL = 0.125
+Pmos->DIBL = 0.125
+# Subthreshold temperature swing (K/dec)
+Nmos->SubthresholdTempSwing = 100.0
+Pmos->SubthresholdTempSwing = 100.0
+#------------------------------------------------------------------------------
+
+# =============================================================================
+# Parameters for interconnect
+# =============================================================================
+
+Wire->AvailableLayers = [Metal1,Local,Intermediate,Semiglobal,Global]
+
+# Metal 1 Wire (used for std cell routing only)
+# Min width (m)
+Wire->Metal1->MinWidth = 20e-9
+# Min spacing (m)
+Wire->Metal1->MinSpacing = 20e-9
+# Resistivity (Ohm-m)
+Wire->Metal1->Resistivity = 6.8e-8
+# Metal thickness (m)
+Wire->Metal1->MetalThickness = 35.0e-9
+# Dielectric thickness (m)
+Wire->Metal1->DielectricThickness = 35.0e-9
+# Dielectric constant
+Wire->Metal1->DielectricConstant = 3.00
+
+# Local wire, 1.0X of the M1 pitch
+# Min width (m)
+Wire->Local->MinWidth = 20e-9
+# Min spacing (m)
+Wire->Local->MinSpacing = 20e-9
+# Resistivity (Ohm-m)
+Wire->Local->Resistivity = 6.8e-8
+# Metal thickness (m)
+Wire->Local->MetalThickness = 35.0e-9
+# Dielectric thickness (m)
+Wire->Local->DielectricThickness = 35.0e-9
+# Dielectric constant
+Wire->Local->DielectricConstant = 3.00
+
+# Intermediate wire, 2.0X the M1 pitch
+# Min width (m)
+Wire->Intermediate->MinWidth = 40e-9
+# Min spacing (m)
+Wire->Intermediate->MinSpacing = 40e-9
+# Resistivity (Ohm-m)
+Wire->Intermediate->Resistivity = 4.50e-8
+# Metal thickness (m)
+Wire->Intermediate->MetalThickness = 70.0e-9
+# Dielectric thickness (m)
+Wire->Intermediate->DielectricThickness = 70.0e-9
+# Dielectric constant
+Wire->Intermediate->DielectricConstant = 2.80
+
+# Semiglobal wire, 4.0X the M1 pitch
+# Min width (m)
+Wire->Semiglobal->MinWidth = 80e-9
+# Min spacing (m)
+Wire->Semiglobal->MinSpacing = 80e-9
+# Resistivity (Ohm-m)
+Wire->Semiglobal->Resistivity = 2.80e-8
+# Metal thickness (m)
+Wire->Semiglobal->MetalThickness = 150.0e-9
+# Dielectric thickness (m)
+Wire->Semiglobal->DielectricThickness = 150.0e-9
+# Dielectric constant
+Wire->Semiglobal->DielectricConstant = 2.60      
+
+# Global wire, 8.0X the M1 pitch
+# Min width (m)
+Wire->Global->MinWidth = 160e-9
+# Min spacing (m)
+Wire->Global->MinSpacing = 160e-9
+# Resistivity (Ohm-m)
+Wire->Global->Resistivity = 2.30e-8
+# Metal thickness (m)
+Wire->Global->MetalThickness = 280e-9
+# Dielectric thickness (m)
+Wire->Global->DielectricThickness = 250e-9
+# Dielectric constant
+Wire->Global->DielectricConstant = 2.60
+
+# =============================================================================
+# Parameters for Standard Cells
+# =============================================================================
+
+# The height of the standard cell is usually a multiple of the vertical
+# M1 pitch (tracks). By definition, an X1 size cell has transistors
+# that fit exactly in the given cell height without folding, or leaving
+# any wasted vertical area
+
+# Reasonable values for the number of M1 tracks that we have seen are 8-14
+StdCell->Tracks = 11
+# Height overhead due to supply rails, well spacing, etc. Note that this will grow
+# if the height of the standard cell decreases!
+StdCell->HeightOverheadFactor = 1.400
+
+# Sets the available sizes of each standard cell. Keep in mind that
+# 1.0 is the biggest cell without any transistor folding
+StdCell->AvailableSizes = [1.0, 1.4, 2.0, 3.0, 4.0, 6.0, 8.0, 10.0, 12.0, 16.0]
+
+
+
diff --git a/ext/dsent/util/CommonType.h b/ext/dsent/util/CommonType.h
new file mode 100644 (file)
index 0000000..e8c9705
--- /dev/null
@@ -0,0 +1,36 @@
+#ifndef __DSENT_UTIL_COMMON_TYPE_H__
+#define __DSENT_UTIL_COMMON_TYPE_H__
+
+#include <iostream>
+
+#include "libutil/LibUtil.h"
+
+#include "util/Result.h"
+
+#include "tech/TechModel.h"
+
+namespace DSENT
+{
+    using std::cout;
+    using std::endl;
+
+    // Enable functions
+    using LibUtil::deletePtrMap;
+    using LibUtil::clearPtrMap;
+    using LibUtil::deletePtrVector;
+    using LibUtil::clearPtrVector;
+
+    // Enable classes
+    using LibUtil::Exception;
+    using LibUtil::Log;
+    using LibUtil::String;
+    using LibUtil::Map;
+    using LibUtil::StringMap;
+
+    typedef StringMap   ParameterMap;
+    typedef StringMap   PropertyMap;
+
+} // namespace DSENT
+
+#endif // __DSENT_UTIL_COMMON_TYPE_H__
+
diff --git a/ext/dsent/util/Config.cc b/ext/dsent/util/Config.cc
new file mode 100644 (file)
index 0000000..a12a300
--- /dev/null
@@ -0,0 +1,105 @@
+#include "util/Config.h"
+
+#include "model/std_cells/StdCellLib.h"
+
+namespace DSENT
+{
+
+    Config* Config::ms_singleton_ = NULL;
+
+    void Config::allocate(const String& cfg_file_name_)
+    {
+        Log::printLine("Config::allocate");
+
+        // Allocate static Config instance
+        ASSERT(!ms_singleton_, "Config singleton is allocated");
+        ms_singleton_ = new Config();
+        ms_singleton_->readFile(cfg_file_name_);
+
+        Log::printLine("Config::allocate - End");
+        return;
+    }
+
+    void Config::release()
+    {
+        Log::printLine("Config::release");
+
+        // Release static Config instance
+        ASSERT(ms_singleton_, "Config singleton is not allocated");
+        delete ms_singleton_;
+        ms_singleton_ = NULL;
+
+        Log::printLine("Config::release - End");
+        return;
+    }
+
+    Config* Config::getSingleton()
+    {
+        ASSERT(ms_singleton_, "Config singleton is not allocated");
+        return ms_singleton_;
+    }
+
+    Config::Config()
+        : m_tech_model_(NULL)
+    {}
+
+    Config::~Config()
+    {
+        delete m_tech_model_;
+    }
+
+    void Config::setTechModel(const TechModel* tech_model_)
+    {
+        ASSERT((tech_model_ != NULL), "tech_model_ is null");
+
+        m_tech_model_ = tech_model_;
+        return;
+    }
+
+    const TechModel* Config::getTechModel() const
+    {
+        ASSERT((m_tech_model_ != NULL), "m_tech_model_ is null");
+
+        return m_tech_model_;
+    }
+
+    void Config::readFile(const String& file_name_)
+    {
+        Log::printLine("Config::readFile");
+
+        LibUtil::Config::readFile(file_name_);
+
+        Log::printLine("Config::readFile - End");
+        return;
+    }
+
+    void Config::constructTechModel(const String& overwrite_str_)
+    {
+        Log::printLine("Config::constructTechModel");
+
+        // Allocate static TechModel instance
+        const String& electrical_tech_model_filename = get("ElectricalTechModelFilename");
+
+        TechModel* tech_model = new TechModel();
+        tech_model->readFile(electrical_tech_model_filename);
+        if(keyExist("PhotonicTechModelFilename"))
+        {
+            const String& photonic_tech_model_filename = get("PhotonicTechModelFilename");
+            tech_model->readFile(photonic_tech_model_filename);
+        }
+
+        // Overwrite the settings at runtime
+        tech_model->readString(overwrite_str_);
+
+        // Allocate static StdCellLib instance
+        StdCellLib* std_cell_lib = new StdCellLib(tech_model);
+
+        // Set the StdCellLib pointer in static TechModel instance
+        tech_model->setStdCellLib(std_cell_lib);
+
+        m_tech_model_ = tech_model;
+        Log::printLine("Config::constructTechModel - End");
+        return;
+    }
+} // namespace DSENT
+
diff --git a/ext/dsent/util/Config.h b/ext/dsent/util/Config.h
new file mode 100644 (file)
index 0000000..910f5ca
--- /dev/null
@@ -0,0 +1,40 @@
+#ifndef __DSENT_UTIL_CONFIG_H__
+#define __DSENT_UTIL_CONFIG_H__
+
+#include "util/CommonType.h"
+
+namespace DSENT
+{
+    class TechModel;
+    class StdCellLib;
+
+    class Config : public LibUtil::Config
+    {
+        public:
+            static void allocate(const String& cfg_file_name_);
+            static void release();
+            static Config* getSingleton();
+
+        protected:
+            static Config* ms_singleton_;
+
+        public:
+            Config();
+            ~Config();
+
+        public:
+            void setTechModel(const TechModel* tech_model_);
+            const TechModel* getTechModel() const;
+
+            void constructTechModel(const String& overwrite_str_);
+
+        protected:
+            void readFile(const String& file_name_);
+
+        protected:
+            const TechModel* m_tech_model_;
+    }; // class Config
+} // namespace DSENT
+
+#endif // __DSENT_UTIL_CONFIG_H__
+
diff --git a/ext/dsent/util/Constants.cc b/ext/dsent/util/Constants.cc
new file mode 100644 (file)
index 0000000..6af0a27
--- /dev/null
@@ -0,0 +1,20 @@
+
+#include "util/Constants.h"
+
+namespace DSENT
+{
+    // PI
+    const double Constants::pi = 3.14159;       //PI
+    // Boltzman's
+    const double Constants::k = 1.3806503e-23;  // m^2 * kg / (s^2 * K);
+    // Speed of light
+    const double Constants::c = 2.9979246e8;    // m/s
+    // Charge of electron
+    const double Constants::q = 1.602e-19;      // C
+    // Permitivity of free space
+    const double Constants::e0 = 8.85e-12;
+    // Permitivity ratio of silicon
+    const double Constants::es = 11.7;
+
+} // namespace DSENT
+
diff --git a/ext/dsent/util/Constants.h b/ext/dsent/util/Constants.h
new file mode 100644 (file)
index 0000000..4447e69
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef __DSENT_UTIL_CONSTANTS_H__
+#define __DSENT_UTIL_CONSTANTS_H__
+
+namespace DSENT
+{
+    class Constants
+    {
+        public:
+            // Physical constants
+            static const double pi;
+            static const double k;
+            static const double c;
+            static const double q;
+            static const double e0;
+            static const double es;
+    };
+
+} // namespace DSENT
+
+#endif // __DSENT_UTIL_CONSTANTS_H__
+
diff --git a/ext/dsent/util/Result.cc b/ext/dsent/util/Result.cc
new file mode 100644 (file)
index 0000000..f2a1b23
--- /dev/null
@@ -0,0 +1,249 @@
+#include "util/Result.h"
+
+#include <iostream>
+
+#include "libutil/Log.h"
+#include "libutil/Assert.h"
+
+namespace DSENT
+{
+    using std::ostream;
+    using std::endl;
+
+    Result::SubResult::SubResult(const Result* sub_result_, const String& producer_, double num_results_)
+        : m_result_(sub_result_), m_producer_(producer_), m_num_results_(num_results_)
+    {
+        // Check if the result is not a null pointer
+        ASSERT((sub_result_ != NULL), "Internal error: sub_result_ is null");
+
+        // Check if the number of results greater than 0
+        ASSERT((num_results_ >= 0), "Internal error: num_results_ (" + String(num_results_) + ") is less than 0");
+    }
+
+    Result::SubResult::~SubResult()
+    {}
+
+    const Result* Result::SubResult::getResult() const
+    {
+        return m_result_;
+    }
+
+    const String& Result::SubResult::getProducer() const
+    {
+        return m_producer_;
+    }
+
+    double Result::SubResult::getNumResults() const
+    {
+        return m_num_results_;
+    }
+
+    Result::SubResult* Result::SubResult::clone() const
+    {
+        return new SubResult(*this);
+    }
+
+    Result::SubResult::SubResult(const SubResult& sub_result_)
+        : m_result_(sub_result_.m_result_), m_producer_(sub_result_.m_producer_), m_num_results_(sub_result_.m_num_results_)
+    {}
+
+    Result::Result()
+    {}
+
+    Result::Result(const String& result_name_)
+        : m_result_name_(result_name_)
+    {}
+
+    Result::~Result()
+    {
+        // Clear all sub results
+        for(vector<SubResult*>::iterator it = m_sub_results_.begin(); 
+            it != m_sub_results_.end(); ++it)
+        {
+            SubResult* sub_result = (*it);
+            delete sub_result;
+        }
+    }
+
+    const String& Result::getName() const
+    {
+        return m_result_name_;
+    }
+
+    void Result::setValue(double /* value_ */)
+    {
+        throw LibUtil::Exception("[Error] " + getName() + " -> Cannot set the value of a non-atomic result!");
+        return;
+    }
+
+    void Result::addValue(double /* value_ */)
+    {
+        throw LibUtil::Exception("[Error] " + getName() + 
+                " -> Cannot add the value of a non-atomic result");
+        return;
+    }
+
+    double Result::getValue() const
+    {
+        throw LibUtil::Exception("[Error] " + getName() + " -> Cannot get the value of a non-atomic result!");
+        return 0.0;
+    }    
+    
+    void Result::addSubResult(const Result* sub_result_, const String& result_producer_, double num_results_)
+    {
+        SubResult* new_sub_result = new SubResult(sub_result_, result_producer_, num_results_);
+        m_sub_results_.push_back(new_sub_result);
+        return;
+    }
+
+    void Result::removeAllSubResults()
+    {
+        // Clear all sub results
+        for(vector<SubResult*>::iterator it = m_sub_results_.begin(); 
+            it != m_sub_results_.end(); ++it)
+        {
+            SubResult* sub_result = (*it);
+            delete sub_result;
+        }
+        m_sub_results_.clear();
+        return;
+    }
+
+    double Result::calculateSum() const
+    {
+        double sum = 0.0;
+
+        // Loop through all sub results and calculate the sum
+        for(vector<SubResult*>::const_iterator it = m_sub_results_.begin();
+            it != m_sub_results_.end(); ++it)
+        {
+            const SubResult* temp_sub_result = (*it);
+            const Result* temp_result = temp_sub_result->getResult();
+            double num_results = temp_sub_result->getNumResults();
+            sum += temp_result->calculateSum()*num_results;
+        }
+        return sum;
+    }
+
+    void Result::print(const String& prepend_str_, int detail_level_, ostream& ost_) const
+    {
+        print(prepend_str_, 1.0, detail_level_, ost_);
+        return;
+    }
+
+    Result* Result::clone() const
+    {
+        return new Result(*this);
+    }
+
+    Result::Result(const Result& result_)
+    {
+        // Copy the result name
+        m_result_name_ = result_.m_result_name_;
+
+        // Clone all sub results
+        for(vector<SubResult*>::const_iterator it = m_sub_results_.begin(); 
+            it != m_sub_results_.end(); ++it)
+        {
+            const SubResult* temp_sub_result = (*it);
+            SubResult* new_sub_result = temp_sub_result->clone();
+            m_sub_results_.push_back(new_sub_result);
+        }
+    }
+
+    void Result::print(const String& prepend_str_, double num_results_, int detail_level_, ostream& ost_) const
+    {
+        // Go down to lower level if detail_level_ > 0, else print the sthe sthe sthe sum
+        if(detail_level_ > 0)
+        {
+            for(vector<SubResult*>::const_iterator it = m_sub_results_.begin();
+                    it != m_sub_results_.end(); ++it)
+            {
+                const SubResult* temp_sub_result = (*it);
+                const Result* temp_result = temp_sub_result->getResult();
+                const String& temp_producer = temp_sub_result->getProducer();
+                const String& temp_result_name = temp_result->getName();
+                double temp_num_results = temp_sub_result->getNumResults();
+                String temp_prepend_str = prepend_str_ + "->" + temp_producer;
+
+                if(!temp_result_name.empty())
+                {
+                    temp_prepend_str += ":" + temp_result_name;
+                }
+                temp_result->print(temp_prepend_str, num_results_*temp_num_results, detail_level_ - 1, ost_);
+            }
+        }
+        else
+        {
+            ost_ << prepend_str_ << " = " << calculateSum()*num_results_;
+            ost_ << " (" << calculateSum() << " * " << num_results_ << ")" << endl;
+        }
+        return;
+    }
+
+    void Result::printHierarchy(const String& prepend_str_, int detail_level_, ostream& ost_) const
+    {
+        if(detail_level_ > 0)
+        {
+            for(vector<SubResult*>::const_iterator it = m_sub_results_.begin(); it != m_sub_results_.end(); ++it)
+            {
+                const SubResult* temp_sub_result = (*it);
+                const Result* temp_result = temp_sub_result->getResult();
+                const String& temp_producer = temp_sub_result->getProducer();
+                const String& temp_result_name = temp_result->getName();
+                String temp_prepend_str = prepend_str_ + "    ";
+
+                ost_ << prepend_str_ << " |--" << temp_producer << "->" << temp_result_name << endl;
+
+                temp_result->printHierarchy(temp_prepend_str, detail_level_ - 1, ost_);
+            }
+        }
+        return;
+    }
+
+    AtomicResult::AtomicResult(const String& result_name_, double value_)
+        : Result(result_name_), m_value_(value_)
+    {}
+
+    AtomicResult::~AtomicResult()
+    {}
+
+    void AtomicResult::setValue(double value_)
+    {
+        m_value_ = value_;
+        return;
+    }
+    
+    void AtomicResult::addValue(double value_)
+    {
+        m_value_ += value_;
+        return;
+    }
+
+    double AtomicResult::getValue() const
+    {
+        return m_value_;
+    }
+
+    double AtomicResult::calculateSum() const
+    {
+        return m_value_;
+    }
+
+    AtomicResult* AtomicResult::clone() const
+    {
+        return new AtomicResult(*this);
+    }
+
+    AtomicResult::AtomicResult(const AtomicResult& atomic_result_)
+        : Result(atomic_result_), m_value_(atomic_result_.m_value_)
+    {}
+
+    void AtomicResult::print(const String& prepend_str_, double num_results_, int /* detail_level_ */, ostream& ost_) const
+    {
+        ost_ << prepend_str_ << " = " << m_value_*num_results_;
+        ost_ << " (" << m_value_ << " * " << num_results_ << ")" << endl;
+        return;
+    }
+} // namespace DSENT
+
diff --git a/ext/dsent/util/Result.h b/ext/dsent/util/Result.h
new file mode 100644 (file)
index 0000000..96f0e58
--- /dev/null
@@ -0,0 +1,105 @@
+#ifndef __DSENT_UTIL_RESULT_H__
+#define __DSENT_UTIL_RESULT_H__
+
+#include <iostream>
+#include <vector>
+
+#include "libutil/String.h"
+#include "libutil/Map.h"
+
+namespace DSENT
+{
+    using std::ostream;
+    using std::vector;
+    using LibUtil::Map;
+    using LibUtil::String;
+
+    class Result
+    {
+        public:
+            class SubResult
+            {
+                public:
+                    SubResult(const Result* result_, const String& producer_, double num_results_);
+                    ~SubResult();
+
+                public:
+                    const Result* getResult() const;
+                    const String& getProducer() const;
+                    double getNumResults() const;
+
+                    SubResult* clone() const;
+
+                protected:
+                    SubResult(const SubResult& sub_result_);
+
+                private:
+                    // Pointer to the actual result
+                    const Result* m_result_;
+                    // Name of the instance that produces this result
+                    String m_producer_;
+                    // Number of the times this result should be produce
+                    double m_num_results_;
+            }; // class SubResult
+
+        public:
+            Result();
+            Result(const String& result_name_);
+            virtual ~Result();
+
+        public:
+            // Get the name of result
+            const String& getName() const;
+            // Add a sub result
+            void addSubResult(const Result* sub_result_, const String& result_producer_, double num_results_);
+            // Remove all sub results
+            void removeAllSubResults();
+            // Set the value of a result, not available except for AtomicResult
+            virtual void setValue(double value_);
+            // Set the value of a result, not available except for AtomicResult
+            virtual void addValue(double value_);
+            // Get the value of a result, not available except for AtomicResult
+            virtual double getValue() const;
+            // Loop through all sub results and calculate the sum
+            virtual double calculateSum() const;
+            // Print the result with hierarchy if detail_level_ > 0. Print the sum when detail_level_ <= 0
+            void print(const String& prepend_str_, int detail_level_, ostream& ost_) const;
+            // Print the tree of the results
+            void printHierarchy(const String& prepend_str_, int detail_level_, ostream& ost_) const;
+
+            Result* clone() const;
+
+        protected:
+            Result(const Result& result_);
+            virtual void print(const String& prepend_str_, double num_results_, int detail_level_, ostream& ost_) const;
+
+        private:
+            String m_result_name_;
+            vector<SubResult*> m_sub_results_;
+    }; // class Result
+
+    class AtomicResult : public Result
+    {
+        public:
+            AtomicResult(const String& result_name_, double value_ = 0.0);
+            ~AtomicResult();
+
+        public:
+            void setValue(double value_);
+            void addValue(double value_);
+            double getValue() const;
+            virtual double calculateSum() const;
+            AtomicResult* clone() const;
+
+        protected:
+            AtomicResult(const AtomicResult& atomic_result_);
+            virtual void print(const String& prepend_str_, double num_results_, int detail_level_, ostream& ost_) const;
+
+        private:
+            // Actual value of the result
+            double m_value_;
+    }; // class AtomicResult
+} // namespace DSENT
+
+#endif // __DSENT_UTIL_RESULT_H__
+