summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ext/dsent/DSENT.cc423
-rw-r--r--ext/dsent/DSENT.h64
-rw-r--r--ext/dsent/LICENSE19
-rw-r--r--ext/dsent/Makefile55
-rw-r--r--ext/dsent/README374
-rw-r--r--ext/dsent/configs/electrical-clos.cfg84
-rw-r--r--ext/dsent/configs/electrical-link.cfg57
-rw-r--r--ext/dsent/configs/electrical-mesh.cfg81
-rw-r--r--ext/dsent/configs/example.cfg40
-rw-r--r--ext/dsent/configs/photonic-clos.cfg112
-rw-r--r--ext/dsent/configs/photonic-link.cfg75
-rw-r--r--ext/dsent/configs/router.cfg131
-rw-r--r--ext/dsent/libutil/Assert.h22
-rw-r--r--ext/dsent/libutil/Calculator.cc239
-rw-r--r--ext/dsent/libutil/Calculator.h86
-rw-r--r--ext/dsent/libutil/Config.cc144
-rw-r--r--ext/dsent/libutil/Config.h37
-rw-r--r--ext/dsent/libutil/Exception.cc17
-rw-r--r--ext/dsent/libutil/Exception.h29
-rw-r--r--ext/dsent/libutil/LibUtil.h37
-rw-r--r--ext/dsent/libutil/Log.cc86
-rw-r--r--ext/dsent/libutil/Log.h43
-rw-r--r--ext/dsent/libutil/Makefile43
-rw-r--r--ext/dsent/libutil/Map.h242
-rw-r--r--ext/dsent/libutil/MathUtil.cc7
-rw-r--r--ext/dsent/libutil/MathUtil.h21
-rw-r--r--ext/dsent/libutil/OptionParser.cc177
-rw-r--r--ext/dsent/libutil/OptionParser.h57
-rw-r--r--ext/dsent/libutil/String.cc347
-rw-r--r--ext/dsent/libutil/String.h218
-rw-r--r--ext/dsent/main.cc10
-rw-r--r--ext/dsent/model/ElectricalModel.cc871
-rw-r--r--ext/dsent/model/ElectricalModel.h244
-rw-r--r--ext/dsent/model/EventInfo.cc86
-rw-r--r--ext/dsent/model/EventInfo.h32
-rw-r--r--ext/dsent/model/Model.cc698
-rw-r--r--ext/dsent/model/Model.h223
-rw-r--r--ext/dsent/model/ModelGen.cc306
-rw-r--r--ext/dsent/model/ModelGen.h30
-rw-r--r--ext/dsent/model/OpticalModel.cc277
-rw-r--r--ext/dsent/model/OpticalModel.h143
-rw-r--r--ext/dsent/model/PortInfo.cc35
-rw-r--r--ext/dsent/model/PortInfo.h37
-rw-r--r--ext/dsent/model/TransitionInfo.cc70
-rw-r--r--ext/dsent/model/TransitionInfo.h50
-rw-r--r--ext/dsent/model/electrical/BarrelShifter.cc241
-rw-r--r--ext/dsent/model/electrical/BarrelShifter.h34
-rw-r--r--ext/dsent/model/electrical/BroadcastHTree.cc400
-rw-r--r--ext/dsent/model/electrical/BroadcastHTree.h54
-rw-r--r--ext/dsent/model/electrical/DFFRAM.cc321
-rw-r--r--ext/dsent/model/electrical/DFFRAM.h33
-rw-r--r--ext/dsent/model/electrical/Decoder.cc235
-rw-r--r--ext/dsent/model/electrical/Decoder.h33
-rw-r--r--ext/dsent/model/electrical/DemuxTreeDeserializer.cc378
-rw-r--r--ext/dsent/model/electrical/DemuxTreeDeserializer.h33
-rw-r--r--ext/dsent/model/electrical/MatrixArbiter.cc434
-rw-r--r--ext/dsent/model/electrical/MatrixArbiter.h33
-rw-r--r--ext/dsent/model/electrical/Multiplexer.cc347
-rw-r--r--ext/dsent/model/electrical/Multiplexer.h34
-rw-r--r--ext/dsent/model/electrical/MultiplexerCrossbar.cc214
-rw-r--r--ext/dsent/model/electrical/MultiplexerCrossbar.h38
-rw-r--r--ext/dsent/model/electrical/MuxTreeSerializer.cc226
-rw-r--r--ext/dsent/model/electrical/MuxTreeSerializer.h33
-rw-r--r--ext/dsent/model/electrical/OR.cc239
-rw-r--r--ext/dsent/model/electrical/OR.h36
-rw-r--r--ext/dsent/model/electrical/RepeatedLink.cc305
-rw-r--r--ext/dsent/model/electrical/RepeatedLink.h44
-rw-r--r--ext/dsent/model/electrical/RippleAdder.cc106
-rw-r--r--ext/dsent/model/electrical/RippleAdder.h30
-rw-r--r--ext/dsent/model/electrical/SeparableAllocator.cc270
-rw-r--r--ext/dsent/model/electrical/SeparableAllocator.h33
-rw-r--r--ext/dsent/model/electrical/TestModel.cc218
-rw-r--r--ext/dsent/model/electrical/TestModel.h32
-rw-r--r--ext/dsent/model/electrical/router/Router.cc536
-rw-r--r--ext/dsent/model/electrical/router/Router.h46
-rw-r--r--ext/dsent/model/electrical/router/RouterInputPort.cc201
-rw-r--r--ext/dsent/model/electrical/router/RouterInputPort.h33
-rw-r--r--ext/dsent/model/electrical/router/RouterSwitchAllocator.cc199
-rw-r--r--ext/dsent/model/electrical/router/RouterSwitchAllocator.h33
-rw-r--r--ext/dsent/model/network/ElectricalClos.cc489
-rw-r--r--ext/dsent/model/network/ElectricalClos.h37
-rw-r--r--ext/dsent/model/network/ElectricalMesh.cc296
-rw-r--r--ext/dsent/model/network/ElectricalMesh.h37
-rw-r--r--ext/dsent/model/network/PhotonicClos.cc512
-rw-r--r--ext/dsent/model/network/PhotonicClos.h37
-rw-r--r--ext/dsent/model/optical/GatedLaserSource.cc106
-rw-r--r--ext/dsent/model/optical/GatedLaserSource.h33
-rw-r--r--ext/dsent/model/optical/LaserSource.cc105
-rw-r--r--ext/dsent/model/optical/LaserSource.h33
-rw-r--r--ext/dsent/model/optical/OpticalLinkBackendRx.cc364
-rw-r--r--ext/dsent/model/optical/OpticalLinkBackendRx.h39
-rw-r--r--ext/dsent/model/optical/OpticalLinkBackendTx.cc355
-rw-r--r--ext/dsent/model/optical/OpticalLinkBackendTx.h39
-rw-r--r--ext/dsent/model/optical/OpticalTestModel.cc121
-rw-r--r--ext/dsent/model/optical/OpticalTestModel.h30
-rw-r--r--ext/dsent/model/optical/RingDetector.cc338
-rw-r--r--ext/dsent/model/optical/RingDetector.h54
-rw-r--r--ext/dsent/model/optical/RingFilter.cc77
-rw-r--r--ext/dsent/model/optical/RingFilter.h30
-rw-r--r--ext/dsent/model/optical/RingModulator.cc403
-rw-r--r--ext/dsent/model/optical/RingModulator.h54
-rw-r--r--ext/dsent/model/optical/SWMRLink.cc309
-rw-r--r--ext/dsent/model/optical/SWMRLink.h38
-rw-r--r--ext/dsent/model/optical/SWSRLink.cc328
-rw-r--r--ext/dsent/model/optical/SWSRLink.h38
-rw-r--r--ext/dsent/model/optical/ThrottledLaserSource.cc137
-rw-r--r--ext/dsent/model/optical/ThrottledLaserSource.h40
-rw-r--r--ext/dsent/model/optical_graph/OpticalDetector.cc32
-rw-r--r--ext/dsent/model/optical_graph/OpticalDetector.h45
-rw-r--r--ext/dsent/model/optical_graph/OpticalFilter.cc65
-rw-r--r--ext/dsent/model/optical_graph/OpticalFilter.h48
-rw-r--r--ext/dsent/model/optical_graph/OpticalGraph.cc216
-rw-r--r--ext/dsent/model/optical_graph/OpticalGraph.h62
-rw-r--r--ext/dsent/model/optical_graph/OpticalLaser.cc31
-rw-r--r--ext/dsent/model/optical_graph/OpticalLaser.h32
-rw-r--r--ext/dsent/model/optical_graph/OpticalModulator.cc54
-rw-r--r--ext/dsent/model/optical_graph/OpticalModulator.h51
-rw-r--r--ext/dsent/model/optical_graph/OpticalNode.cc96
-rw-r--r--ext/dsent/model/optical_graph/OpticalNode.h92
-rw-r--r--ext/dsent/model/optical_graph/OpticalReceiver.h25
-rw-r--r--ext/dsent/model/optical_graph/OpticalTransmitter.h28
-rw-r--r--ext/dsent/model/optical_graph/OpticalWaveguide.cc20
-rw-r--r--ext/dsent/model/optical_graph/OpticalWaveguide.h27
-rw-r--r--ext/dsent/model/optical_graph/OpticalWavelength.cc129
-rw-r--r--ext/dsent/model/optical_graph/OpticalWavelength.h57
-rw-r--r--ext/dsent/model/std_cells/ADDF.cc671
-rw-r--r--ext/dsent/model/std_cells/ADDF.h39
-rw-r--r--ext/dsent/model/std_cells/AND2.cc272
-rw-r--r--ext/dsent/model/std_cells/AND2.h32
-rw-r--r--ext/dsent/model/std_cells/BUF.cc216
-rw-r--r--ext/dsent/model/std_cells/BUF.h33
-rw-r--r--ext/dsent/model/std_cells/CellMacros.cc477
-rw-r--r--ext/dsent/model/std_cells/CellMacros.h57
-rw-r--r--ext/dsent/model/std_cells/DFFQ.cc536
-rw-r--r--ext/dsent/model/std_cells/DFFQ.h38
-rw-r--r--ext/dsent/model/std_cells/INV.cc219
-rw-r--r--ext/dsent/model/std_cells/INV.h34
-rw-r--r--ext/dsent/model/std_cells/LATQ.cc380
-rw-r--r--ext/dsent/model/std_cells/LATQ.h34
-rw-r--r--ext/dsent/model/std_cells/MUX2.cc420
-rw-r--r--ext/dsent/model/std_cells/MUX2.h34
-rw-r--r--ext/dsent/model/std_cells/NAND2.cc267
-rw-r--r--ext/dsent/model/std_cells/NAND2.h33
-rw-r--r--ext/dsent/model/std_cells/NOR2.cc268
-rw-r--r--ext/dsent/model/std_cells/NOR2.h33
-rw-r--r--ext/dsent/model/std_cells/OR2.cc279
-rw-r--r--ext/dsent/model/std_cells/OR2.h33
-rw-r--r--ext/dsent/model/std_cells/StdCell.cc71
-rw-r--r--ext/dsent/model/std_cells/StdCell.h53
-rw-r--r--ext/dsent/model/std_cells/StdCellLib.cc180
-rw-r--r--ext/dsent/model/std_cells/StdCellLib.h63
-rw-r--r--ext/dsent/model/std_cells/XOR2.cc345
-rw-r--r--ext/dsent/model/std_cells/XOR2.h34
-rw-r--r--ext/dsent/model/timing_graph/ElectricalDelay.cc55
-rw-r--r--ext/dsent/model/timing_graph/ElectricalDelay.h43
-rw-r--r--ext/dsent/model/timing_graph/ElectricalDriver.cc95
-rw-r--r--ext/dsent/model/timing_graph/ElectricalDriver.h57
-rw-r--r--ext/dsent/model/timing_graph/ElectricalDriverMultiplier.cc53
-rw-r--r--ext/dsent/model/timing_graph/ElectricalDriverMultiplier.h42
-rw-r--r--ext/dsent/model/timing_graph/ElectricalLoad.cc49
-rw-r--r--ext/dsent/model/timing_graph/ElectricalLoad.h43
-rw-r--r--ext/dsent/model/timing_graph/ElectricalNet.cc73
-rw-r--r--ext/dsent/model/timing_graph/ElectricalNet.h50
-rw-r--r--ext/dsent/model/timing_graph/ElectricalTimingNode.cc174
-rw-r--r--ext/dsent/model/timing_graph/ElectricalTimingNode.h104
-rw-r--r--ext/dsent/model/timing_graph/ElectricalTimingOptimizer.cc73
-rw-r--r--ext/dsent/model/timing_graph/ElectricalTimingOptimizer.h30
-rw-r--r--ext/dsent/model/timing_graph/ElectricalTimingTree.cc247
-rw-r--r--ext/dsent/model/timing_graph/ElectricalTimingTree.h73
-rw-r--r--ext/dsent/tech/TechModel.cc320
-rw-r--r--ext/dsent/tech/TechModel.h71
-rw-r--r--ext/dsent/tech/tech_models/Bulk22LVT.model179
-rw-r--r--ext/dsent/tech/tech_models/Bulk32LVT.model168
-rw-r--r--ext/dsent/tech/tech_models/Bulk45LVT.model168
-rw-r--r--ext/dsent/tech/tech_models/Photonics.model89
-rw-r--r--ext/dsent/tech/tech_models/TG11LVT.model181
-rw-r--r--ext/dsent/util/CommonType.h36
-rw-r--r--ext/dsent/util/Config.cc105
-rw-r--r--ext/dsent/util/Config.h40
-rw-r--r--ext/dsent/util/Constants.cc20
-rw-r--r--ext/dsent/util/Constants.h21
-rw-r--r--ext/dsent/util/Result.cc249
-rw-r--r--ext/dsent/util/Result.h105
183 files changed, 25714 insertions, 0 deletions
diff --git a/ext/dsent/DSENT.cc b/ext/dsent/DSENT.cc
new file mode 100644
index 000000000..576cbbebc
--- /dev/null
+++ b/ext/dsent/DSENT.cc
@@ -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
index 000000000..42abb98e1
--- /dev/null
+++ b/ext/dsent/DSENT.h
@@ -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
index 000000000..eef8c8894
--- /dev/null
+++ b/ext/dsent/LICENSE
@@ -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
index 000000000..124188353
--- /dev/null
+++ b/ext/dsent/Makefile
@@ -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
index 000000000..0143a43ef
--- /dev/null
+++ b/ext/dsent/README
@@ -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
index 000000000..29888f754
--- /dev/null
+++ b/ext/dsent/configs/electrical-clos.cfg
@@ -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
index 000000000..8369b8633
--- /dev/null
+++ b/ext/dsent/configs/electrical-link.cfg
@@ -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
index 000000000..929e4f19c
--- /dev/null
+++ b/ext/dsent/configs/electrical-mesh.cfg
@@ -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
index 000000000..9e147b2d4
--- /dev/null
+++ b/ext/dsent/configs/example.cfg
@@ -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
index 000000000..252b49ab0
--- /dev/null
+++ b/ext/dsent/configs/photonic-clos.cfg
@@ -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
index 000000000..755e38bbc
--- /dev/null
+++ b/ext/dsent/configs/photonic-link.cfg
@@ -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
index 000000000..2e68b7e2c
--- /dev/null
+++ b/ext/dsent/configs/router.cfg
@@ -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
index 000000000..0fdd364b2
--- /dev/null
+++ b/ext/dsent/libutil/Assert.h
@@ -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
index 000000000..e78e67287
--- /dev/null
+++ b/ext/dsent/libutil/Calculator.cc
@@ -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
index 000000000..4fcdf471f
--- /dev/null
+++ b/ext/dsent/libutil/Calculator.h
@@ -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
index 000000000..f858c6926
--- /dev/null
+++ b/ext/dsent/libutil/Config.cc
@@ -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
index 000000000..a60c4b8fd
--- /dev/null
+++ b/ext/dsent/libutil/Config.h
@@ -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
index 000000000..c6db0e3fb
--- /dev/null
+++ b/ext/dsent/libutil/Exception.cc
@@ -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
index 000000000..88d68cce2
--- /dev/null
+++ b/ext/dsent/libutil/Exception.h
@@ -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
index 000000000..12eb76fa0
--- /dev/null
+++ b/ext/dsent/libutil/LibUtil.h
@@ -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
index 000000000..cb4266bf9
--- /dev/null
+++ b/ext/dsent/libutil/Log.cc
@@ -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
index 000000000..9c759e702
--- /dev/null
+++ b/ext/dsent/libutil/Log.h
@@ -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
index 000000000..150028346
--- /dev/null
+++ b/ext/dsent/libutil/Makefile
@@ -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
index 000000000..0352c8634
--- /dev/null
+++ b/ext/dsent/libutil/Map.h
@@ -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
index 000000000..0e177b5fc
--- /dev/null
+++ b/ext/dsent/libutil/MathUtil.cc
@@ -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
index 000000000..1f3341ee1
--- /dev/null
+++ b/ext/dsent/libutil/MathUtil.h
@@ -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
index 000000000..6d2695f2d
--- /dev/null
+++ b/ext/dsent/libutil/OptionParser.cc
@@ -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
index 000000000..b98012a80
--- /dev/null
+++ b/ext/dsent/libutil/OptionParser.h
@@ -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
index 000000000..146e9f824
--- /dev/null
+++ b/ext/dsent/libutil/String.cc
@@ -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
index 000000000..95fe17565
--- /dev/null
+++ b/ext/dsent/libutil/String.h
@@ -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
index 000000000..f826829b2
--- /dev/null
+++ b/ext/dsent/main.cc
@@ -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
index 000000000..469e26c9e
--- /dev/null
+++ b/ext/dsent/model/ElectricalModel.cc
@@ -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
index 000000000..15dfefd78
--- /dev/null
+++ b/ext/dsent/model/ElectricalModel.h
@@ -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
index 000000000..6bbe781e5
--- /dev/null
+++ b/ext/dsent/model/EventInfo.cc
@@ -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
index 000000000..646a6e18c
--- /dev/null
+++ b/ext/dsent/model/EventInfo.h
@@ -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
index 000000000..5a7bfe391
--- /dev/null
+++ b/ext/dsent/model/Model.cc
@@ -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
index 000000000..9e516d584
--- /dev/null
+++ b/ext/dsent/model/Model.h
@@ -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
index 000000000..06957d6fd
--- /dev/null
+++ b/ext/dsent/model/ModelGen.cc
@@ -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
index 000000000..c11f435d5
--- /dev/null
+++ b/ext/dsent/model/ModelGen.h
@@ -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
index 000000000..7236d6bda
--- /dev/null
+++ b/ext/dsent/model/OpticalModel.cc
@@ -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
index 000000000..0b4f27d37
--- /dev/null
+++ b/ext/dsent/model/OpticalModel.h
@@ -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
index 000000000..fd859fc7b
--- /dev/null
+++ b/ext/dsent/model/PortInfo.cc
@@ -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
index 000000000..68cd5dc19
--- /dev/null
+++ b/ext/dsent/model/PortInfo.h
@@ -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
index 000000000..ac4402060
--- /dev/null
+++ b/ext/dsent/model/TransitionInfo.cc
@@ -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
index 000000000..6f00cb86a
--- /dev/null
+++ b/ext/dsent/model/TransitionInfo.h
@@ -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
index 000000000..b951fc566
--- /dev/null
+++ b/ext/dsent/model/electrical/BarrelShifter.cc
@@ -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
index 000000000..e26ca9e91
--- /dev/null
+++ b/ext/dsent/model/electrical/BarrelShifter.h
@@ -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
index 000000000..efac128e7
--- /dev/null
+++ b/ext/dsent/model/electrical/BroadcastHTree.cc
@@ -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
index 000000000..f2c8d407b
--- /dev/null
+++ b/ext/dsent/model/electrical/BroadcastHTree.h
@@ -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
index 000000000..604aead2f
--- /dev/null
+++ b/ext/dsent/model/electrical/DFFRAM.cc
@@ -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
index 000000000..0e7626ecd
--- /dev/null
+++ b/ext/dsent/model/electrical/DFFRAM.h
@@ -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
index 000000000..7629bf8b2
--- /dev/null
+++ b/ext/dsent/model/electrical/Decoder.cc
@@ -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
index 000000000..3c09fc4ef
--- /dev/null
+++ b/ext/dsent/model/electrical/Decoder.h
@@ -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
index 000000000..4d74e8db2
--- /dev/null
+++ b/ext/dsent/model/electrical/DemuxTreeDeserializer.cc
@@ -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
index 000000000..216614193
--- /dev/null
+++ b/ext/dsent/model/electrical/DemuxTreeDeserializer.h
@@ -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
index 000000000..7f72abd63
--- /dev/null
+++ b/ext/dsent/model/electrical/MatrixArbiter.cc
@@ -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
index 000000000..59a6786ab
--- /dev/null
+++ b/ext/dsent/model/electrical/MatrixArbiter.h
@@ -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
index 000000000..f51f43b4c
--- /dev/null
+++ b/ext/dsent/model/electrical/Multiplexer.cc
@@ -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
index 000000000..845798b18
--- /dev/null
+++ b/ext/dsent/model/electrical/Multiplexer.h
@@ -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
index 000000000..7400d5ed2
--- /dev/null
+++ b/ext/dsent/model/electrical/MultiplexerCrossbar.cc
@@ -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
index 000000000..e7f092061
--- /dev/null
+++ b/ext/dsent/model/electrical/MultiplexerCrossbar.h
@@ -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
index 000000000..8f3b92122
--- /dev/null
+++ b/ext/dsent/model/electrical/MuxTreeSerializer.cc
@@ -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
index 000000000..f56cccc4f
--- /dev/null
+++ b/ext/dsent/model/electrical/MuxTreeSerializer.h
@@ -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
index 000000000..d948ff086
--- /dev/null
+++ b/ext/dsent/model/electrical/OR.cc
@@ -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
index 000000000..b8304799c
--- /dev/null
+++ b/ext/dsent/model/electrical/OR.h
@@ -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
index 000000000..08a40e432
--- /dev/null
+++ b/ext/dsent/model/electrical/RepeatedLink.cc
@@ -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
index 000000000..1cd8e3412
--- /dev/null
+++ b/ext/dsent/model/electrical/RepeatedLink.h
@@ -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
index 000000000..779cd4798
--- /dev/null
+++ b/ext/dsent/model/electrical/RippleAdder.cc
@@ -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
index 000000000..6f5f71072
--- /dev/null
+++ b/ext/dsent/model/electrical/RippleAdder.h
@@ -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
index 000000000..e0965cbe9
--- /dev/null
+++ b/ext/dsent/model/electrical/SeparableAllocator.cc
@@ -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
index 000000000..21519bf38
--- /dev/null
+++ b/ext/dsent/model/electrical/SeparableAllocator.h
@@ -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
index 000000000..24f1fab43
--- /dev/null
+++ b/ext/dsent/model/electrical/TestModel.cc
@@ -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
index 000000000..5e07ea30c
--- /dev/null
+++ b/ext/dsent/model/electrical/TestModel.h
@@ -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
index 000000000..c079bd1d5
--- /dev/null
+++ b/ext/dsent/model/electrical/router/Router.cc
@@ -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
index 000000000..c2c1df3bc
--- /dev/null
+++ b/ext/dsent/model/electrical/router/Router.h
@@ -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
index 000000000..b698d3d80
--- /dev/null
+++ b/ext/dsent/model/electrical/router/RouterInputPort.cc
@@ -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
index 000000000..1d326a5cf
--- /dev/null
+++ b/ext/dsent/model/electrical/router/RouterInputPort.h
@@ -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
index 000000000..92e5431b1
--- /dev/null
+++ b/ext/dsent/model/electrical/router/RouterSwitchAllocator.cc
@@ -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
index 000000000..8b18e199f
--- /dev/null
+++ b/ext/dsent/model/electrical/router/RouterSwitchAllocator.h
@@ -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
index 000000000..94781d886
--- /dev/null
+++ b/ext/dsent/model/network/ElectricalClos.cc
@@ -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
index 000000000..c6a1f8063
--- /dev/null
+++ b/ext/dsent/model/network/ElectricalClos.h
@@ -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
index 000000000..5ad544eb5
--- /dev/null
+++ b/ext/dsent/model/network/ElectricalMesh.cc
@@ -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
index 000000000..de89a8f80
--- /dev/null
+++ b/ext/dsent/model/network/ElectricalMesh.h
@@ -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
index 000000000..1b0868ebc
--- /dev/null
+++ b/ext/dsent/model/network/PhotonicClos.cc
@@ -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
index 000000000..814885dd7
--- /dev/null
+++ b/ext/dsent/model/network/PhotonicClos.h
@@ -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
index 000000000..e32474daf
--- /dev/null
+++ b/ext/dsent/model/optical/GatedLaserSource.cc
@@ -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
index 000000000..b6413b047
--- /dev/null
+++ b/ext/dsent/model/optical/GatedLaserSource.h
@@ -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
index 000000000..e55de8cf7
--- /dev/null
+++ b/ext/dsent/model/optical/LaserSource.cc
@@ -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
index 000000000..92c7658d5
--- /dev/null
+++ b/ext/dsent/model/optical/LaserSource.h
@@ -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
index 000000000..3a65cee62
--- /dev/null
+++ b/ext/dsent/model/optical/OpticalLinkBackendRx.cc
@@ -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
index 000000000..19f396664
--- /dev/null
+++ b/ext/dsent/model/optical/OpticalLinkBackendRx.h
@@ -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
index 000000000..18d86cfe7
--- /dev/null
+++ b/ext/dsent/model/optical/OpticalLinkBackendTx.cc
@@ -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
index 000000000..a3e596403
--- /dev/null
+++ b/ext/dsent/model/optical/OpticalLinkBackendTx.h
@@ -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
index 000000000..c821c4841
--- /dev/null
+++ b/ext/dsent/model/optical/OpticalTestModel.cc
@@ -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
index 000000000..06a80e955
--- /dev/null
+++ b/ext/dsent/model/optical/OpticalTestModel.h
@@ -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
index 000000000..4baf2f68f
--- /dev/null
+++ b/ext/dsent/model/optical/RingDetector.cc
@@ -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
index 000000000..e18b2fe75
--- /dev/null
+++ b/ext/dsent/model/optical/RingDetector.h
@@ -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
index 000000000..5f0bd5b40
--- /dev/null
+++ b/ext/dsent/model/optical/RingFilter.cc
@@ -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
index 000000000..87fcb8c04
--- /dev/null
+++ b/ext/dsent/model/optical/RingFilter.h
@@ -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
index 000000000..8fe320fbd
--- /dev/null
+++ b/ext/dsent/model/optical/RingModulator.cc
@@ -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
index 000000000..bbfa7f4ee
--- /dev/null
+++ b/ext/dsent/model/optical/RingModulator.h
@@ -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
index 000000000..56d2d70b3
--- /dev/null
+++ b/ext/dsent/model/optical/SWMRLink.cc
@@ -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
index 000000000..a2618358c
--- /dev/null
+++ b/ext/dsent/model/optical/SWMRLink.h
@@ -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
index 000000000..88973e392
--- /dev/null
+++ b/ext/dsent/model/optical/SWSRLink.cc
@@ -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
index 000000000..fd6ecca73
--- /dev/null
+++ b/ext/dsent/model/optical/SWSRLink.h
@@ -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
index 000000000..e95188b77
--- /dev/null
+++ b/ext/dsent/model/optical/ThrottledLaserSource.cc
@@ -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
index 000000000..117465419
--- /dev/null
+++ b/ext/dsent/model/optical/ThrottledLaserSource.h
@@ -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
index 000000000..8de005099
--- /dev/null
+++ b/ext/dsent/model/optical_graph/OpticalDetector.cc
@@ -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
index 000000000..e3994f176
--- /dev/null
+++ b/ext/dsent/model/optical_graph/OpticalDetector.h
@@ -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
index 000000000..1bac9a8c9
--- /dev/null
+++ b/ext/dsent/model/optical_graph/OpticalFilter.cc
@@ -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
index 000000000..e908618e4
--- /dev/null
+++ b/ext/dsent/model/optical_graph/OpticalFilter.h
@@ -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
index 000000000..424f2bcb2
--- /dev/null
+++ b/ext/dsent/model/optical_graph/OpticalGraph.cc
@@ -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
index 000000000..43dab1bf8
--- /dev/null
+++ b/ext/dsent/model/optical_graph/OpticalGraph.h
@@ -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
index 000000000..8b25f90bd
--- /dev/null
+++ b/ext/dsent/model/optical_graph/OpticalLaser.cc
@@ -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
index 000000000..911517e1d
--- /dev/null
+++ b/ext/dsent/model/optical_graph/OpticalLaser.h
@@ -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
index 000000000..662560341
--- /dev/null
+++ b/ext/dsent/model/optical_graph/OpticalModulator.cc
@@ -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
index 000000000..416c2a0f3
--- /dev/null
+++ b/ext/dsent/model/optical_graph/OpticalModulator.h
@@ -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
index 000000000..89e034b09
--- /dev/null
+++ b/ext/dsent/model/optical_graph/OpticalNode.cc
@@ -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
index 000000000..bb88d2da1
--- /dev/null
+++ b/ext/dsent/model/optical_graph/OpticalNode.h
@@ -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
index 000000000..11c940522
--- /dev/null
+++ b/ext/dsent/model/optical_graph/OpticalReceiver.h
@@ -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
index 000000000..235d88880
--- /dev/null
+++ b/ext/dsent/model/optical_graph/OpticalTransmitter.h
@@ -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
index 000000000..7e35a18aa
--- /dev/null
+++ b/ext/dsent/model/optical_graph/OpticalWaveguide.cc
@@ -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
index 000000000..6fd03bcf3
--- /dev/null
+++ b/ext/dsent/model/optical_graph/OpticalWaveguide.h
@@ -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
index 000000000..fa5e36f63
--- /dev/null
+++ b/ext/dsent/model/optical_graph/OpticalWavelength.cc
@@ -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
index 000000000..6a5f31e9a
--- /dev/null
+++ b/ext/dsent/model/optical_graph/OpticalWavelength.h
@@ -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
index 000000000..99ebcdb6b
--- /dev/null
+++ b/ext/dsent/model/std_cells/ADDF.cc
@@ -0,0 +1,671 @@
+#include "model/std_cells/ADDF.h"
+
+#include <cmath>
+
+#include "model/PortInfo.h"
+#include "model/EventInfo.h"
+#include "model/TransitionInfo.h"
+#include "model/std_cells/StdCellLib.h"
+#include "model/std_cells/CellMacros.h"
+#include "model/timing_graph/ElectricalNet.h"
+#include "model/timing_graph/ElectricalDriver.h"
+#include "model/timing_graph/ElectricalLoad.h"
+#include "model/timing_graph/ElectricalDelay.h"
+
+namespace DSENT
+{
+ using std::ceil;
+ using std::max;
+
+ ADDF::ADDF(const String& instance_name_, const TechModel* tech_model_)
+ : StdCell(instance_name_, tech_model_)
+ {
+ initParameters();
+ initProperties();
+ }
+
+ ADDF::~ADDF()
+ {}
+
+ void ADDF::initProperties()
+ {
+ return;
+ }
+
+ void ADDF::constructModel()
+ {
+ // All constructModel should do is create Area/NDDPower/Energy Results as
+ // well as instantiate any sub-instances using only the hard parameters
+
+ createInputPort("A");
+ createInputPort("B");
+ createInputPort("CI");
+ createOutputPort("S");
+ createOutputPort("CO");
+
+ createLoad("A_Cap");
+ createLoad("B_Cap");
+ createLoad("CI_Cap");
+ createDelay("A_to_S_delay");
+ createDelay("B_to_S_delay");
+ createDelay("CI_to_S_delay");
+ createDelay("A_to_CO_delay");
+ createDelay("B_to_CO_delay");
+ createDelay("CI_to_CO_delay");
+ createDriver("S_Ron", true);
+ createDriver("CO_Ron", true);
+
+ ElectricalLoad* a_cap = getLoad("A_Cap");
+ ElectricalLoad* b_cap = getLoad("B_Cap");
+ ElectricalLoad* ci_cap = getLoad("CI_Cap");
+ ElectricalDelay* a_to_s_delay = getDelay("A_to_S_delay");
+ ElectricalDelay* b_to_s_delay = getDelay("B_to_S_delay");
+ ElectricalDelay* ci_to_s_delay = getDelay("CI_to_S_delay");
+ ElectricalDelay* a_to_co_delay = getDelay("A_to_CO_delay");
+ ElectricalDelay* b_to_co_delay = getDelay("B_to_CO_delay");
+ ElectricalDelay* ci_to_co_delay = getDelay("CI_to_CO_delay");
+ ElectricalDriver* s_ron = getDriver("S_Ron");
+ ElectricalDriver* co_ron = getDriver("CO_Ron");
+
+ getNet("A")->addDownstreamNode(a_cap);
+ getNet("B")->addDownstreamNode(b_cap);
+ getNet("CI")->addDownstreamNode(ci_cap);
+ a_cap->addDownstreamNode(a_to_s_delay);
+ b_cap->addDownstreamNode(b_to_s_delay);
+ ci_cap->addDownstreamNode(ci_to_s_delay);
+ a_cap->addDownstreamNode(a_to_co_delay);
+ b_cap->addDownstreamNode(b_to_co_delay);
+ ci_cap->addDownstreamNode(ci_to_co_delay);
+
+ a_to_s_delay->addDownstreamNode(s_ron);
+ b_to_s_delay->addDownstreamNode(s_ron);
+ ci_to_s_delay->addDownstreamNode(s_ron);
+ a_to_co_delay->addDownstreamNode(co_ron);
+ b_to_co_delay->addDownstreamNode(co_ron);
+ ci_to_co_delay->addDownstreamNode(co_ron);
+
+ s_ron->addDownstreamNode(getNet("S"));
+ co_ron->addDownstreamNode(getNet("CO"));
+
+ // Create Area result
+ // Create NDD Power result
+ createElectricalAtomicResults();
+ // Create ADDF Event Energy Result
+ createElectricalEventAtomicResult("ADDF");
+
+ getEventInfo("Idle")->setStaticTransitionInfos();
+
+ return;
+ }
+
+ void ADDF::updateModel()
+ {
+ // Get parameters
+ double drive_strength = getDrivingStrength();
+ Map<double>* cache = getTechModel()->getStdCellLib()->getStdCellCache();
+
+ // Standard cell cache string
+ String cell_name = "ADDF_X" + (String) drive_strength;
+
+ // Get timing parameters
+ getLoad("A_Cap")->setLoadCap(cache->get(cell_name + "->Cap->A"));
+ getLoad("B_Cap")->setLoadCap(cache->get(cell_name + "->Cap->B"));
+ getLoad("CI_Cap")->setLoadCap(cache->get(cell_name + "->Cap->CI"));
+
+ getDelay("A_to_S_delay")->setDelay(cache->get(cell_name + "->Delay->A_to_S"));
+ getDelay("B_to_S_delay")->setDelay(cache->get(cell_name + "->Delay->B_to_S"));
+ getDelay("CI_to_S_delay")->setDelay(cache->get(cell_name + "->Delay->CI_to_S"));
+ getDelay("A_to_CO_delay")->setDelay(cache->get(cell_name + "->Delay->A_to_CO"));
+ getDelay("B_to_CO_delay")->setDelay(cache->get(cell_name + "->Delay->B_to_CO"));
+ getDelay("CI_to_CO_delay")->setDelay(cache->get(cell_name + "->Delay->CI_to_CO"));
+
+ getDriver("S_Ron")->setOutputRes(cache->get(cell_name + "->DriveRes->S"));
+ getDriver("CO_Ron")->setOutputRes(cache->get(cell_name + "->DriveRes->CO"));
+
+ // Set the cell area
+ getAreaResult("Active")->setValue(cache->get(cell_name + "->Area->Active"));
+ getAreaResult("Metal1Wire")->setValue(cache->get(cell_name + "->Area->Metal1Wire"));
+
+ return;
+ }
+
+ void ADDF::evaluateModel()
+ {
+ return;
+ }
+
+ void ADDF::useModel()
+ {
+ // Get parameters
+ double drive_strength = getDrivingStrength();
+ Map<double>* cache = getTechModel()->getStdCellLib()->getStdCellCache();
+
+ // Standard cell cache string
+ String cell_name = "ADDF_X" + (String) drive_strength;
+
+ // Propagate the transition info and get the 0->1 transition count
+ propagateTransitionInfo();
+ double P_A = getInputPort("A")->getTransitionInfo().getProbability1();
+ double P_B = getInputPort("B")->getTransitionInfo().getProbability1();
+ double P_CI = getInputPort("CI")->getTransitionInfo().getProbability1();
+ double A_num_trans_01 = getInputPort("A")->getTransitionInfo().getNumberTransitions01();
+ double B_num_trans_01 = getInputPort("B")->getTransitionInfo().getNumberTransitions01();
+ double CI_num_trans_01 = getInputPort("CI")->getTransitionInfo().getNumberTransitions01();
+ double P_num_trans_01 = m_trans_P_.getNumberTransitions01();
+ double G_num_trans_01 = m_trans_G_.getNumberTransitions01();
+ double CP_num_trans_01 = m_trans_CP_.getNumberTransitions01();
+ double S_num_trans_01 = getOutputPort("S")->getTransitionInfo().getNumberTransitions01();
+ double CO_num_trans_01 = getOutputPort("CO")->getTransitionInfo().getNumberTransitions01();
+
+ // Calculate leakage
+ double leakage = 0;
+ leakage += cache->get(cell_name + "->Leakage->!A!B!CI") * (1 - P_A) * (1 - P_B) * (1 - P_CI);
+ leakage += cache->get(cell_name + "->Leakage->!A!BCI") * (1 - P_A) * (1 - P_B) * P_CI;
+ leakage += cache->get(cell_name + "->Leakage->!AB!CI") * (1 - P_A) * P_B * (1 - P_CI);
+ leakage += cache->get(cell_name + "->Leakage->!ABCI") * (1 - P_A) * P_B * P_CI;
+ leakage += cache->get(cell_name + "->Leakage->A!B!CI") * P_A * (1 - P_B) * (1 - P_CI);
+ leakage += cache->get(cell_name + "->Leakage->A!BCI") * P_A * (1 - P_B) * P_CI;
+ leakage += cache->get(cell_name + "->Leakage->AB!CI") * P_A * P_B * (1 - P_CI);
+ leakage += cache->get(cell_name + "->Leakage->ABCI") * P_A * P_B * P_CI;
+ getNddPowerResult("Leakage")->setValue(leakage);
+
+ // Get VDD
+ double vdd = getTechModel()->get("Vdd");
+
+ // Get capacitances
+ double a_b_cap = cache->get(cell_name + "->Cap->A_b");
+ double b_b_cap = cache->get(cell_name + "->Cap->B_b");
+ double ci_b_cap = cache->get(cell_name + "->Cap->CI_b");
+ double p_cap = cache->get(cell_name + "->Cap->P");
+ double p_b_cap = cache->get(cell_name + "->Cap->P_b");
+ double s_cap = cache->get(cell_name + "->Cap->S");
+ double cp_cap = cache->get(cell_name + "->Cap->CP");
+ double g_cap = cache->get(cell_name + "->Cap->G");
+ double co_cap = cache->get(cell_name + "->Cap->CO");
+ double s_load_cap = getNet("S")->getTotalDownstreamCap();
+ double co_load_cap = getNet("CO")->getTotalDownstreamCap();
+
+ // Calculate ADDF Event energy
+ double addf_event_energy = 0.0;
+ addf_event_energy += a_b_cap * A_num_trans_01;
+ addf_event_energy += b_b_cap * B_num_trans_01;
+ addf_event_energy += ci_b_cap * CI_num_trans_01;
+ addf_event_energy += (p_cap + p_b_cap) * P_num_trans_01;
+ addf_event_energy += (s_cap + s_load_cap) * S_num_trans_01;
+ addf_event_energy += cp_cap * CP_num_trans_01;
+ addf_event_energy += g_cap * G_num_trans_01;
+ addf_event_energy += (co_cap + co_load_cap) * CO_num_trans_01;
+ addf_event_energy *= vdd * vdd;
+ getEventResult("ADDF")->setValue(addf_event_energy);
+
+ return;
+ }
+
+ void ADDF::propagateTransitionInfo()
+ {
+ const TransitionInfo& trans_A = getInputPort("A")->getTransitionInfo();
+ const TransitionInfo& trans_B = getInputPort("B")->getTransitionInfo();
+ const TransitionInfo& trans_CI = getInputPort("CI")->getTransitionInfo();
+
+ double max_freq_mult = max(max(trans_A.getFrequencyMultiplier(), trans_B.getFrequencyMultiplier()), trans_CI.getFrequencyMultiplier());
+ const TransitionInfo& scaled_trans_A = trans_A.scaleFrequencyMultiplier(max_freq_mult);
+ const TransitionInfo& scaled_trans_B = trans_B.scaleFrequencyMultiplier(max_freq_mult);
+ const TransitionInfo& scaled_trans_CI = trans_CI.scaleFrequencyMultiplier(max_freq_mult);
+
+ double A_prob_00 = scaled_trans_A.getNumberTransitions00() / max_freq_mult;
+ double A_prob_01 = scaled_trans_A.getNumberTransitions01() / max_freq_mult;
+ double A_prob_10 = A_prob_01;
+ double A_prob_11 = scaled_trans_A.getNumberTransitions11() / max_freq_mult;
+ double B_prob_00 = scaled_trans_B.getNumberTransitions00() / max_freq_mult;
+ double B_prob_01 = scaled_trans_B.getNumberTransitions01() / max_freq_mult;
+ double B_prob_10 = B_prob_01;
+ double B_prob_11 = scaled_trans_B.getNumberTransitions11() / max_freq_mult;
+ double CI_prob_00 = scaled_trans_CI.getNumberTransitions00() / max_freq_mult;
+ double CI_prob_01 = scaled_trans_CI.getNumberTransitions01() / max_freq_mult;
+ double CI_prob_10 = CI_prob_01;
+ double CI_prob_11 = scaled_trans_CI.getNumberTransitions11() / max_freq_mult;
+
+ // Set P transition info
+ double P_prob_00 = A_prob_00 * B_prob_00 +
+ A_prob_01 * B_prob_01 +
+ A_prob_10 * B_prob_10 +
+ A_prob_11 * B_prob_11;
+ double P_prob_01 = A_prob_00 * B_prob_01 +
+ A_prob_01 * B_prob_00 +
+ A_prob_10 * B_prob_11 +
+ A_prob_11 * B_prob_10;
+ double P_prob_10 = P_prob_01;
+ double P_prob_11 = A_prob_00 * B_prob_11 +
+ A_prob_01 * B_prob_10 +
+ A_prob_10 * B_prob_01 +
+ A_prob_11 * B_prob_00;
+
+ // Set G transition info
+ double G_prob_00 = A_prob_11 * B_prob_11;
+ double G_prob_01 = A_prob_11 * B_prob_10 +
+ A_prob_10 * (B_prob_11 + B_prob_10);
+ double G_prob_10 = G_prob_01;
+ double G_prob_11 = A_prob_00 +
+ A_prob_01 * (B_prob_00 + B_prob_10) +
+ A_prob_10 * (B_prob_00 + B_prob_01) +
+ A_prob_11 * B_prob_00;
+
+ // Set CP transition info
+ double CP_prob_00 = P_prob_11 * CI_prob_11;
+ double CP_prob_01 = P_prob_11 * CI_prob_10 +
+ P_prob_10 * (CI_prob_11 + CI_prob_10);
+ double CP_prob_10 = CP_prob_01;
+ double CP_prob_11 = P_prob_00 +
+ P_prob_01 * (CI_prob_00 + CI_prob_10) +
+ P_prob_10 * (CI_prob_00 + CI_prob_01) +
+ P_prob_11 * CI_prob_00;
+
+ // Set S transition info
+ double S_prob_00 = P_prob_00 * CI_prob_00 +
+ P_prob_01 * CI_prob_01 +
+ P_prob_10 * CI_prob_10 +
+ P_prob_11 * CI_prob_11;
+ double S_prob_01 = P_prob_00 * CI_prob_01 +
+ P_prob_01 * CI_prob_00 +
+ P_prob_10 * CI_prob_11 +
+ P_prob_11 * CI_prob_10;
+ double S_prob_11 = P_prob_00 * CI_prob_11 +
+ P_prob_01 * CI_prob_10 +
+ P_prob_10 * CI_prob_01 +
+ P_prob_11 * CI_prob_00;
+
+ // Set CO transition info
+ double CO_prob_00 = G_prob_11 * CP_prob_11;
+ double CO_prob_01 = G_prob_11 * CP_prob_10 +
+ G_prob_10 * (CP_prob_11 + CP_prob_10);
+ double CO_prob_11 = G_prob_00 +
+ G_prob_01 * (CP_prob_00 + CP_prob_10) +
+ G_prob_10 * (CP_prob_00 + CP_prob_01) +
+ G_prob_11 * CP_prob_00;
+
+ m_trans_P_ = TransitionInfo(P_prob_00 * max_freq_mult, P_prob_01 * max_freq_mult, P_prob_11 * max_freq_mult);
+ m_trans_G_ = TransitionInfo(G_prob_00 * max_freq_mult, G_prob_01 * max_freq_mult, G_prob_11 * max_freq_mult);
+ m_trans_CP_ = TransitionInfo(CP_prob_00 * max_freq_mult, CP_prob_01 * max_freq_mult, CP_prob_11 * max_freq_mult);
+
+ // Check that probabilities add up to 1.0 with some finite tolerance
+ ASSERT(LibUtil::Math::isEqual((S_prob_00 + S_prob_01 + S_prob_01 + S_prob_11), 1.0),
+ "[Error] " + getInstanceName() + "Output S transition probabilities must add up to 1 (" +
+ (String) S_prob_00 + ", " + (String) S_prob_01 + ", " + (String) S_prob_11 + ")!");
+
+ // Check that probabilities add up to 1.0 with some finite tolerance
+ ASSERT(LibUtil::Math::isEqual((CO_prob_00 + CO_prob_01 + CO_prob_01 + CO_prob_11), 1.0),
+ "[Error] " + getInstanceName() + "Output S transition probabilities must add up to 1 (" +
+ (String) CO_prob_00 + ", " + (String) CO_prob_01 + ", " + (String) CO_prob_11 + ")!");
+
+ // Turn probability of transitions per cycle into number of transitions per time unit
+ TransitionInfo trans_S(S_prob_00 * max_freq_mult, S_prob_01 * max_freq_mult, S_prob_11 * max_freq_mult);
+ getOutputPort("S")->setTransitionInfo(trans_S);
+ TransitionInfo trans_CO(CO_prob_00 * max_freq_mult, CO_prob_01 * max_freq_mult, CO_prob_11 * max_freq_mult);
+ getOutputPort("CO")->setTransitionInfo(trans_CO);
+ return;
+ }
+
+ // Creates the standard cell, characterizes and abstracts away the details
+ void ADDF::cacheStdCell(StdCellLib* cell_lib_, double drive_strength_)
+ {
+ // Get parameters
+ double gate_pitch = cell_lib_->getTechModel()->get("Gate->PitchContacted");
+ Map<double>* cache = cell_lib_->getStdCellCache();
+
+ // Standard cell cache string
+ String cell_name = "ADDF_X" + (String) drive_strength_;
+
+ Log::printLine("=== " + cell_name + " ===");
+
+ // Now actually build the full standard cell model
+ createInputPort("A");
+ createInputPort("B");
+ createInputPort("CI");
+ createOutputPort("S");
+ createOutputPort("CO");
+
+ createNet("A_b");
+ createNet("B_b");
+ createNet("CI_b");
+ createNet("P");
+ createNet("P_b");
+ createNet("G"); //actually G_b since it is NAND'ed
+ createNet("CP"); //actually (CP)_b since it is NAND'ed
+
+ // Adds macros
+ CellMacros::addInverter(this, "INV1", false, true, "A", "A_b");
+ CellMacros::addInverter(this, "INV2", false, true, "B", "B_b");
+ CellMacros::addInverter(this, "INV3", false, true, "CI", "CI_b");
+ CellMacros::addInverter(this, "INV4", false, true, "P", "P_b");
+ CellMacros::addTristate(this, "INVZ1", false, true, true, true, "B", "A", "A_b", "P");
+ CellMacros::addTristate(this, "INVZ2", false, true, true, true, "B_b", "A_b", "A", "P");
+ CellMacros::addTristate(this, "INVZ3", true, true, true, true, "P", "CI", "CI_b", "S");
+ CellMacros::addTristate(this, "INVZ4", true, true, true, true, "P_b", "CI_b", "CI", "S");
+ CellMacros::addNand2(this, "NAND1", false, true, true, "CI", "P", "CP");
+ CellMacros::addNand2(this, "NAND2", false, true, true, "A", "B", "G");
+ CellMacros::addNand2(this, "NAND3", true, true, true, "CP", "G", "CO");
+
+ // I have no idea how to size each of the parts haha
+ CellMacros::updateInverter(this, "INV1", drive_strength_ * 0.250);
+ CellMacros::updateInverter(this, "INV2", drive_strength_ * 0.250);
+ CellMacros::updateInverter(this, "INV3", drive_strength_ * 0.250);
+ CellMacros::updateInverter(this, "INV4", drive_strength_ * 0.500);
+ CellMacros::updateTristate(this, "INVZ1", drive_strength_ * 0.250);
+ CellMacros::updateTristate(this, "INVZ2", drive_strength_ * 0.250);
+ CellMacros::updateTristate(this, "INVZ3", drive_strength_ * 0.500);
+ CellMacros::updateTristate(this, "INVZ4", drive_strength_ * 0.500);
+ CellMacros::updateNand2(this, "NAND1", drive_strength_ * 0.500);
+ CellMacros::updateNand2(this, "NAND2", drive_strength_ * 0.500);
+ CellMacros::updateNand2(this, "NAND3", drive_strength_ * 1.000);
+
+ // Cache area result
+ double area = 0.0;
+ area += gate_pitch * getTotalHeight() * 1;
+ area += gate_pitch * getTotalHeight() * getGenProperties()->get("INV1_GatePitches").toDouble();
+ area += gate_pitch * getTotalHeight() * getGenProperties()->get("INV2_GatePitches").toDouble();
+ area += gate_pitch * getTotalHeight() * getGenProperties()->get("INV3_GatePitches").toDouble();
+ area += gate_pitch * getTotalHeight() * getGenProperties()->get("INV4_GatePitches").toDouble();
+ area += gate_pitch * getTotalHeight() * getGenProperties()->get("INVZ1_GatePitches").toDouble();
+ area += gate_pitch * getTotalHeight() * getGenProperties()->get("INVZ2_GatePitches").toDouble();
+ area += gate_pitch * getTotalHeight() * getGenProperties()->get("INVZ3_GatePitches").toDouble();
+ area += gate_pitch * getTotalHeight() * getGenProperties()->get("INVZ4_GatePitches").toDouble();
+ area += gate_pitch * getTotalHeight() * getGenProperties()->get("NAND1_GatePitches").toDouble();
+ area += gate_pitch * getTotalHeight() * getGenProperties()->get("NAND2_GatePitches").toDouble();
+ area += gate_pitch * getTotalHeight() * getGenProperties()->get("NAND3_GatePitches").toDouble();
+ cache->set(cell_name + "->Area->Active", area);
+ cache->set(cell_name + "->Area->Metal1Wire", area);
+ Log::printLine(cell_name + "->Area->Active=" + (String) area);
+ Log::printLine(cell_name + "->Area->Metal1Wire=" + (String) area);
+
+ // --------------------------------------------------------------------
+ // Leakage Model Calculation
+ // --------------------------------------------------------------------
+ // Cache leakage power results (for every single signal combination)
+ double leakage_000 = 0; //!A, !B, !CI
+ double leakage_001 = 0; //!A, !B, CI
+ double leakage_010 = 0; //!A, B, !CI
+ double leakage_011 = 0; //!A, B, CI
+ double leakage_100 = 0; //A, !B, !CI
+ double leakage_101 = 0; //A, !B, CI
+ double leakage_110 = 0; //A, B, !CI
+ double leakage_111 = 0; //A, B, CI
+
+ //This is so painful...
+ leakage_000 += getGenProperties()->get("INV1_LeakagePower_0").toDouble();
+ leakage_000 += getGenProperties()->get("INV2_LeakagePower_0").toDouble();
+ leakage_000 += getGenProperties()->get("INV3_LeakagePower_0").toDouble();
+ leakage_000 += getGenProperties()->get("INV4_LeakagePower_0").toDouble();
+ leakage_000 += getGenProperties()->get("INVZ1_LeakagePower_010_0").toDouble();
+ leakage_000 += getGenProperties()->get("INVZ2_LeakagePower_101_0").toDouble();
+ leakage_000 += getGenProperties()->get("INVZ3_LeakagePower_010_0").toDouble();
+ leakage_000 += getGenProperties()->get("INVZ4_LeakagePower_101_0").toDouble();
+ leakage_000 += getGenProperties()->get("NAND1_LeakagePower_00").toDouble();
+ leakage_000 += getGenProperties()->get("NAND2_LeakagePower_00").toDouble();
+ leakage_000 += getGenProperties()->get("NAND3_LeakagePower_11").toDouble();
+
+ leakage_001 += getGenProperties()->get("INV1_LeakagePower_0").toDouble();
+ leakage_001 += getGenProperties()->get("INV2_LeakagePower_0").toDouble();
+ leakage_001 += getGenProperties()->get("INV3_LeakagePower_1").toDouble();
+ leakage_001 += getGenProperties()->get("INV4_LeakagePower_0").toDouble();
+ leakage_001 += getGenProperties()->get("INVZ1_LeakagePower_010_0").toDouble();
+ leakage_001 += getGenProperties()->get("INVZ2_LeakagePower_101_0").toDouble();
+ leakage_001 += getGenProperties()->get("INVZ3_LeakagePower_100_1").toDouble();
+ leakage_001 += getGenProperties()->get("INVZ4_LeakagePower_011_1").toDouble();
+ leakage_001 += getGenProperties()->get("NAND1_LeakagePower_10").toDouble();
+ leakage_001 += getGenProperties()->get("NAND2_LeakagePower_00").toDouble();
+ leakage_001 += getGenProperties()->get("NAND3_LeakagePower_11").toDouble();
+
+ leakage_010 += getGenProperties()->get("INV1_LeakagePower_0").toDouble();
+ leakage_010 += getGenProperties()->get("INV2_LeakagePower_1").toDouble();
+ leakage_010 += getGenProperties()->get("INV3_LeakagePower_0").toDouble();
+ leakage_010 += getGenProperties()->get("INV4_LeakagePower_1").toDouble();
+ leakage_010 += getGenProperties()->get("INVZ1_LeakagePower_011_1").toDouble();
+ leakage_010 += getGenProperties()->get("INVZ2_LeakagePower_100_1").toDouble();
+ leakage_010 += getGenProperties()->get("INVZ3_LeakagePower_011_1").toDouble();
+ leakage_010 += getGenProperties()->get("INVZ4_LeakagePower_100_1").toDouble();
+ leakage_010 += getGenProperties()->get("NAND1_LeakagePower_01").toDouble();
+ leakage_010 += getGenProperties()->get("NAND2_LeakagePower_01").toDouble();
+ leakage_010 += getGenProperties()->get("NAND3_LeakagePower_11").toDouble();
+
+ leakage_011 += getGenProperties()->get("INV1_LeakagePower_0").toDouble();
+ leakage_011 += getGenProperties()->get("INV2_LeakagePower_1").toDouble();
+ leakage_011 += getGenProperties()->get("INV3_LeakagePower_1").toDouble();
+ leakage_011 += getGenProperties()->get("INV4_LeakagePower_1").toDouble();
+ leakage_011 += getGenProperties()->get("INVZ1_LeakagePower_011_1").toDouble();
+ leakage_011 += getGenProperties()->get("INVZ2_LeakagePower_100_1").toDouble();
+ leakage_011 += getGenProperties()->get("INVZ3_LeakagePower_101_0").toDouble();
+ leakage_011 += getGenProperties()->get("INVZ4_LeakagePower_010_0").toDouble();
+ leakage_011 += getGenProperties()->get("NAND1_LeakagePower_11").toDouble();
+ leakage_011 += getGenProperties()->get("NAND2_LeakagePower_01").toDouble();
+ leakage_011 += getGenProperties()->get("NAND3_LeakagePower_01").toDouble();
+
+ leakage_100 += getGenProperties()->get("INV1_LeakagePower_1").toDouble();
+ leakage_100 += getGenProperties()->get("INV2_LeakagePower_0").toDouble();
+ leakage_100 += getGenProperties()->get("INV3_LeakagePower_0").toDouble();
+ leakage_100 += getGenProperties()->get("INV4_LeakagePower_1").toDouble();
+ leakage_100 += getGenProperties()->get("INVZ1_LeakagePower_100_1").toDouble();
+ leakage_100 += getGenProperties()->get("INVZ2_LeakagePower_011_1").toDouble();
+ leakage_100 += getGenProperties()->get("INVZ3_LeakagePower_011_1").toDouble();
+ leakage_100 += getGenProperties()->get("INVZ4_LeakagePower_100_1").toDouble();
+ leakage_100 += getGenProperties()->get("NAND1_LeakagePower_01").toDouble();
+ leakage_100 += getGenProperties()->get("NAND2_LeakagePower_10").toDouble();
+ leakage_100 += getGenProperties()->get("NAND3_LeakagePower_11").toDouble();
+
+ leakage_101 += getGenProperties()->get("INV1_LeakagePower_1").toDouble();
+ leakage_101 += getGenProperties()->get("INV2_LeakagePower_0").toDouble();
+ leakage_101 += getGenProperties()->get("INV3_LeakagePower_1").toDouble();
+ leakage_101 += getGenProperties()->get("INV4_LeakagePower_1").toDouble();
+ leakage_101 += getGenProperties()->get("INVZ1_LeakagePower_100_1").toDouble();
+ leakage_101 += getGenProperties()->get("INVZ2_LeakagePower_011_1").toDouble();
+ leakage_101 += getGenProperties()->get("INVZ3_LeakagePower_101_0").toDouble();
+ leakage_101 += getGenProperties()->get("INVZ4_LeakagePower_010_0").toDouble();
+ leakage_101 += getGenProperties()->get("NAND1_LeakagePower_11").toDouble();
+ leakage_101 += getGenProperties()->get("NAND2_LeakagePower_10").toDouble();
+ leakage_101 += getGenProperties()->get("NAND3_LeakagePower_01").toDouble();
+
+ leakage_110 += getGenProperties()->get("INV1_LeakagePower_1").toDouble();
+ leakage_110 += getGenProperties()->get("INV2_LeakagePower_1").toDouble();
+ leakage_110 += getGenProperties()->get("INV3_LeakagePower_0").toDouble();
+ leakage_110 += getGenProperties()->get("INV4_LeakagePower_0").toDouble();
+ leakage_110 += getGenProperties()->get("INVZ1_LeakagePower_101_0").toDouble();
+ leakage_110 += getGenProperties()->get("INVZ2_LeakagePower_010_0").toDouble();
+ leakage_110 += getGenProperties()->get("INVZ3_LeakagePower_010_0").toDouble();
+ leakage_110 += getGenProperties()->get("INVZ4_LeakagePower_101_0").toDouble();
+ leakage_110 += getGenProperties()->get("NAND1_LeakagePower_00").toDouble();
+ leakage_110 += getGenProperties()->get("NAND2_LeakagePower_11").toDouble();
+ leakage_110 += getGenProperties()->get("NAND3_LeakagePower_10").toDouble();
+
+ leakage_111 += getGenProperties()->get("INV1_LeakagePower_1").toDouble();
+ leakage_111 += getGenProperties()->get("INV2_LeakagePower_1").toDouble();
+ leakage_111 += getGenProperties()->get("INV3_LeakagePower_1").toDouble();
+ leakage_111 += getGenProperties()->get("INV4_LeakagePower_0").toDouble();
+ leakage_111 += getGenProperties()->get("INVZ1_LeakagePower_101_0").toDouble();
+ leakage_111 += getGenProperties()->get("INVZ2_LeakagePower_010_0").toDouble();
+ leakage_111 += getGenProperties()->get("INVZ3_LeakagePower_100_1").toDouble();
+ leakage_111 += getGenProperties()->get("INVZ4_LeakagePower_011_1").toDouble();
+ leakage_111 += getGenProperties()->get("NAND1_LeakagePower_10").toDouble();
+ leakage_111 += getGenProperties()->get("NAND2_LeakagePower_11").toDouble();
+ leakage_111 += getGenProperties()->get("NAND3_LeakagePower_10").toDouble();
+
+ cache->set(cell_name + "->Leakage->!A!B!CI", leakage_000);
+ cache->set(cell_name + "->Leakage->!A!BCI", leakage_001);
+ cache->set(cell_name + "->Leakage->!AB!CI", leakage_010);
+ cache->set(cell_name + "->Leakage->!ABCI", leakage_011);
+ cache->set(cell_name + "->Leakage->A!B!CI", leakage_100);
+ cache->set(cell_name + "->Leakage->A!BCI", leakage_101);
+ cache->set(cell_name + "->Leakage->AB!CI", leakage_110);
+ cache->set(cell_name + "->Leakage->ABCI", leakage_111);
+ Log::printLine(cell_name + "->Leakage->!A!B!CI=" + (String) leakage_000);
+ Log::printLine(cell_name + "->Leakage->!A!BCI=" + (String) leakage_001);
+ Log::printLine(cell_name + "->Leakage->!AB!CI=" + (String) leakage_010);
+ Log::printLine(cell_name + "->Leakage->!ABCI=" + (String) leakage_011);
+ Log::printLine(cell_name + "->Leakage->A!B!CI=" + (String) leakage_100);
+ Log::printLine(cell_name + "->Leakage->A!BCI=" + (String) leakage_101);
+ Log::printLine(cell_name + "->Leakage->AB!CI=" + (String) leakage_110);
+ Log::printLine(cell_name + "->Leakage->ABCI=" + (String) leakage_111);
+ // --------------------------------------------------------------------
+
+ /*
+ // Cache event energy results
+ double event_a_flip = 0.0;
+ event_a_flip += getGenProperties()->get("INV1_A_Flip").toDouble() + getGenProperties()->get("INV1_ZN_Flip").toDouble();
+ event_a_flip += getGenProperties()->get("INVZ1_OE_Flip").toDouble() + getGenProperties()->get("INVZ1_OEN_Flip").toDouble();
+ event_a_flip += getGenProperties()->get("INVZ2_OE_Flip").toDouble() + getGenProperties()->get("INVZ2_OEN_Flip").toDouble();
+ event_a_flip += getGenProperties()->get("NAND2_A1_Flip").toDouble();
+ cache->set(cell_name + "->Event_A_Flip", event_a_flip);
+ Log::printLine(cell_name + "->Event_A_Flip=" + (String) event_a_flip);
+
+ double event_b_flip = 0.0;
+ event_b_flip += getGenProperties()->get("INV2_A_Flip").toDouble() + getGenProperties()->get("INV2_ZN_Flip").toDouble();
+ event_b_flip += getGenProperties()->get("INVZ1_A_Flip").toDouble();
+ event_b_flip += getGenProperties()->get("INVZ2_A_Flip").toDouble();
+ event_b_flip += getGenProperties()->get("NAND2_A1_Flip").toDouble();
+ cache->set(cell_name + "->Event_B_Flip", event_b_flip);
+ Log::printLine(cell_name + "->Event_B_Flip=" + (String) event_b_flip);
+
+ double event_ci_flip = 0.0;
+ event_ci_flip += getGenProperties()->get("INV3_A_Flip").toDouble() + getGenProperties()->get("INV3_ZN_Flip").toDouble();
+ event_ci_flip += getGenProperties()->get("INVZ3_OE_Flip").toDouble() + getGenProperties()->get("INVZ3_OEN_Flip").toDouble();
+ event_ci_flip += getGenProperties()->get("INVZ4_OE_Flip").toDouble() + getGenProperties()->get("INVZ4_OEN_Flip").toDouble();
+ event_ci_flip += getGenProperties()->get("NAND1_A1_Flip").toDouble();
+ cache->set(cell_name + "->Event_CI_Flip", event_ci_flip);
+ Log::printLine(cell_name + "->Event_CI_Flip=" + (String) event_ci_flip);
+
+ double event_p_flip = 0.0;
+ event_p_flip += getGenProperties()->get("INV4_A_Flip").toDouble() + getGenProperties()->get("INV4_ZN_Flip").toDouble();
+ event_p_flip += getGenProperties()->get("INVZ1_ZN_Flip").toDouble();
+ event_p_flip += getGenProperties()->get("INVZ2_ZN_Flip").toDouble();
+ event_p_flip += getGenProperties()->get("NAND1_A2_Flip").toDouble();
+ cache->set(cell_name + "->Event_P_Flip", event_p_flip);
+ Log::printLine(cell_name + "->Event_P_Flip=" + (String) event_p_flip);
+
+ double event_s_flip = 0.0;
+ event_s_flip += getGenProperties()->get("INVZ3_ZN_Flip").toDouble();
+ event_s_flip += getGenProperties()->get("INVZ4_ZN_Flip").toDouble();
+ cache->set(cell_name + "->Event_S_Flip", event_s_flip);
+ Log::printLine(cell_name + "->Event_S_Flip=" + (String) event_s_flip);
+
+ double event_cp_flip = 0.0;
+ event_cp_flip += getGenProperties()->get("NAND1_ZN_Flip").toDouble();
+ event_cp_flip += getGenProperties()->get("NAND3_A2_Flip").toDouble();
+ cache->set(cell_name + "->Event_CP_Flip", event_cp_flip);
+ Log::printLine(cell_name + "->Event_CP_Flip=" + (String) event_cp_flip);
+
+ double event_g_flip = 0.0;
+ event_g_flip += getGenProperties()->get("NAND2_ZN_Flip").toDouble();
+ event_g_flip += getGenProperties()->get("NAND3_A2_Flip").toDouble();
+ cache->set(cell_name + "->Event_G_Flip", event_g_flip);
+ Log::printLine(cell_name + "->Event_G_Flip=" + (String) event_g_flip);
+
+ double event_co_flip = 0.0;
+ event_co_flip += getGenProperties()->get("NAND3_ZN_Flip").toDouble();
+ cache->set(cell_name + "->Event_CO_Flip", event_co_flip);
+ Log::printLine(cell_name + "->Event_CO_Flip=" + (String) event_co_flip);
+ */
+ // --------------------------------------------------------------------
+ // Get Node Capacitances
+ // --------------------------------------------------------------------
+ double a_cap = getNet("A")->getTotalDownstreamCap();
+ double b_cap = getNet("B")->getTotalDownstreamCap();
+ double ci_cap = getNet("CI")->getTotalDownstreamCap();
+ double a_b_cap = getNet("A_b")->getTotalDownstreamCap();
+ double b_b_cap = getNet("B_b")->getTotalDownstreamCap();
+ double ci_b_cap = getNet("CI_b")->getTotalDownstreamCap();
+ double p_cap = getNet("P")->getTotalDownstreamCap();
+ double p_b_cap = getNet("P_b")->getTotalDownstreamCap();
+ double s_cap = getNet("S")->getTotalDownstreamCap();
+ double cp_cap = getNet("CP")->getTotalDownstreamCap();
+ double g_cap = getNet("G")->getTotalDownstreamCap();
+ double co_cap = getNet("CO")->getTotalDownstreamCap();
+
+ cache->set(cell_name + "->Cap->A", a_cap);
+ cache->set(cell_name + "->Cap->B", b_cap);
+ cache->set(cell_name + "->Cap->CI", ci_cap);
+ cache->set(cell_name + "->Cap->A_b", a_b_cap);
+ cache->set(cell_name + "->Cap->B_b", b_b_cap);
+ cache->set(cell_name + "->Cap->CI_b", ci_b_cap);
+ cache->set(cell_name + "->Cap->P", p_cap);
+ cache->set(cell_name + "->Cap->P_b", p_b_cap);
+ cache->set(cell_name + "->Cap->S", s_cap);
+ cache->set(cell_name + "->Cap->CP", cp_cap);
+ cache->set(cell_name + "->Cap->G", g_cap);
+ cache->set(cell_name + "->Cap->CO", co_cap);
+
+ Log::printLine(cell_name + "->Cap->A=" + (String) a_cap);
+ Log::printLine(cell_name + "->Cap->B=" + (String) b_cap);
+ Log::printLine(cell_name + "->Cap->CI=" + (String) ci_cap);
+ Log::printLine(cell_name + "->Cap->A_b=" + (String) a_b_cap);
+ Log::printLine(cell_name + "->Cap->B_b=" + (String) b_b_cap);
+ Log::printLine(cell_name + "->Cap->CI_b=" + (String) ci_b_cap);
+ Log::printLine(cell_name + "->Cap->P=" + (String) p_cap);
+ Log::printLine(cell_name + "->Cap->P_b=" + (String) p_b_cap);
+ Log::printLine(cell_name + "->Cap->S=" + (String) s_cap);
+ Log::printLine(cell_name + "->Cap->CP=" + (String) cp_cap);
+ Log::printLine(cell_name + "->Cap->G=" + (String) g_cap);
+ Log::printLine(cell_name + "->Cap->CO=" + (String) co_cap);
+ // --------------------------------------------------------------------
+
+ // --------------------------------------------------------------------
+ // Build Internal Delay Model
+ // --------------------------------------------------------------------
+ // Build abstracted timing model
+ double s_ron = (getDriver("INVZ3_RonZN")->getOutputRes() + getDriver("INVZ4_RonZN")->getOutputRes()) / 2;
+ double co_ron = getDriver("NAND3_RonZN")->getOutputRes();
+
+ double a_to_s_delay = 0.0;
+ a_to_s_delay += getDriver("INV1_RonZN")->calculateDelay();
+ a_to_s_delay += max(getDriver("INVZ1_RonZN")->calculateDelay(), getDriver("INVZ2_RonZN")->calculateDelay());
+ a_to_s_delay += max(getDriver("INVZ3_RonZN")->calculateDelay(), getDriver("INV4_RonZN")->calculateDelay() + getDriver("INVZ4_RonZN")->calculateDelay());
+
+ double b_to_s_delay = 0.0;
+ b_to_s_delay += max(getDriver("INVZ1_RonZN")->calculateDelay(), getDriver("INV2_RonZN")->calculateDelay() + getDriver("INVZ2_RonZN")->calculateDelay());
+ b_to_s_delay += max(getDriver("INVZ3_RonZN")->calculateDelay(), getDriver("INV4_RonZN")->calculateDelay() + getDriver("INVZ4_RonZN")->calculateDelay());
+
+ double ci_to_s_delay = 0.0;
+ ci_to_s_delay += getDriver("INV3_RonZN")->calculateDelay();
+ ci_to_s_delay += max(getDriver("INVZ3_RonZN")->calculateDelay(), getDriver("INVZ4_RonZN")->calculateDelay());
+
+ double a_to_co_delay = 0.0;
+ a_to_co_delay += max(getDriver("NAND2_RonZN")->calculateDelay(), //Generate path
+ getDriver("INV1_RonZN")->calculateDelay() + //Carry propagate path
+ max(getDriver("INVZ1_RonZN")->calculateDelay(), getDriver("INVZ2_RonZN")->calculateDelay()) +
+ getDriver("NAND1_RonZN")->calculateDelay());
+ a_to_co_delay += getDriver("NAND3_RonZN")->calculateDelay();
+
+ double b_to_co_delay = 0.0;
+ b_to_co_delay += max(getDriver("NAND2_RonZN")->calculateDelay(), //Generate path
+ max(getDriver("INVZ1_RonZN")->calculateDelay(), //Carry propagate path
+ getDriver("INV2_RonZN")->calculateDelay() + getDriver("INVZ2_RonZN")->calculateDelay()) +
+ getDriver("NAND1_RonZN")->calculateDelay());
+ b_to_co_delay += getDriver("NAND3_RonZN")->calculateDelay();
+
+ double ci_to_co_delay = 0.0;
+ ci_to_co_delay += getDriver("NAND1_RonZN")->calculateDelay();
+ ci_to_co_delay += getDriver("NAND3_RonZN")->calculateDelay();
+
+ cache->set(cell_name + "->DriveRes->S", s_ron);
+ cache->set(cell_name + "->DriveRes->CO", co_ron);
+
+ cache->set(cell_name + "->Delay->A_to_S", a_to_s_delay);
+ cache->set(cell_name + "->Delay->B_to_S", b_to_s_delay);
+ cache->set(cell_name + "->Delay->CI_to_S", ci_to_s_delay);
+ cache->set(cell_name + "->Delay->A_to_CO", a_to_co_delay);
+ cache->set(cell_name + "->Delay->B_to_CO", b_to_co_delay);
+ cache->set(cell_name + "->Delay->CI_to_CO", ci_to_co_delay);
+
+ Log::printLine(cell_name + "->DriveRes->S=" + (String) s_ron);
+ Log::printLine(cell_name + "->DriveRes->CO=" + (String) co_ron);
+ Log::printLine(cell_name + "->Delay->A_to_S=" + (String) a_to_s_delay);
+ Log::printLine(cell_name + "->Delay->B_to_S=" + (String) b_to_s_delay);
+ Log::printLine(cell_name + "->Delay->CI_to_S=" + (String) ci_to_s_delay);
+ Log::printLine(cell_name + "->Delay->A_to_CO=" + (String) a_to_co_delay);
+ Log::printLine(cell_name + "->Delay->B_to_CO=" + (String) b_to_co_delay);
+ Log::printLine(cell_name + "->Delay->CI_to_CO=" + (String) ci_to_co_delay);
+ // --------------------------------------------------------------------
+
+ return;
+
+ }
+
+} // namespace DSENT
+
diff --git a/ext/dsent/model/std_cells/ADDF.h b/ext/dsent/model/std_cells/ADDF.h
new file mode 100644
index 000000000..03bae5d4f
--- /dev/null
+++ b/ext/dsent/model/std_cells/ADDF.h
@@ -0,0 +1,39 @@
+#ifndef __DSENT_MODEL_STD_CELLS_ADDF_H__
+#define __DSENT_MODEL_STD_CELLS_ADDF_H__
+
+#include "util/CommonType.h"
+#include "model/std_cells/StdCell.h"
+#include "model/TransitionInfo.h"
+
+namespace DSENT
+{
+ // A full adder standard cell
+ class ADDF : public StdCell
+ {
+ public:
+ ADDF(const String& instance_name_, const TechModel* tech_model_);
+ virtual ~ADDF();
+
+ public:
+ // Set a list of properties needed to update model
+ void initProperties();
+ // Cache the standard cell
+ void cacheStdCell(StdCellLib* cell_lib_, double drive_strength_);
+ private:
+ TransitionInfo m_trans_P_;
+ TransitionInfo m_trans_G_;
+ TransitionInfo m_trans_CP_;
+
+ protected:
+ // Build the model
+ virtual void constructModel();
+ virtual void updateModel();
+ virtual void evaluateModel();
+ virtual void useModel();
+ virtual void propagateTransitionInfo();
+
+ }; // class ADDF
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_STD_CELLS_ADDF_H__
+
diff --git a/ext/dsent/model/std_cells/AND2.cc b/ext/dsent/model/std_cells/AND2.cc
new file mode 100644
index 000000000..2113c2397
--- /dev/null
+++ b/ext/dsent/model/std_cells/AND2.cc
@@ -0,0 +1,272 @@
+#include "model/std_cells/AND2.h"
+
+#include <cmath>
+
+#include "model/PortInfo.h"
+#include "model/TransitionInfo.h"
+#include "model/EventInfo.h"
+#include "model/std_cells/StdCellLib.h"
+#include "model/std_cells/CellMacros.h"
+#include "model/timing_graph/ElectricalNet.h"
+#include "model/timing_graph/ElectricalDriver.h"
+#include "model/timing_graph/ElectricalLoad.h"
+#include "model/timing_graph/ElectricalDelay.h"
+
+namespace DSENT
+{
+ using std::max;
+
+ AND2::AND2(const String& instance_name_, const TechModel* tech_model_)
+ : StdCell(instance_name_, tech_model_)
+ {
+ initProperties();
+ }
+
+ AND2::~AND2()
+ {}
+
+ void AND2::initProperties()
+ {
+ return;
+ }
+
+ void AND2::constructModel()
+ {
+ // All constructModel should do is create Area/NDDPower/Energy Results as
+ // well as instantiate any sub-instances using only the hard parameters
+
+ createInputPort("A");
+ createInputPort("B");
+ createOutputPort("Y");
+
+ createLoad("A_Cap");
+ createLoad("B_Cap");
+ createDelay("A_to_Y_delay");
+ createDelay("B_to_Y_delay");
+ createDriver("Y_Ron", true);
+
+ ElectricalLoad* a_cap = getLoad("A_Cap");
+ ElectricalLoad* b_cap = getLoad("B_Cap");
+ ElectricalDelay* a_to_y_delay = getDelay("A_to_Y_delay");
+ ElectricalDelay* b_to_y_delay = getDelay("B_to_Y_delay");
+ ElectricalDriver* y_ron = getDriver("Y_Ron");
+
+ getNet("A")->addDownstreamNode(a_cap);
+ getNet("B")->addDownstreamNode(b_cap);
+ a_cap->addDownstreamNode(a_to_y_delay);
+ b_cap->addDownstreamNode(b_to_y_delay);
+ a_to_y_delay->addDownstreamNode(y_ron);
+ b_to_y_delay->addDownstreamNode(y_ron);
+ y_ron->addDownstreamNode(getNet("Y"));
+
+ // Create Area result
+ // Create NDD Power result
+ createElectricalAtomicResults();
+ getEventInfo("Idle")->setStaticTransitionInfos();
+ // Create AND Event Energy Result
+ createElectricalEventAtomicResult("AND2");
+
+ return;
+ }
+
+ void AND2::updateModel()
+ {
+ // All updateModel should do is calculate numbers for the Area/NDDPower/Energy
+ // Results as anything else that needs to be done using either soft or hard parameters
+
+ // Get parameters
+ double drive_strength = getDrivingStrength();
+ Map<double>* cache = getTechModel()->getStdCellLib()->getStdCellCache();
+
+ // Standard cell cache string
+ String cell_name = "AND2_X" + (String) drive_strength;
+
+ // Get timing parameters
+ getLoad("A_Cap")->setLoadCap(cache->get(cell_name + "->Cap->A"));
+ getLoad("B_Cap")->setLoadCap(cache->get(cell_name + "->Cap->B"));
+ getDelay("A_to_Y_delay")->setDelay(cache->get(cell_name + "->Delay->A_to_Y"));
+ getDelay("B_to_Y_delay")->setDelay(cache->get(cell_name + "->Delay->B_to_Y"));
+ getDriver("Y_Ron")->setOutputRes(cache->get(cell_name + "->DriveRes->Y"));
+
+ // Set the cell area
+ getAreaResult("Active")->setValue(cache->get(cell_name + "->ActiveArea"));
+ getAreaResult("Metal1Wire")->setValue(cache->get(cell_name + "->ActiveArea"));
+
+ return;
+ }
+
+ void AND2::evaluateModel()
+ {
+ return;
+ }
+
+ void AND2::useModel()
+ {
+ // Get parameters
+ double drive_strength = getDrivingStrength();
+ Map<double>* cache = getTechModel()->getStdCellLib()->getStdCellCache();
+
+ // Standard cell cache string
+ String cell_name = "AND2_X" + (String) drive_strength;
+
+ // Propagate the transition info and get the 0->1 transtion count
+ propagateTransitionInfo();
+ double P_A = getInputPort("A")->getTransitionInfo().getProbability1();
+ double P_B = getInputPort("B")->getTransitionInfo().getProbability1();
+ double Y_num_trans_01 = getOutputPort("Y")->getTransitionInfo().getNumberTransitions01();
+
+ // Calculate leakage
+ double leakage = 0;
+ leakage += cache->get(cell_name + "->Leakage->!A!B") * (1 - P_A) * (1 - P_B);
+ leakage += cache->get(cell_name + "->Leakage->!AB") * (1 - P_A) * P_B;
+ leakage += cache->get(cell_name + "->Leakage->A!B") * P_A * (1 - P_B);
+ leakage += cache->get(cell_name + "->Leakage->AB") * P_A * P_B;
+ getNddPowerResult("Leakage")->setValue(leakage);
+
+ // Get VDD
+ double vdd = getTechModel()->get("Vdd");
+
+ // Get capacitances
+ double y_b_cap = cache->get(cell_name + "->Cap->Y_b");
+ double y_cap = cache->get(cell_name + "->Cap->Y");
+ double y_load_cap = getNet("Y")->getTotalDownstreamCap();
+
+ // Calculate AND2Event energy
+ double energy_per_trans_01 = (y_b_cap + y_cap + y_load_cap) * vdd * vdd;
+ getEventResult("AND2")->setValue(energy_per_trans_01 * Y_num_trans_01);
+
+ return;
+ }
+
+ void AND2::propagateTransitionInfo()
+ {
+ // Get input signal transition info
+ const TransitionInfo& trans_A = getInputPort("A")->getTransitionInfo();
+ const TransitionInfo& trans_B = getInputPort("B")->getTransitionInfo();
+
+ double max_freq_mult = max(trans_A.getFrequencyMultiplier(), trans_B.getFrequencyMultiplier());
+ const TransitionInfo& scaled_trans_A = trans_A.scaleFrequencyMultiplier(max_freq_mult);
+ const TransitionInfo& scaled_trans_B = trans_B.scaleFrequencyMultiplier(max_freq_mult);
+
+ double A_prob_00 = scaled_trans_A.getNumberTransitions00() / max_freq_mult;
+ double A_prob_01 = scaled_trans_A.getNumberTransitions01() / max_freq_mult;
+ double A_prob_10 = A_prob_01;
+ double A_prob_11 = scaled_trans_A.getNumberTransitions11() / max_freq_mult;
+ double B_prob_00 = scaled_trans_B.getNumberTransitions00() / max_freq_mult;
+ double B_prob_01 = scaled_trans_B.getNumberTransitions01() / max_freq_mult;
+ double B_prob_10 = B_prob_01;
+ double B_prob_11 = scaled_trans_B.getNumberTransitions11() / max_freq_mult;
+
+ // Set output transition info
+ double Y_prob_00 = A_prob_00 +
+ A_prob_01 * (B_prob_00 + B_prob_10) +
+ A_prob_10 * (B_prob_00 + B_prob_01) +
+ A_prob_11 * B_prob_00;
+ double Y_prob_01 = A_prob_01 * (B_prob_01 + B_prob_11) +
+ A_prob_11 * B_prob_01;
+ double Y_prob_11 = A_prob_11 * B_prob_11;
+
+ // Check that probabilities add up to 1.0 with some finite tolerance
+ ASSERT(LibUtil::Math::isEqual(Y_prob_00 + Y_prob_01 + Y_prob_01 + Y_prob_11, 1.0), "[Error] " + getInstanceName() +
+ "Output transition probabilities must add up to 1 (" + (String) Y_prob_00 + ", " +
+ (String) Y_prob_01 + ", " + (String) Y_prob_11 + ")!");
+
+ // Turn probability of transitions per cycle into number of transitions per time unit
+ TransitionInfo trans_Y(Y_prob_00 * max_freq_mult, Y_prob_01 * max_freq_mult, Y_prob_11 * max_freq_mult);
+ getOutputPort("Y")->setTransitionInfo(trans_Y);
+ return;
+ }
+
+ void AND2::cacheStdCell(StdCellLib* cell_lib_, double drive_strength_)
+ {
+ // Standard cell cache string
+ String cell_name = "AND2_X" + (String) drive_strength_;
+
+ Log::printLine("=== " + cell_name + " ===");
+
+ // Get parameters
+ double gate_pitch = cell_lib_->getTechModel()->get("Gate->PitchContacted");
+ Map<double>* cache = cell_lib_->getStdCellCache();
+
+ // Now actually build the full standard cell model
+ // Create the two input ports
+ createInputPort("A");
+ createInputPort("B");
+ createOutputPort("Y");
+
+ createNet("Y_b");
+
+ // Adds macros
+ CellMacros::addNand2(this, "NAND2", false, true, true, "A", "B", "Y_b");
+ CellMacros::addInverter(this, "INV", false, true, "Y_b", "Y");
+ CellMacros::updateNand2(this, "NAND2", drive_strength_ * 0.5);
+ CellMacros::updateInverter(this, "INV", drive_strength_ * 1.0);
+
+ // Cache area result
+ double area = 0.0;
+ area += gate_pitch * getTotalHeight() * 1;
+ area += gate_pitch * getTotalHeight() * getGenProperties()->get("NAND2_GatePitches").toDouble();
+ area += gate_pitch * getTotalHeight() * getGenProperties()->get("INV_GatePitches").toDouble();
+ cache->set(cell_name + "->ActiveArea", area);
+ Log::printLine(cell_name + "->ActiveArea=" + (String) area);
+
+ // --------------------------------------------------------------------
+ // Leakage Model Calculation
+ // --------------------------------------------------------------------
+ double leakage_00 = getGenProperties()->get("NAND2_LeakagePower_00").toDouble() +
+ getGenProperties()->get("INV_LeakagePower_0").toDouble();
+ double leakage_01 = getGenProperties()->get("NAND2_LeakagePower_01").toDouble() +
+ getGenProperties()->get("INV_LeakagePower_0").toDouble();
+ double leakage_10 = getGenProperties()->get("NAND2_LeakagePower_10").toDouble() +
+ getGenProperties()->get("INV_LeakagePower_0").toDouble();
+ double leakage_11 = getGenProperties()->get("NAND2_LeakagePower_11").toDouble() +
+ getGenProperties()->get("INV_LeakagePower_1").toDouble();
+ cache->set(cell_name + "->Leakage->!A!B", leakage_00);
+ cache->set(cell_name + "->Leakage->!AB", leakage_01);
+ cache->set(cell_name + "->Leakage->A!B", leakage_10);
+ cache->set(cell_name + "->Leakage->AB", leakage_11);
+ Log::printLine(cell_name + "->Leakage->!A!B=" + (String) leakage_00);
+ Log::printLine(cell_name + "->Leakage->!AB=" + (String) leakage_01);
+ Log::printLine(cell_name + "->Leakage->A!B=" + (String) leakage_10);
+ Log::printLine(cell_name + "->Leakage->AB=" + (String) leakage_11);
+ // --------------------------------------------------------------------
+
+ // --------------------------------------------------------------------
+ // Get Node Capacitances
+ // --------------------------------------------------------------------
+ double a_cap = getNet("A")->getTotalDownstreamCap();
+ double b_cap = getNet("B")->getTotalDownstreamCap();
+ double y_b_cap = getNet("Y_b")->getTotalDownstreamCap();
+ double y_cap = getNet("Y")->getTotalDownstreamCap();
+
+ cache->set(cell_name + "->Cap->A", a_cap);
+ cache->set(cell_name + "->Cap->B", b_cap);
+ cache->set(cell_name + "->Cap->Y_b", y_b_cap);
+ cache->set(cell_name + "->Cap->Y", y_cap);
+ Log::printLine(cell_name + "->Cap->A=" + (String) a_cap);
+ Log::printLine(cell_name + "->Cap->B=" + (String) b_cap);
+ Log::printLine(cell_name + "->Cap->Y=" + (String) y_b_cap);
+ Log::printLine(cell_name + "->Cap->Y=" + (String) y_cap);
+ // --------------------------------------------------------------------
+
+ // --------------------------------------------------------------------
+ // Build Internal Delay Model
+ // --------------------------------------------------------------------
+ double y_ron = getDriver("INV_RonZN")->getOutputRes();
+ double a_to_y_delay = getDriver("NAND2_RonZN")->calculateDelay() +
+ getDriver("INV_RonZN")->calculateDelay();
+ double b_to_y_delay = getDriver("NAND2_RonZN")->calculateDelay() +
+ getDriver("INV_RonZN")->calculateDelay();
+
+ cache->set(cell_name + "->DriveRes->Y", y_ron);
+ cache->set(cell_name + "->Delay->A_to_Y", a_to_y_delay);
+ cache->set(cell_name + "->Delay->B_to_Y", b_to_y_delay);
+ Log::printLine(cell_name + "->DriveRes->Y=" + (String) y_ron);
+ Log::printLine(cell_name + "->Delay->A_to_Y=" + (String) a_to_y_delay);
+ Log::printLine(cell_name + "->Delay->B_to_Y=" + (String) b_to_y_delay);
+ // --------------------------------------------------------------------
+
+ return;
+
+ }
+} // namespace DSENT
diff --git a/ext/dsent/model/std_cells/AND2.h b/ext/dsent/model/std_cells/AND2.h
new file mode 100644
index 000000000..67fe36be1
--- /dev/null
+++ b/ext/dsent/model/std_cells/AND2.h
@@ -0,0 +1,32 @@
+#ifndef __DSENT_MODEL_STD_CELLS_AND2_H__
+#define __DSENT_MODEL_STD_CELLS_AND2_H__
+
+#include "util/CommonType.h"
+#include "model/std_cells/StdCell.h"
+
+namespace DSENT
+{
+ class AND2 : public StdCell
+ {
+ public:
+ AND2(const String& instance_name_, const TechModel* tech_model_);
+ virtual ~AND2();
+
+ public:
+ // Set a list of properties' name needed to construct model
+ void initProperties();
+ // Cache the standard cell
+ void cacheStdCell(StdCellLib* cell_lib_, double drive_strength_);
+
+ protected:
+ // Build the model
+ virtual void constructModel();
+ virtual void updateModel();
+ virtual void evaluateModel();
+ virtual void useModel();
+ virtual void propagateTransitionInfo();
+ }; // class AND2
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_STD_CELLS_AND2_H__
+
diff --git a/ext/dsent/model/std_cells/BUF.cc b/ext/dsent/model/std_cells/BUF.cc
new file mode 100644
index 000000000..61c7dac4b
--- /dev/null
+++ b/ext/dsent/model/std_cells/BUF.cc
@@ -0,0 +1,216 @@
+#include "model/std_cells/BUF.h"
+
+#include <cmath>
+
+#include "model/PortInfo.h"
+#include "model/TransitionInfo.h"
+#include "model/EventInfo.h"
+#include "model/std_cells/StdCellLib.h"
+#include "model/std_cells/CellMacros.h"
+#include "model/timing_graph/ElectricalNet.h"
+#include "model/timing_graph/ElectricalDriver.h"
+#include "model/timing_graph/ElectricalLoad.h"
+#include "model/timing_graph/ElectricalDelay.h"
+
+namespace DSENT
+{
+ using std::max;
+
+ BUF::BUF(const String& instance_name_, const TechModel* tech_model_)
+ : StdCell(instance_name_, tech_model_)
+ {
+ initProperties();
+ }
+
+ BUF::~BUF()
+ {}
+
+ void BUF::initProperties()
+ {
+ return;
+ }
+
+ void BUF::constructModel()
+ {
+ createInputPort("A");
+ createOutputPort("Y");
+
+ createLoad("A_Cap");
+ createDelay("A_to_Y_delay");
+ createDriver("Y_Ron", true);
+
+ ElectricalLoad* a_cap = getLoad("A_Cap");
+ ElectricalDelay* a_to_y_delay = getDelay("A_to_Y_delay");
+ ElectricalDriver* y_ron = getDriver("Y_Ron");
+
+ getNet("A")->addDownstreamNode(a_cap);
+ a_cap->addDownstreamNode(a_to_y_delay);
+ a_to_y_delay->addDownstreamNode(y_ron);
+ y_ron->addDownstreamNode(getNet("Y"));
+
+ // Create Area result
+ // Create NDD Power result
+ createElectricalAtomicResults();
+ // Create OR Event Energy Result
+ createElectricalEventAtomicResult("BUF");
+
+ getEventInfo("Idle")->setStaticTransitionInfos();
+
+ return;
+ }
+
+ void BUF::updateModel()
+ {
+ // Get parameters
+ double drive_strength = getDrivingStrength();
+ Map<double>* cache = getTechModel()->getStdCellLib()->getStdCellCache();
+
+ // Standard cell cache string
+ const String& cell_name = "BUF_X" + (String) drive_strength;
+
+ // Get timing parameters
+ getLoad("A_Cap")->setLoadCap(cache->get(cell_name + "->Cap->A"));
+ getDelay("A_to_Y_delay")->setDelay(cache->get(cell_name + "->Delay->A_to_Y"));
+ getDriver("Y_Ron")->setOutputRes(cache->get(cell_name + "->DriveRes->Y"));
+
+ // Set the cell area
+ getAreaResult("Active")->setValue(cache->get(cell_name + "->ActiveArea"));
+ getAreaResult("Metal1Wire")->setValue(cache->get(cell_name + "->ActiveArea"));
+
+ return;
+ }
+
+ void BUF::evaluateModel()
+ {
+ return;
+ }
+
+ void BUF::useModel()
+ {
+ // Get parameters
+ double drive_strength = getDrivingStrength();
+ Map<double>* cache = getTechModel()->getStdCellLib()->getStdCellCache();
+
+ // Stadard cell cache string
+ const String& cell_name = "BUF_X" + (String) drive_strength;
+
+ // Propagate the transition info and get the 0->1 transtion count
+ propagateTransitionInfo();
+ double P_A = getInputPort("A")->getTransitionInfo().getProbability1();
+ double Y_num_trans_01 = getOutputPort("Y")->getTransitionInfo().getNumberTransitions01();
+
+ // Calculate leakage
+ double leakage = 0;
+ leakage += cache->get(cell_name + "->Leakage->!A") * (1 - P_A);
+ leakage += cache->get(cell_name + "->Leakage->A") * P_A;
+ getNddPowerResult("Leakage")->setValue(leakage);
+
+ // Get VDD
+ double vdd = getTechModel()->get("Vdd");
+
+ // Get capacitances
+ double y_b_cap = cache->get(cell_name + "->Cap->Y_b");
+ double y_cap = cache->get(cell_name + "->Cap->Y");
+ double y_load_cap = getNet("Y")->getTotalDownstreamCap();
+
+ // Calculate BUFEvent energy
+ double energy_per_trans_01 = (y_b_cap + y_cap + y_load_cap) * vdd * vdd;
+ getEventResult("BUF")->setValue(energy_per_trans_01 * Y_num_trans_01);
+
+ return;
+ }
+
+ void BUF::propagateTransitionInfo()
+ {
+ // Get input signal transition info
+ const TransitionInfo& trans_A = getInputPort("A")->getTransitionInfo();
+
+ getOutputPort("Y")->setTransitionInfo(trans_A);
+ return;
+ }
+
+ // Creates the standard cell, characterizes and abstracts away the details
+ void BUF::cacheStdCell(StdCellLib* cell_lib_, double drive_strength_)
+ {
+ // Get parameters
+ double gate_pitch = cell_lib_->getTechModel()->get("Gate->PitchContacted");
+ Map<double>* cache = cell_lib_->getStdCellCache();
+
+ // Stadard cell cache string
+ const String& cell_name = "BUF_X" + (String) drive_strength_;
+
+ Log::printLine("=== " + cell_name + " ===");
+
+ // Now actually build the full standard cell model
+ createInputPort("A");
+ createOutputPort("Y");
+
+ createNet("Y_b");
+
+ // Adds macros
+ CellMacros::addInverter(this, "INV0", false, true, "A", "Y_b");
+ CellMacros::addInverter(this, "INV1", false, true, "Y_b", "Y");
+
+ // Update macros
+ CellMacros::updateInverter(this, "INV0", drive_strength_ * 0.367);
+ CellMacros::updateInverter(this, "INV1", drive_strength_ * 1.0);
+
+ // Cache area result
+ double area = 0.0;
+ area += gate_pitch * getTotalHeight() * 1;
+ area += gate_pitch * getTotalHeight() * getGenProperties()->get("INV0_GatePitches").toDouble();
+ area += gate_pitch * getTotalHeight() * getGenProperties()->get("INV1_GatePitches").toDouble();
+ cache->set(cell_name + "->ActiveArea", area);
+ Log::printLine(cell_name + "->ActiveArea=" + (String)area);
+
+ // --------------------------------------------------------------------
+ // Leakage Model Calculation
+ // --------------------------------------------------------------------
+ // Cache leakage power results (for every single signal combination)
+ double leakage_0 = 0.0; // !A
+ double leakage_1 = 0.0; // A
+
+ leakage_0 += getGenProperties()->get("INV0_LeakagePower_0").toDouble();
+ leakage_0 += getGenProperties()->get("INV1_LeakagePower_1").toDouble();
+
+ leakage_1 += getGenProperties()->get("INV0_LeakagePower_1").toDouble();
+ leakage_1 += getGenProperties()->get("INV1_LeakagePower_0").toDouble();
+
+ cache->set(cell_name + "->Leakage->!A", leakage_0);
+ cache->set(cell_name + "->Leakage->A", leakage_1);
+ Log::printLine(cell_name + "->Leakage->!A=" + (String) leakage_0);
+ Log::printLine(cell_name + "->Leakage->A=" + (String) leakage_1);
+ // --------------------------------------------------------------------
+
+ // --------------------------------------------------------------------
+ // Get Node Capacitances
+ // --------------------------------------------------------------------
+ double a_cap = getNet("A")->getTotalDownstreamCap();
+ double y_b_cap = getNet("Y_b")->getTotalDownstreamCap();
+ double y_cap = getNet("Y")->getTotalDownstreamCap();
+
+ cache->set(cell_name + "->Cap->A", a_cap);
+ cache->set(cell_name + "->Cap->Y_b", y_b_cap);
+ cache->set(cell_name + "->Cap->Y", y_cap);
+ Log::printLine(cell_name + "->Cap->A_Cap=" + (String) a_cap);
+ Log::printLine(cell_name + "->Cap->Y_b_Cap=" + (String) y_b_cap);
+ Log::printLine(cell_name + "->Cap->Y_Cap=" + (String) y_cap);
+ // --------------------------------------------------------------------
+
+ // --------------------------------------------------------------------
+ // Build Internal Delay Model
+ // --------------------------------------------------------------------
+ double y_ron = getDriver("INV1_RonZN")->getOutputRes();
+ double a_to_y_delay = getDriver("INV0_RonZN")->calculateDelay() +
+ getDriver("INV1_RonZN")->calculateDelay();
+
+ cache->set(cell_name + "->DriveRes->Y", y_ron);
+ cache->set(cell_name + "->Delay->A_to_Y", a_to_y_delay);
+ Log::printLine(cell_name + "->DriveRes->Y=" + (String) y_ron);
+ Log::printLine(cell_name + "->Delay->A_to_Y=" + (String) a_to_y_delay);
+ // --------------------------------------------------------------------
+
+ return;
+ }
+} // namespace DSENT
+
diff --git a/ext/dsent/model/std_cells/BUF.h b/ext/dsent/model/std_cells/BUF.h
new file mode 100644
index 000000000..1c85b2a44
--- /dev/null
+++ b/ext/dsent/model/std_cells/BUF.h
@@ -0,0 +1,33 @@
+#ifndef __DSENT_MODEL_STD_CELLS_BUF_H__
+#define __DSENT_MODEL_STD_CELLS_BUF_H__
+
+#include "util/CommonType.h"
+#include "model/std_cells/StdCell.h"
+
+namespace DSENT
+{
+ class BUF : public StdCell
+ {
+ public:
+ BUF(const String& instance_name_, const TechModel* tech_model_);
+ virtual ~BUF();
+
+ public:
+ // Set a list of properties' name needed to construct model
+ void initProperties();
+ // Cache the standard cell
+ void cacheStdCell(StdCellLib* cell_lib_, double drive_strength_);
+
+ protected:
+ // Build the model
+ virtual void constructModel();
+ virtual void updateModel();
+ virtual void evaluateModel();
+ virtual void useModel();
+ virtual void propagateTransitionInfo();
+
+ }; // class BUF
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_STD_CELLS_BUF_H__
+
diff --git a/ext/dsent/model/std_cells/CellMacros.cc b/ext/dsent/model/std_cells/CellMacros.cc
new file mode 100644
index 000000000..5b243942a
--- /dev/null
+++ b/ext/dsent/model/std_cells/CellMacros.cc
@@ -0,0 +1,477 @@
+#include "model/std_cells/CellMacros.h"
+
+#include <cmath>
+#include <vector>
+
+#include "model/std_cells/StdCell.h"
+#include "model/timing_graph/ElectricalNet.h"
+#include "model/timing_graph/ElectricalDriver.h"
+#include "model/timing_graph/ElectricalLoad.h"
+
+namespace DSENT
+{
+ //-------------------------------------------------------------------------
+ // NOR2 Macro (TODO: Generalize to N-input macro once leakage calc is done)
+ //-------------------------------------------------------------------------
+ void CellMacros::addNor2(StdCell* cell_, const String& name_,
+ bool sizable_, bool a1_to_zn_path_, bool a2_to_zn_path_,
+ const String& a1_net_, const String& a2_net_, const String& zn_net_)
+ {
+ //Create electrical timing model for the nand
+ // Construct loads and drivers
+ cell_->createLoad(name_ + "_CgA1");
+ cell_->createLoad(name_ + "_CgA2");
+ cell_->createLoad(name_ + "_CdZN");
+ cell_->createDriver(name_ + "_RonZN", sizable_);
+
+ //Get references to loads and drivers
+ ElectricalLoad* gate_a1_load = cell_->getLoad(name_ + "_CgA1");
+ ElectricalLoad* gate_a2_load = cell_->getLoad(name_ + "_CgA2");
+ ElectricalLoad* drain_load = cell_->getLoad(name_ + "_CdZN");
+ ElectricalDriver* zn_drive = cell_->getDriver(name_ + "_RonZN");
+ ElectricalNet* a1_net = cell_->getNet(a1_net_);
+ ElectricalNet* a2_net = cell_->getNet(a2_net_);
+ ElectricalNet* zn_net = cell_->getNet(zn_net_);
+
+ //Add loads and drivers to the specified nets
+ a1_net->addDownstreamNode(gate_a1_load);
+ a2_net->addDownstreamNode(gate_a2_load);
+ zn_net->addDownstreamNode(drain_load);
+ if (a1_to_zn_path_) gate_a1_load->addDownstreamNode(zn_drive);
+ if (a2_to_zn_path_) gate_a2_load->addDownstreamNode(zn_drive);
+ zn_drive->addDownstreamNode(zn_net);
+
+ return;
+ }
+
+ void CellMacros::updateNor2(StdCell* cell_, const String& name_, double normalized_size_)
+ {
+ ASSERT(normalized_size_ >= 0.0, "[Error] " + cell_->getInstanceName() +
+ " -> Cannot update a macro with a negative normalized size!");
+
+ //Grab pointer to tech model
+ const TechModel* tech = cell_->getTechModel();
+
+ // Get technology parameters
+ double vdd = tech->get("Vdd");
+ double gate_cap = tech->get("Gate->CapPerWidth");
+ double drain_cap = tech->get("Drain->CapPerWidth");
+ double nmos_eff_res = tech->get("Nmos->EffResWidth");
+ double pmos_eff_res = tech->get("Pmos->EffResWidth");
+ double pmos_eff_res_stack_ratio = tech->get("Pmos->EffResStackRatio");
+ double gate_pitch_contacted = tech->get("Gate->PitchContacted");
+ double metal1_wire_min_width = tech->get("Wire->Metal1->MinWidth");
+
+ //Calculate number of folds and gate pitches needed
+ unsigned int folds = (normalized_size_ < 1.0) ? 1 : (unsigned int)ceil(normalized_size_);
+ cell_->getGenProperties()->set(name_ + "_GatePitches", 2 * folds);
+
+ //Calculate widths, making sure they are above the minimum width
+ double nmos_width = std::max(calculateNmosWidth(cell_, 1, 2, 1) * normalized_size_ / folds, (double) tech->get("Gate->MinWidth"));
+ double pmos_width = std::max(calculatePmosWidth(cell_, 1, 2, 2) * normalized_size_ / folds, (double) tech->get("Gate->MinWidth"));
+
+ //Calculate leakage power for each given input state
+ double leakage_power_00 = vdd * folds * 2 * tech->calculateNmosLeakageCurrent(1, nmos_width, 0x0);
+ double leakage_power_01 = vdd * folds * tech->calculatePmosLeakageCurrent(2, pmos_width, ~0x1);
+ double leakage_power_10 = vdd * folds * tech->calculatePmosLeakageCurrent(2, pmos_width, ~0x2);
+ double leakage_power_11 = vdd * folds * tech->calculatePmosLeakageCurrent(2, pmos_width, ~0x3);
+ cell_->getGenProperties()->set(name_ + "_LeakagePower_00", leakage_power_00);
+ cell_->getGenProperties()->set(name_ + "_LeakagePower_01", leakage_power_01);
+ cell_->getGenProperties()->set(name_ + "_LeakagePower_10", leakage_power_10);
+ cell_->getGenProperties()->set(name_ + "_LeakagePower_11", leakage_power_11);
+
+ //Calculate R_on and capacitances
+ double pmos_stack2_balance = 1.0 + pmos_eff_res_stack_ratio;
+ double c_g = (nmos_width + pmos_width) * gate_cap * folds;
+ double c_d = (2 * pmos_width + 2 * nmos_width) * drain_cap * folds;
+ double r_on = (nmos_eff_res / nmos_width + pmos_stack2_balance * pmos_eff_res / pmos_width) / (folds * 2.0);
+
+ // Estimate the wire cap and add them all at the output
+ double cell_height = cell_->getTotalHeight();
+ double wire_width = metal1_wire_min_width;
+ double wire_spacing = gate_pitch_contacted - metal1_wire_min_width;
+ double wire_length = 2.0 * folds * cell_height;
+ double wire_cap = tech->calculateWireCapacitance("Metal1", wire_width, wire_spacing, wire_length);
+
+ // Construct equivalent load and drive strength
+ cell_->getLoad(name_ + "_CgA1")->setLoadCap(c_g);
+ cell_->getLoad(name_ + "_CgA2")->setLoadCap(c_g);
+ cell_->getLoad(name_ + "_CdZN")->setLoadCap(c_d + wire_cap);
+ cell_->getDriver(name_ + "_RonZN")->setOutputRes(r_on);
+
+ // Calculate flip energies
+ double zn_flip_energy = 0.5 * (c_d + wire_cap) * vdd * vdd;
+ double a1_flip_energy = 0.5 * c_g * vdd * vdd;
+ double a2_flip_energy = 0.5 * c_g * vdd * vdd;
+ cell_->getGenProperties()->set(name_ + "_ZN_Flip", zn_flip_energy);
+ cell_->getGenProperties()->set(name_ + "_A1_Flip", a1_flip_energy);
+ cell_->getGenProperties()->set(name_ + "_A2_Flip", a2_flip_energy);
+ }
+ //-------------------------------------------------------------------------
+
+ //-------------------------------------------------------------------------
+ // NAND2 Macro (TODO: Generalize to N-input macro once leakage calc is done)
+ //-------------------------------------------------------------------------
+ //Adds a NAND2 to the standard cell, normalized to some size
+ void CellMacros::addNand2(StdCell* cell_, const String& name_,
+ bool sizable_, bool a1_to_zn_path_, bool a2_to_zn_path_,
+ const String& a1_net_, const String& a2_net_, const String& zn_net_)
+ {
+ //Create electrical timing model for the nor
+ // Construct loads and drivers
+ cell_->createLoad(name_ + "_CgA1");
+ cell_->createLoad(name_ + "_CgA2");
+ cell_->createLoad(name_ + "_CdZN");
+ cell_->createDriver(name_ + "_RonZN", sizable_);
+
+ //Get references to loads and drivers
+ ElectricalLoad* gate_a1_load = cell_->getLoad(name_ + "_CgA1");
+ ElectricalLoad* gate_a2_load = cell_->getLoad(name_ + "_CgA2");
+ ElectricalLoad* drain_load = cell_->getLoad(name_ + "_CdZN");
+ ElectricalDriver* zn_drive = cell_->getDriver(name_ + "_RonZN");
+ ElectricalNet* a1_net = cell_->getNet(a1_net_);
+ ElectricalNet* a2_net = cell_->getNet(a2_net_);
+ ElectricalNet* zn_net = cell_->getNet(zn_net_);
+
+ a1_net->addDownstreamNode(gate_a1_load);
+ a2_net->addDownstreamNode(gate_a2_load);
+ zn_net->addDownstreamNode(drain_load);
+ if (a1_to_zn_path_) gate_a1_load->addDownstreamNode(zn_drive);
+ if (a2_to_zn_path_) gate_a2_load->addDownstreamNode(zn_drive);
+ zn_drive->addDownstreamNode(zn_net);
+
+ return;
+ }
+
+ //Updates a NAND2 to to the standard cell, normalized to some size
+ void CellMacros::updateNand2(StdCell* cell_, const String& name_, double normalized_size_)
+ {
+ ASSERT(normalized_size_ >= 0.0, "[Error] " + cell_->getInstanceName() +
+ " -> Cannot update a macro with a negative normalized size!");
+
+ //Grab pointer to tech model
+ const TechModel* tech = cell_->getTechModel();
+
+ // Get technology parameters
+ double vdd = tech->get("Vdd");
+ double gate_cap = tech->get("Gate->CapPerWidth");
+ double drain_cap = tech->get("Drain->CapPerWidth");
+ double nmos_eff_res = tech->get("Nmos->EffResWidth");
+ double pmos_eff_res = tech->get("Pmos->EffResWidth");
+ double nmos_eff_res_stack_ratio = tech->get("Nmos->EffResStackRatio");
+ double gate_pitch_contacted = tech->get("Gate->PitchContacted");
+ double metal1_wire_min_width = tech->get("Wire->Metal1->MinWidth");
+
+ //Calculate number of folds needed
+ unsigned int folds = (normalized_size_ < 1.0) ? 1 : (unsigned int)ceil(normalized_size_);
+ cell_->getGenProperties()->set(name_ + "_GatePitches", 2 * folds);
+
+ //Calculate widths, making sure they are above the minimum width
+ double nmos_width = std::max(calculateNmosWidth(cell_, 2, 1, 2) * normalized_size_ / folds, (double) tech->get("Gate->MinWidth"));
+ double pmos_width = std::max(calculatePmosWidth(cell_, 2, 1, 1) * normalized_size_ / folds, (double) tech->get("Gate->MinWidth"));
+
+ // Leakage power calculation
+ double leakage_power_00 = vdd * folds * tech->calculateNmosLeakageCurrent(2, nmos_width, 0x0);
+ double leakage_power_01 = vdd * folds * tech->calculateNmosLeakageCurrent(2, nmos_width, 0x1);
+ double leakage_power_10 = vdd * folds * tech->calculateNmosLeakageCurrent(2, nmos_width, 0x2);
+ double leakage_power_11 = vdd * folds * 2 * tech->calculatePmosLeakageCurrent(1, pmos_width, ~0x3);
+ cell_->getGenProperties()->set(name_ + "_LeakagePower_00", leakage_power_00);
+ cell_->getGenProperties()->set(name_ + "_LeakagePower_01", leakage_power_01);
+ cell_->getGenProperties()->set(name_ + "_LeakagePower_10", leakage_power_10);
+ cell_->getGenProperties()->set(name_ + "_LeakagePower_11", leakage_power_11);
+
+ // Get input parameters
+ double nmos_stack2_balance = 1.0 + nmos_eff_res_stack_ratio;
+
+ //Calculate caps
+ double c_g = (nmos_width + pmos_width) * gate_cap * folds;
+ double c_d = (2 * pmos_width + 2 * nmos_width) * drain_cap * folds;
+ double r_on = (nmos_stack2_balance * nmos_eff_res / nmos_width + pmos_eff_res / pmos_width) / (folds * 2.0);
+
+ // Estimate the wire cap and add them all at the output
+ double cell_height = cell_->getTotalHeight();
+ double wire_width = metal1_wire_min_width;
+ double wire_spacing = gate_pitch_contacted - metal1_wire_min_width;
+ double wire_length = 2.0 * folds * cell_height;
+ double wire_cap = tech->calculateWireCapacitance("Metal1", wire_width, wire_spacing, wire_length);
+
+ // Construct equivalent load and drive strength
+ cell_->getLoad(name_ + "_CgA1")->setLoadCap(c_g);
+ cell_->getLoad(name_ + "_CgA2")->setLoadCap(c_g);
+ cell_->getLoad(name_ + "_CdZN")->setLoadCap(c_d + wire_cap);
+ cell_->getDriver(name_ + "_RonZN")->setOutputRes(r_on);
+
+ // Calculate flip energies
+ double zn_flip_energy = 0.5 * (c_d + wire_cap) * vdd * vdd;
+ double a1_flip_energy = 0.5 * c_g * vdd * vdd;
+ double a2_flip_energy = 0.5 * c_g * vdd * vdd;
+ cell_->getGenProperties()->set(name_ + "_ZN_Flip", zn_flip_energy);
+ cell_->getGenProperties()->set(name_ + "_A1_Flip", a1_flip_energy);
+ cell_->getGenProperties()->set(name_ + "_A2_Flip", a2_flip_energy);
+ }
+ //-------------------------------------------------------------------------
+
+ //-------------------------------------------------------------------------
+ // INV Macro
+ //-------------------------------------------------------------------------
+ //Adds an inverter to the model, normalized to some size
+ void CellMacros::addInverter(StdCell* cell_, const String& name_,
+ bool sizable_, bool a_to_zn_path_,
+ const String& a_net_, const String& zn_net_)
+ {
+ //Create electrical timing model for the inverter
+ // Construct loads and drivers
+ cell_->createLoad(name_ + "_CgA");
+ cell_->createLoad(name_ + "_CdZN");
+ cell_->createDriver(name_ + "_RonZN", sizable_);
+
+ //Get references to loads and drivers
+ ElectricalLoad* gate_load = cell_->getLoad(name_ + "_CgA");
+ ElectricalLoad* drain_load = cell_->getLoad(name_ + "_CdZN");
+ ElectricalDriver* out_drive = cell_->getDriver(name_ + "_RonZN");
+ ElectricalNet* a_net = cell_->getNet(a_net_);
+ ElectricalNet* zn_net = cell_->getNet(zn_net_);
+
+ // Setup connectivity of loads and drivers
+ a_net->addDownstreamNode(gate_load);
+ if (a_to_zn_path_) gate_load->addDownstreamNode(out_drive);
+ zn_net->addDownstreamNode(drain_load);
+ out_drive->addDownstreamNode(zn_net);
+
+ return;
+ }
+
+ //Updates the numbers of an inverter for some normalized size
+ void CellMacros::updateInverter(StdCell* cell_, const String& name_, double normalized_size_)
+ {
+ ASSERT(normalized_size_ >= 0.0, "[Error] " + cell_->getInstanceName() +
+ " -> Cannot update a macro with a negative normalized size!");
+
+ //Grab pointer to tech model
+ const TechModel* tech = cell_->getTechModel();
+
+ //Get values from technology library
+ double vdd = tech->get("Vdd");
+ double gate_cap = tech->get("Gate->CapPerWidth");
+ double drain_cap = tech->get("Drain->CapPerWidth");
+ double nmos_eff_res = tech->get("Nmos->EffResWidth");
+ double pmos_eff_res = tech->get("Pmos->EffResWidth");
+ double gate_pitch_contacted = tech->get("Gate->PitchContacted");
+ double metal1_wire_min_width = tech->get("Wire->Metal1->MinWidth");
+
+ //Calculate number of folds needed
+ unsigned int folds = (normalized_size_ < 1.0) ? 1 : (unsigned int)ceil(normalized_size_);
+ cell_->getGenProperties()->set(name_ + "_GatePitches", folds);
+
+ //Calculate widths, making sure they are above the minimum width
+ double nmos_width = std::max(calculateNmosWidth(cell_, 1, 1, 1) * normalized_size_ / folds, (double) tech->get("Gate->MinWidth"));
+ double pmos_width = std::max(calculatePmosWidth(cell_, 1, 1, 1) * normalized_size_ / folds, (double) tech->get("Gate->MinWidth"));
+
+ //Calculate leakage power for each given input state
+ double leakage_power_0 = vdd * folds * tech->calculateNmosLeakageCurrent(1, nmos_width, 0x0);
+ double leakage_power_1 = vdd * folds * tech->calculatePmosLeakageCurrent(1, pmos_width, ~0x1);
+ cell_->getGenProperties()->set(name_ + "_LeakagePower_0", leakage_power_0);
+ cell_->getGenProperties()->set(name_ + "_LeakagePower_1", leakage_power_1);
+
+ //Calculate caps
+ double c_g = (nmos_width + pmos_width) * gate_cap * folds;
+ double c_d = (pmos_width + nmos_width) * drain_cap * folds;
+ double r_on = (nmos_eff_res / nmos_width + pmos_eff_res / pmos_width) / (folds * 2.0);
+
+ // Estimate the wire cap and add them all at the output
+ double cell_height = cell_->getTotalHeight();
+ double wire_width = metal1_wire_min_width;
+ double wire_spacing = gate_pitch_contacted - metal1_wire_min_width;
+ double wire_length = folds * cell_height;
+ double wire_cap = tech->calculateWireCapacitance("Metal1", wire_width, wire_spacing, wire_length);
+
+ // Construct equivalent load and drive strength
+ cell_->getLoad(name_ + "_CgA")->setLoadCap(c_g);
+ cell_->getLoad(name_ + "_CdZN")->setLoadCap(c_d + wire_cap);
+ cell_->getDriver(name_ + "_RonZN")->setOutputRes(r_on);
+
+ // Calculate flip energy (output flip)
+ // Calculate flip energies
+ double zn_flip_energy = 0.5 * (c_d + wire_cap) * vdd * vdd;
+ double a_flip_energy = 0.5 * c_g * vdd * vdd;
+ cell_->getGenProperties()->set(name_ + "_ZN_Flip", zn_flip_energy);
+ cell_->getGenProperties()->set(name_ + "_A_Flip", a_flip_energy);
+
+ return;
+ }
+ //-------------------------------------------------------------------------
+
+ //-------------------------------------------------------------------------
+ // INVZ Macro
+ //-------------------------------------------------------------------------
+ //Adds a tristated inverter to the model, normalized to some size
+ void CellMacros::addTristate(StdCell* cell_, const String& name_,
+ bool sizable_, bool a_to_zn_path_, bool oe_to_zn_path_, bool oen_to_zn_path_,
+ const String& a_net_, const String& oe_net_, const String& oen_net_, const String& zn_net_)
+ {
+ // Construct loads and drivers
+ cell_->createLoad(name_ + "_CgA");
+ cell_->createLoad(name_ + "_CgOE");
+ cell_->createLoad(name_ + "_CgOEN");
+ cell_->createLoad(name_ + "_CdZN");
+ cell_->createDriver(name_ + "_RonZN", sizable_);
+
+ // Get references to loads, nets and drivers
+ ElectricalLoad* gate_a_load = cell_->getLoad(name_ + "_CgA");
+ ElectricalLoad* gate_oe_load = cell_->getLoad(name_ + "_CgOE");
+ ElectricalLoad* gate_oen_load = cell_->getLoad(name_ + "_CgOEN");
+ ElectricalLoad* drain_load = cell_->getLoad(name_ + "_CdZN");
+ ElectricalDriver* out_drive = cell_->getDriver(name_ + "_RonZN");
+ ElectricalNet* a_net = cell_->getNet(a_net_);
+ ElectricalNet* oe_net = cell_->getNet(oe_net_);
+ ElectricalNet* oen_net = cell_->getNet(oen_net_);
+ ElectricalNet* zn_net = cell_->getNet(zn_net_);
+
+ // Setup connectivity of loads and drivers
+ a_net->addDownstreamNode(gate_a_load);
+ oe_net->addDownstreamNode(gate_oe_load);
+ oen_net->addDownstreamNode(gate_oen_load);
+ if (a_to_zn_path_) gate_a_load->addDownstreamNode(out_drive);
+ if (oe_to_zn_path_) gate_oe_load->addDownstreamNode(out_drive);
+ if (oen_to_zn_path_) gate_oen_load->addDownstreamNode(out_drive);
+ zn_net->addDownstreamNode(drain_load);
+ out_drive->addDownstreamNode(zn_net);
+
+ return;
+ }
+
+ //Updates the numbers of an inverter for some normalized size
+ void CellMacros::updateTristate(StdCell* cell_, const String& name_, double normalized_size_)
+ {
+ ASSERT(normalized_size_ >= 0.0, "[Error] " + cell_->getInstanceName() +
+ " -> Cannot update a macro with a negative normalized size!");
+
+ //Grab pointer to tech model
+ const TechModel* tech = cell_->getTechModel();
+
+ //Get values from technology library
+ double vdd = tech->get("Vdd");
+ double gate_cap = tech->get("Gate->CapPerWidth");
+ double drain_cap = tech->get("Drain->CapPerWidth");
+ double nmos_eff_res = tech->get("Nmos->EffResWidth");
+ double pmos_eff_res = tech->get("Pmos->EffResWidth");
+ double pmos_eff_res_stack_ratio = tech->get("Pmos->EffResStackRatio");
+ double nmos_eff_res_stack_ratio = tech->get("Nmos->EffResStackRatio");
+ double gate_pitch_contacted = tech->get("Gate->PitchContacted");
+ double metal1_wire_min_width = tech->get("Wire->Metal1->MinWidth");
+
+ //Calculate number of folds and gate pitches needed
+ unsigned int folds = (normalized_size_ < 1.0) ? 1 : (unsigned int)ceil(normalized_size_);
+ cell_->getGenProperties()->set(name_ + "_GatePitches", 2 * folds);
+
+ //Calculate widths, making sure they are above the minimum width
+ double nmos_width = std::max(calculateNmosWidth(cell_, 2, 2, 2) * normalized_size_ / folds, (double) tech->get("Gate->MinWidth"));
+ double pmos_width = std::max(calculatePmosWidth(cell_, 2, 2, 2) * normalized_size_ / folds, (double) tech->get("Gate->MinWidth"));
+
+ //Calculate leakage power for each given input state
+ //if output_enable = 0, then it is possible that the PMOS may leak (if output = 0),
+ //or the NMOS will leak (if output = 1)
+
+ //OE OEN A _ ZN
+ double leakage_power_010_0 = vdd * folds * tech->calculatePmosLeakageCurrent(2, pmos_width, ~0x2);
+ double leakage_power_010_1 = vdd * folds * tech->calculateNmosLeakageCurrent(2, nmos_width, 0x0);
+ double leakage_power_011_0 = vdd * folds * tech->calculatePmosLeakageCurrent(2, pmos_width, ~0x3);
+ double leakage_power_011_1 = vdd * folds * tech->calculateNmosLeakageCurrent(2, nmos_width, 0x1);
+ double leakage_power_100_1 = vdd * folds * tech->calculateNmosLeakageCurrent(2, nmos_width, 0x2);
+ double leakage_power_101_0 = vdd * folds * tech->calculatePmosLeakageCurrent(2, pmos_width, ~0x1);
+ cell_->getGenProperties()->set(name_ + "_LeakagePower_010_0", leakage_power_010_0);
+ cell_->getGenProperties()->set(name_ + "_LeakagePower_010_1", leakage_power_010_1);
+ cell_->getGenProperties()->set(name_ + "_LeakagePower_011_0", leakage_power_011_0);
+ cell_->getGenProperties()->set(name_ + "_LeakagePower_011_1", leakage_power_011_1);
+ cell_->getGenProperties()->set(name_ + "_LeakagePower_100_1", leakage_power_100_1);
+ cell_->getGenProperties()->set(name_ + "_LeakagePower_101_0", leakage_power_101_0);
+
+ //Caculate stack balance
+ double pmos_stack2_balance = 1.0 + pmos_eff_res_stack_ratio;
+ double nmos_stack2_balance = 1.0 + nmos_eff_res_stack_ratio;
+
+ //Calculate caps
+ double c_g_a = (nmos_width + pmos_width) * gate_cap * folds;
+ double c_g_oe = nmos_width * gate_cap * folds;
+ double c_g_oen = pmos_width * gate_cap * folds;
+ double c_d = (2 * pmos_width + 2 * nmos_width) * drain_cap * folds;
+ double r_on = (nmos_stack2_balance * nmos_eff_res / nmos_width + pmos_stack2_balance * pmos_eff_res / pmos_width) / (folds * 2.0);
+
+ // Estimate the wire cap and add them all at the output
+ double cell_height = cell_->getTotalHeight();
+ double wire_width = metal1_wire_min_width;
+ double wire_spacing = gate_pitch_contacted - metal1_wire_min_width;
+ double wire_length = 2.0 * folds * cell_height;
+ double wire_cap = tech->calculateWireCapacitance("Metal1", wire_width, wire_spacing, wire_length);
+
+ // Construct equivalent load and drive strength
+ cell_->getLoad(name_ + "_CgA")->setLoadCap(c_g_a);
+ cell_->getLoad(name_ + "_CgOE")->setLoadCap(c_g_oe);
+ cell_->getLoad(name_ + "_CgOEN")->setLoadCap(c_g_oen);
+ cell_->getLoad(name_ + "_CdZN")->setLoadCap(c_d + wire_cap);
+ cell_->getDriver(name_ + "_RonZN")->setOutputRes(r_on);
+
+ // Calculate flip energy (output flip)
+ double zn_flip_energy = 0.5 * (c_d + wire_cap) * vdd * vdd;
+ double a_flip_energy = 0.5 * c_g_a * vdd * vdd;
+ double oe_flip_energy = 0.5 * c_g_oe * vdd * vdd;
+ double oen_flip_energy = 0.5 * c_g_oen * vdd * vdd;
+ cell_->getGenProperties()->set(name_ + "_ZN_Flip", zn_flip_energy);
+ cell_->getGenProperties()->set(name_ + "_A_Flip", a_flip_energy);
+ cell_->getGenProperties()->set(name_ + "_OE_Flip", oe_flip_energy);
+ cell_->getGenProperties()->set(name_ + "_OEN_Flip", oen_flip_energy);
+ return;
+ }
+ //-------------------------------------------------------------------------
+
+
+ //-------------------------------------------------------------------------
+ // Helper Functions
+ //-------------------------------------------------------------------------
+ //Returns the width of NMOS transistors, given the NMOS and PMOS stacking
+ double CellMacros::calculateNmosWidth(const StdCell* cell_, unsigned int max_stacked_nmos_, unsigned int max_stacked_pmos_, unsigned int current_stacked_nmos_)
+ {
+ //Grab pointer to tech model
+ const TechModel* tech = cell_->getTechModel();
+
+ double nmos_eff_res_stack_ratio = tech->get("Nmos->EffResStackRatio");
+ double pmos_eff_res_stack_ratio = tech->get("Pmos->EffResStackRatio");
+
+ double nmos_stack_balance = 1.0 + nmos_eff_res_stack_ratio * (double) (max_stacked_nmos_ - 1);
+ double pmos_stack_balance = 1.0 + pmos_eff_res_stack_ratio * (double) (max_stacked_pmos_ - 1);
+ double current_nmos_stack_balance = 1.0 + nmos_eff_res_stack_ratio * (double) (current_stacked_nmos_ - 1);
+
+ double pn_ratio = cell_->getPToNRatio();
+ double active_height = cell_->getActiveHeight();
+
+ //Calculate the width of the current device
+ double nmos_width = active_height * current_nmos_stack_balance / (nmos_stack_balance + pn_ratio * pmos_stack_balance);
+
+ return nmos_width;
+ }
+
+ //Returns the width of PMOS transistors, given the NMOS and PMOS stacking
+ double CellMacros::calculatePmosWidth(const StdCell* cell_, unsigned int max_stacked_nmos_, unsigned int max_stacked_pmos_, unsigned int current_stacked_pmos_)
+ {
+ //Grab pointer to tech model
+ const TechModel* tech = cell_->getTechModel();
+
+ double nmos_eff_res_stack_ratio = tech->get("Nmos->EffResStackRatio");
+ double pmos_eff_res_stack_ratio = tech->get("Pmos->EffResStackRatio");
+
+ double nmos_stack_balance = 1.0 + nmos_eff_res_stack_ratio * (double) (max_stacked_nmos_ - 1);
+ double pmos_stack_balance = 1.0 + pmos_eff_res_stack_ratio * (double) (max_stacked_pmos_ - 1);
+ double current_pmos_stack_balance = 1.0 + pmos_eff_res_stack_ratio * (double) (current_stacked_pmos_ - 1);
+
+ double pn_ratio = cell_->getPToNRatio();
+ double active_height = cell_->getActiveHeight();
+
+ //Calculate the width of the current device
+ double pmos_width = active_height * current_pmos_stack_balance * pn_ratio / (nmos_stack_balance + pn_ratio * pmos_stack_balance);
+
+ return pmos_width;
+ }
+ //-------------------------------------------------------------------------
+
+} // namespace DSENT
+
diff --git a/ext/dsent/model/std_cells/CellMacros.h b/ext/dsent/model/std_cells/CellMacros.h
new file mode 100644
index 000000000..ce4b54473
--- /dev/null
+++ b/ext/dsent/model/std_cells/CellMacros.h
@@ -0,0 +1,57 @@
+#ifndef __DSENT_MODEL_STD_CELLS_CELLMACROS_H__
+#define __DSENT_MODEL_STD_CELLS_CELLMACROS_H__
+
+#include "util/CommonType.h"
+#include "model/std_cells/StdCell.h"
+
+namespace DSENT
+{
+ class StdCell;
+
+ // Contains cell macros that can be created within standard cells
+ class CellMacros
+ {
+ private :
+ CellMacros();
+ ~CellMacros();
+
+ public:
+ //NOR2 Macro
+ //Adds a NOR2 to the standard cell, normalized to some size
+ static void addNor2(StdCell* cell_, const String& name_, bool sizable_, bool a1_to_zn_path_, bool a2_to_zn_path_,
+ const String& a1_net_, const String& a2_net_, const String& zn_net_);
+ //Updates a NOR2 to to the standard cell, normalized to some size
+ static void updateNor2(StdCell* cell_, const String& name_, double normalized_size_);
+
+ //NAND2 Macro
+ //Adds a NAND2 to the standard cell, normalized to some size
+ static void addNand2(StdCell* cell_, const String& name_, bool sizable_, bool a1_to_zn_path_, bool a2_to_zn_path_,
+ const String& a1_net_, const String& a2_net_, const String& zn_net_);
+ //Updates a NAND2 to to the standard cell, normalized to some size
+ static void updateNand2(StdCell* cell_, const String& name_, double normalized_size_);
+
+ //INVERTER Macro
+ //Adds a inverter to the standard cell, normalized to some size
+ static void addInverter(StdCell* cell_, const String& name_, bool sizable_, bool a_to_zn_path_,
+ const String& a_net_, const String& zn_net_);
+ //Updates an inverter to to the standard cell, normalized to some size
+ static void updateInverter(StdCell* cell_, const String& name_, double normalized_size_);
+
+ //INVZ Macro
+ //Adds a tristated inverter to the standard cell, normalized to some size
+ static void addTristate(StdCell* cell_, const String& name_, bool sizable_, bool a_to_zn_path_, bool oe_to_zn_path_, bool oen_to_zn_path_,
+ const String& a_net_, const String& oe_net_, const String& oen_net_, const String& zn_net_);
+ //Updates an tristated inverter to to the standard cell, normalized to some size
+ static void updateTristate(StdCell* cell_, const String& name_, double normalized_size_);
+
+ //Helper functions
+ //Returns the width of NMOS transistors, given the NMOS and PMOS stacking
+ static double calculateNmosWidth(const StdCell* cell_, unsigned int max_stacked_nmos_, unsigned int max_stacked_pmos_, unsigned int current_stack_nmos_);
+ //Returns the width of PMOS transistors, given the NMOS and PMOS stacking
+ static double calculatePmosWidth(const StdCell* cell_, unsigned int max_stacked_nmos_, unsigned int max_stacked_pmos_, unsigned int current_stack_pmos_);
+
+ }; // class CellMacros
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_STD_CELLS_CELLMACROS_H__
+
diff --git a/ext/dsent/model/std_cells/DFFQ.cc b/ext/dsent/model/std_cells/DFFQ.cc
new file mode 100644
index 000000000..9080a7211
--- /dev/null
+++ b/ext/dsent/model/std_cells/DFFQ.cc
@@ -0,0 +1,536 @@
+#include "model/std_cells/DFFQ.h"
+
+#include <cmath>
+
+#include "model/PortInfo.h"
+#include "model/EventInfo.h"
+#include "model/TransitionInfo.h"
+#include "model/std_cells/StdCellLib.h"
+#include "model/std_cells/CellMacros.h"
+#include "model/timing_graph/ElectricalNet.h"
+#include "model/timing_graph/ElectricalDriver.h"
+#include "model/timing_graph/ElectricalLoad.h"
+#include "model/timing_graph/ElectricalDelay.h"
+
+namespace DSENT
+{
+ using std::ceil;
+ using std::max;
+ using std::min;
+
+ DFFQ::DFFQ(const String& instance_name_, const TechModel* tech_model_)
+ : StdCell(instance_name_, tech_model_)
+ {
+ initProperties();
+ }
+
+ DFFQ::~DFFQ()
+ {}
+
+ void DFFQ::initProperties()
+ {
+ return;
+ }
+
+ void DFFQ::constructModel()
+ {
+ // All constructModel should do is create Area/NDDPower/Energy Results as
+ // well as instantiate any sub-instances using only the hard parameters
+
+ createInputPort("D");
+ createInputPort("CK");
+ createOutputPort("Q");
+
+ createLoad("D_Cap");
+ createLoad("CK_Cap");
+ createDelay("D_Setup_delay");
+ createDelay("CK_to_Q_delay");
+ createDriver("Q_Ron", true);
+
+ ElectricalLoad* d_cap = getLoad("D_Cap");
+ ElectricalLoad* ck_cap = getLoad("CK_Cap");
+ ElectricalDelay* d_setup_delay = getDelay("D_Setup_delay");
+ ElectricalDelay* ck_to_q_delay = getDelay("CK_to_Q_delay");
+ ElectricalDriver* q_ron = getDriver("Q_Ron");
+
+ getNet("D")->addDownstreamNode(d_cap);
+ getNet("CK")->addDownstreamNode(ck_cap);
+ d_cap->addDownstreamNode(d_setup_delay);
+ ck_cap->addDownstreamNode(ck_to_q_delay);
+ ck_to_q_delay->addDownstreamNode(q_ron);
+ q_ron->addDownstreamNode(getNet("Q"));
+
+ // Create Area result
+ // Create NDD Power result
+ createElectricalAtomicResults();
+ // Create CK Event Energy Result
+ createElectricalEventAtomicResult("CK");
+ getEventInfo("CK")->setTransitionInfo("CK", TransitionInfo(0.0, 1.0, 0.0));
+ // Create DFF Event Energy Result
+ createElectricalEventAtomicResult("DFFD");
+ getEventInfo("DFFD")->setTransitionInfo("CK", TransitionInfo(0.0, 1.0, 0.0));
+ createElectricalEventAtomicResult("DFFQ");
+ getEventInfo("DFFQ")->setTransitionInfo("CK", TransitionInfo(0.0, 1.0, 0.0));
+
+ // Update Idle event for leakage
+ // CK pin is assumed to be on all the time
+ EventInfo* idle_event_info = getEventInfo("Idle");
+ idle_event_info->setTransitionInfo("CK", TransitionInfo(0.0, 1.0, 0.0));
+ idle_event_info->setTransitionInfo("D", TransitionInfo(0.5, 0.0, 0.5));
+
+ return;
+ }
+
+ void DFFQ::updateModel()
+ {
+ // Get parameters
+ double drive_strength = getDrivingStrength();
+ Map<double>* cache = getTechModel()->getStdCellLib()->getStdCellCache();
+
+ // Standard cell cache string
+ String cell_name = "DFFQ_X" + (String) drive_strength;
+
+ // Get timing parameters
+ getLoad("D_Cap")->setLoadCap(cache->get(cell_name + "->Cap->D"));
+ getLoad("CK_Cap")->setLoadCap(cache->get(cell_name + "->Cap->CK"));
+ getDriver("Q_Ron")->setOutputRes(cache->get(cell_name + "->DriveRes->Q"));
+ getDelay("CK_to_Q_delay")->setDelay(cache->get(cell_name + "->Delay->CK_to_Q"));
+ getDelay("D_Setup_delay")->setDelay(cache->get(cell_name + "->Delay->D_Setup"));
+
+ // Set the cell area
+ getAreaResult("Active")->setValue(cache->get(cell_name + "->Area->Active"));
+ getAreaResult("Metal1Wire")->setValue(cache->get(cell_name + "->Area->Metal1Wire"));
+
+ return;
+ }
+
+ void DFFQ::evaluateModel()
+ {
+ return;
+ }
+
+ void DFFQ::useModel()
+ {
+ // Get parameters
+ double drive_strength = getDrivingStrength();
+ Map<double>* cache = getTechModel()->getStdCellLib()->getStdCellCache();
+
+ // Standard cell cache string
+ String cell_name = "DFFQ_X" + (String) drive_strength;
+
+ // Propagate the transition info and get P_D, P_M, and P_Q
+ propagateTransitionInfo();
+ double P_D = getInputPort("D")->getTransitionInfo().getProbability1();
+ double P_CK = getInputPort("CK")->getTransitionInfo().getProbability1();
+ double P_Q = getOutputPort("Q")->getTransitionInfo().getProbability1();
+ double CK_num_trans_01 = getInputPort("CK")->getTransitionInfo().getNumberTransitions01();
+ double D_num_trans_01 = getInputPort("D")->getTransitionInfo().getNumberTransitions01();
+ double M_num_trans_01 = m_trans_M_.getNumberTransitions01();
+ double Q_num_trans_01 = getOutputPort("Q")->getTransitionInfo().getNumberTransitions01();
+
+ // Calculate leakage
+ double leakage = 0;
+ leakage += cache->get(cell_name + "->Leakage->!D!CK!Q") * (1 - P_D) * (1 - P_CK) * (1 - P_Q);
+ leakage += cache->get(cell_name + "->Leakage->!D!CKQ") * (1 - P_D) * (1 - P_CK) * P_Q;
+ leakage += cache->get(cell_name + "->Leakage->!DCK!Q") * (1 - P_D) * P_CK * (1 - P_Q);
+ leakage += cache->get(cell_name + "->Leakage->!DCKQ") * (1 - P_D) * P_CK * P_Q;
+ leakage += cache->get(cell_name + "->Leakage->D!CK!Q") * P_D * (1 - P_CK) * (1 - P_Q);
+ leakage += cache->get(cell_name + "->Leakage->D!CKQ") * P_D * (1 - P_CK) * P_Q;
+ leakage += cache->get(cell_name + "->Leakage->DCK!Q") * P_D * P_CK * (1 - P_Q);
+ leakage += cache->get(cell_name + "->Leakage->DCKQ") * P_D * P_CK * P_Q;
+ getNddPowerResult("Leakage")->setValue(leakage);
+
+ // Get VDD
+ double vdd = getTechModel()->get("Vdd");
+
+ // Get capacitances
+ double ck_b_cap = cache->get(cell_name + "->Cap->CK_b");
+ double ck_i_cap = cache->get(cell_name + "->Cap->CK_i");
+ double d_b_cap = cache->get(cell_name + "->Cap->D_b");
+ double m_b_cap = cache->get(cell_name + "->Cap->M_b");
+ double m_cap = cache->get(cell_name + "->Cap->M");
+ double m_i_cap = cache->get(cell_name + "->Cap->M_i");
+ double q_b_cap = cache->get(cell_name + "->Cap->Q_b");
+ double q_cap = cache->get(cell_name + "->Cap->Q");
+ double q_load_cap = getNet("Q")->getTotalDownstreamCap();
+
+ // Calculate CK Event energy
+ double ck_event_energy = 0.0;
+ ck_event_energy += (ck_b_cap + ck_i_cap) * CK_num_trans_01;
+ ck_event_energy *= vdd * vdd;
+ getEventResult("CK")->setValue(ck_event_energy);
+ // Calculate DFFD Event energy
+ double dffd_event_energy = 0.0;
+ dffd_event_energy += (d_b_cap) * D_num_trans_01;
+ dffd_event_energy += (m_b_cap + m_cap) * M_num_trans_01;
+ dffd_event_energy *= vdd * vdd;
+ getEventResult("DFFD")->setValue(dffd_event_energy);
+ // Calculate DFFQ Event energy
+ double dffq_event_energy = 0.0;
+ dffq_event_energy += (m_i_cap + q_b_cap + q_cap + q_load_cap) * Q_num_trans_01;
+ dffq_event_energy *= vdd * vdd;
+ getEventResult("DFFQ")->setValue(dffq_event_energy);
+
+ return;
+ }
+
+ void DFFQ::propagateTransitionInfo()
+ {
+ const TransitionInfo& trans_CK = getInputPort("CK")->getTransitionInfo();
+ const TransitionInfo& trans_D = getInputPort("D")->getTransitionInfo();
+
+ double CK_num_trans_01 = trans_CK.getNumberTransitions01();
+ double CK_num_trans_10 = CK_num_trans_01;
+ double CK_num_trans_00 = trans_CK.getNumberTransitions00();
+ double D_freq_mult = trans_D.getFrequencyMultiplier();
+
+ // If thre is no activity on the clock or D, assume M node is randomly distributed among 0 and 1
+ if(LibUtil::Math::isEqual(CK_num_trans_10 + CK_num_trans_00, 0.0) || LibUtil::Math::isEqual(D_freq_mult, 0.0))
+ {
+ m_trans_M_ = TransitionInfo(0.5, 0.0, 0.5);
+ }
+ // If the master latch is sampling just as fast or faster than input data signal
+ // Then it can capture all transitions (though it should be normalized to clock)
+ else if((CK_num_trans_10 + CK_num_trans_00) >= D_freq_mult)
+ {
+ m_trans_M_ = trans_D.scaleFrequencyMultiplier(CK_num_trans_10 + CK_num_trans_00);
+ }
+ // If the master latch is sampling slower than the input data signal, then input
+ // will look like they transition more
+ else
+ {
+ // Calculate scale ratio
+ double scale_ratio = (CK_num_trans_10 + CK_num_trans_00) / D_freq_mult;
+ // 00 and 11 transitions become fewer
+ double D_scaled_diff = 0.5 * (1 - scale_ratio) * (trans_D.getNumberTransitions00() + trans_D.getNumberTransitions11());
+ double D_scaled_num_trans_00 = trans_D.getNumberTransitions00() * scale_ratio;
+ double D_scaled_num_trans_11 = trans_D.getNumberTransitions11() * scale_ratio;
+ // 01 and 10 transitions become more frequent
+ double D_scaled_num_trans_10 = trans_D.getNumberTransitions01() + D_scaled_diff;
+
+ // Create final transition info, remembering to apply scaling ratio to normalize to CK
+ m_trans_M_ = TransitionInfo(D_scaled_num_trans_00 * scale_ratio,
+ D_scaled_num_trans_10 * scale_ratio,
+ D_scaled_num_trans_11 * scale_ratio);
+ }
+
+ // If the clock activity is 0 or if D activity is 0, then we assume that the output is randomly distributed among 0 and 1
+ if(LibUtil::Math::isEqual(CK_num_trans_01, 0.0) || LibUtil::Math::isEqual(D_freq_mult, 0.0))
+ {
+ getOutputPort("Q")->setTransitionInfo(TransitionInfo(0.5, 0.0, 0.5));
+ }
+ // If the DFF's CK is running at a higher frequency than D, Q is just D with a
+ // scaled up frequency multiplier
+ else if(CK_num_trans_01 >= D_freq_mult)
+ {
+ const TransitionInfo& trans_Q = trans_D.scaleFrequencyMultiplier(CK_num_trans_01);
+ getOutputPort("Q")->setTransitionInfo(trans_Q);
+ }
+ // If the DFF is sampling slower than the input data signal, then inputs
+ // will look like they transition more
+ else
+ {
+ // Calculate scale ratio
+ double scale_ratio = CK_num_trans_01 / D_freq_mult;
+ // 00 and 11 transitions become fewer
+ double D_scaled_diff = 0.5 * (1 - scale_ratio) * (trans_D.getNumberTransitions00() + trans_D.getNumberTransitions11());
+ double D_scaled_num_trans_00 = trans_D.getNumberTransitions00() * scale_ratio;
+ double D_scaled_num_trans_11 = trans_D.getNumberTransitions11() * scale_ratio;
+ // 01 and 10 transitions become more frequent
+ double D_scaled_num_trans_10 = trans_D.getNumberTransitions01() + D_scaled_diff;
+ const TransitionInfo trans_Q( D_scaled_num_trans_00 * scale_ratio,
+ D_scaled_num_trans_10 * scale_ratio,
+ D_scaled_num_trans_11 * scale_ratio);
+ getOutputPort("Q")->setTransitionInfo(trans_Q);
+ }
+ return;
+ }
+
+ // Creates the standard cell, characterizes and abstracts away the details
+ void DFFQ::cacheStdCell(StdCellLib* cell_lib_, double drive_strength_)
+ {
+ // Get parameters
+ double gate_pitch = cell_lib_->getTechModel()->get("Gate->PitchContacted");
+ Map<double>* cache = cell_lib_->getStdCellCache();
+
+ // Standard cell cache string
+ String cell_name = "DFFQ_X" + (String) drive_strength_;
+
+ Log::printLine("=== " + cell_name + " ===");
+
+
+ // Now actually build the full standard cell model
+ createInputPort("D");
+ createInputPort("CK");
+ createOutputPort("Q");
+
+ createNet("D_b");
+ createNet("M_b");
+ createNet("M");
+ createNet("M_i");
+ createNet("Q_b");
+ createNet("CK_b");
+ createNet("CK_i");
+
+ // Adds macros
+ CellMacros::addInverter(this, "INV1", false, true, "D", "D_b");
+ CellMacros::addInverter(this, "INV2", false, true, "M_b", "M");
+ CellMacros::addInverter(this, "INV3", false, true, "M_i", "Q_b");
+ CellMacros::addInverter(this, "INV4", true, true, "Q_b", "Q");
+ CellMacros::addInverter(this, "INV5", false, true, "CK", "CK_b");
+ CellMacros::addInverter(this, "INV6", false, true, "CK_b", "CK_i");
+ CellMacros::addTristate(this, "INVZ1", false, true, false, false, "D_b", "CK_b", "CK_i", "M_b"); //trace timing through A->ZN path only
+ CellMacros::addTristate(this, "INVZ2", false, false, false, false, "M", "CK_i", "CK_b", "M_b"); //don't trace timing through the feedback path
+ CellMacros::addTristate(this, "INVZ3", false, false, true, true, "M", "CK_i", "CK_b", "M_i"); //trace timing from OE->ZN and OEN->ZN paths only
+ CellMacros::addTristate(this, "INVZ4", false, false, false, false, "Q_b", "CK_b", "CK_i", "M_i"); //don't trace timing through the feedback path
+
+ // Update macros
+ CellMacros::updateInverter(this, "INV1", drive_strength_ * 0.125);
+ CellMacros::updateInverter(this, "INV2", drive_strength_ * 0.5);
+ CellMacros::updateInverter(this, "INV3", drive_strength_ * 0.5);
+ CellMacros::updateInverter(this, "INV4", drive_strength_ * 1.0);
+ CellMacros::updateInverter(this, "INV5", drive_strength_ * 0.125);
+ CellMacros::updateInverter(this, "INV6", drive_strength_ * 0.125);
+ CellMacros::updateTristate(this, "INVZ1", drive_strength_ * 0.5);
+ CellMacros::updateTristate(this, "INVZ2", drive_strength_ * 0.0625);
+ CellMacros::updateTristate(this, "INVZ3", drive_strength_ * 0.5);
+ CellMacros::updateTristate(this, "INVZ4", drive_strength_ * 0.0625);
+
+ // Cache area result
+ double area = 0.0;
+ area += gate_pitch * getTotalHeight() * 1;
+ area += gate_pitch * getTotalHeight() * getGenProperties()->get("INV1_GatePitches").toDouble();
+ area += gate_pitch * getTotalHeight() * getGenProperties()->get("INV2_GatePitches").toDouble();
+ area += gate_pitch * getTotalHeight() * getGenProperties()->get("INV3_GatePitches").toDouble();
+ area += gate_pitch * getTotalHeight() * getGenProperties()->get("INV4_GatePitches").toDouble();
+ area += gate_pitch * getTotalHeight() * getGenProperties()->get("INV5_GatePitches").toDouble();
+ area += gate_pitch * getTotalHeight() * getGenProperties()->get("INV6_GatePitches").toDouble();
+ area += gate_pitch * getTotalHeight() * getGenProperties()->get("INVZ1_GatePitches").toDouble();
+ area += gate_pitch * getTotalHeight() * getGenProperties()->get("INVZ2_GatePitches").toDouble();
+ area += gate_pitch * getTotalHeight() * getGenProperties()->get("INVZ3_GatePitches").toDouble();
+ area += gate_pitch * getTotalHeight() * getGenProperties()->get("INVZ4_GatePitches").toDouble();
+ cache->set(cell_name + "->Area->Active", area);
+ cache->set(cell_name + "->Area->Metal1Wire", area);
+ Log::printLine(cell_name + "->Area->Active=" + (String) area);
+ Log::printLine(cell_name + "->Area->Metal1Wire=" + (String) area);
+
+ // --------------------------------------------------------------------
+ // Leakage Model Calculation
+ // --------------------------------------------------------------------
+ // Cache leakage power results (for every single signal combination)
+ double leakage_000 = 0; //!D, !CK, !Q
+ double leakage_001 = 0; //!D, !CK, Q
+ double leakage_010 = 0; //!D, CK, !Q
+ double leakage_011 = 0; //!D, CK, Q
+ double leakage_100 = 0; //D, !CK, !Q
+ double leakage_101 = 0; //D, !CK, Q
+ double leakage_110 = 0; //D, CK, !Q
+ double leakage_111 = 0; //D, CK, Q
+
+ //This is so painful...
+ leakage_000 += getGenProperties()->get("INV1_LeakagePower_0").toDouble();
+ leakage_000 += getGenProperties()->get("INV2_LeakagePower_0").toDouble();
+ leakage_000 += getGenProperties()->get("INV3_LeakagePower_0").toDouble();
+ leakage_000 += getGenProperties()->get("INV4_LeakagePower_1").toDouble();
+ leakage_000 += getGenProperties()->get("INV5_LeakagePower_0").toDouble();
+ leakage_000 += getGenProperties()->get("INV6_LeakagePower_1").toDouble();
+ leakage_000 += getGenProperties()->get("INVZ1_LeakagePower_101_0").toDouble();
+ leakage_000 += getGenProperties()->get("INVZ2_LeakagePower_011_0").toDouble();
+ leakage_000 += getGenProperties()->get("INVZ3_LeakagePower_011_0").toDouble();
+ leakage_000 += getGenProperties()->get("INVZ4_LeakagePower_101_0").toDouble();
+
+ leakage_001 += getGenProperties()->get("INV1_LeakagePower_0").toDouble();
+ leakage_001 += getGenProperties()->get("INV2_LeakagePower_0").toDouble();
+ leakage_001 += getGenProperties()->get("INV3_LeakagePower_1").toDouble();
+ leakage_001 += getGenProperties()->get("INV4_LeakagePower_0").toDouble();
+ leakage_001 += getGenProperties()->get("INV5_LeakagePower_0").toDouble();
+ leakage_001 += getGenProperties()->get("INV6_LeakagePower_1").toDouble();
+ leakage_001 += getGenProperties()->get("INVZ1_LeakagePower_101_0").toDouble();
+ leakage_001 += getGenProperties()->get("INVZ2_LeakagePower_011_0").toDouble();
+ leakage_001 += getGenProperties()->get("INVZ3_LeakagePower_011_1").toDouble();
+ leakage_001 += getGenProperties()->get("INVZ4_LeakagePower_100_1").toDouble();
+
+ leakage_010 += getGenProperties()->get("INV1_LeakagePower_0").toDouble();
+ leakage_010 += getGenProperties()->get("INV2_LeakagePower_0").toDouble();
+ leakage_010 += getGenProperties()->get("INV3_LeakagePower_0").toDouble();
+ leakage_010 += getGenProperties()->get("INV4_LeakagePower_1").toDouble();
+ leakage_010 += getGenProperties()->get("INV5_LeakagePower_1").toDouble();
+ leakage_010 += getGenProperties()->get("INV6_LeakagePower_0").toDouble();
+ leakage_010 += getGenProperties()->get("INVZ1_LeakagePower_011_0").toDouble();
+ leakage_010 += getGenProperties()->get("INVZ2_LeakagePower_101_0").toDouble();
+ leakage_010 += getGenProperties()->get("INVZ3_LeakagePower_101_0").toDouble();
+ leakage_010 += getGenProperties()->get("INVZ4_LeakagePower_011_0").toDouble();
+
+ leakage_011 += getGenProperties()->get("INV1_LeakagePower_0").toDouble();
+ leakage_011 += getGenProperties()->get("INV2_LeakagePower_1").toDouble();
+ leakage_011 += getGenProperties()->get("INV3_LeakagePower_1").toDouble();
+ leakage_011 += getGenProperties()->get("INV4_LeakagePower_0").toDouble();
+ leakage_011 += getGenProperties()->get("INV5_LeakagePower_1").toDouble();
+ leakage_011 += getGenProperties()->get("INV6_LeakagePower_0").toDouble();
+ leakage_011 += getGenProperties()->get("INVZ1_LeakagePower_011_1").toDouble();
+ leakage_011 += getGenProperties()->get("INVZ2_LeakagePower_100_1").toDouble();
+ leakage_011 += getGenProperties()->get("INVZ3_LeakagePower_100_1").toDouble();
+ leakage_011 += getGenProperties()->get("INVZ4_LeakagePower_010_1").toDouble();
+
+ leakage_100 += getGenProperties()->get("INV1_LeakagePower_1").toDouble();
+ leakage_100 += getGenProperties()->get("INV2_LeakagePower_1").toDouble();
+ leakage_100 += getGenProperties()->get("INV3_LeakagePower_0").toDouble();
+ leakage_100 += getGenProperties()->get("INV4_LeakagePower_1").toDouble();
+ leakage_100 += getGenProperties()->get("INV5_LeakagePower_0").toDouble();
+ leakage_100 += getGenProperties()->get("INV6_LeakagePower_1").toDouble();
+ leakage_100 += getGenProperties()->get("INVZ1_LeakagePower_100_1").toDouble();
+ leakage_100 += getGenProperties()->get("INVZ2_LeakagePower_010_1").toDouble();
+ leakage_100 += getGenProperties()->get("INVZ3_LeakagePower_010_0").toDouble();
+ leakage_100 += getGenProperties()->get("INVZ4_LeakagePower_101_0").toDouble();
+
+ leakage_101 += getGenProperties()->get("INV1_LeakagePower_1").toDouble();
+ leakage_101 += getGenProperties()->get("INV2_LeakagePower_1").toDouble();
+ leakage_101 += getGenProperties()->get("INV3_LeakagePower_1").toDouble();
+ leakage_101 += getGenProperties()->get("INV4_LeakagePower_0").toDouble();
+ leakage_101 += getGenProperties()->get("INV5_LeakagePower_0").toDouble();
+ leakage_101 += getGenProperties()->get("INV6_LeakagePower_1").toDouble();
+ leakage_101 += getGenProperties()->get("INVZ1_LeakagePower_100_1").toDouble();
+ leakage_101 += getGenProperties()->get("INVZ2_LeakagePower_010_1").toDouble();
+ leakage_101 += getGenProperties()->get("INVZ3_LeakagePower_010_1").toDouble();
+ leakage_101 += getGenProperties()->get("INVZ4_LeakagePower_100_1").toDouble();
+
+ leakage_110 += getGenProperties()->get("INV1_LeakagePower_1").toDouble();
+ leakage_110 += getGenProperties()->get("INV2_LeakagePower_0").toDouble();
+ leakage_110 += getGenProperties()->get("INV3_LeakagePower_0").toDouble();
+ leakage_110 += getGenProperties()->get("INV4_LeakagePower_1").toDouble();
+ leakage_110 += getGenProperties()->get("INV5_LeakagePower_1").toDouble();
+ leakage_110 += getGenProperties()->get("INV6_LeakagePower_0").toDouble();
+ leakage_110 += getGenProperties()->get("INVZ1_LeakagePower_010_0").toDouble();
+ leakage_110 += getGenProperties()->get("INVZ2_LeakagePower_101_0").toDouble();
+ leakage_110 += getGenProperties()->get("INVZ3_LeakagePower_101_0").toDouble();
+ leakage_110 += getGenProperties()->get("INVZ4_LeakagePower_011_0").toDouble();
+
+ leakage_111 += getGenProperties()->get("INV1_LeakagePower_1").toDouble();
+ leakage_111 += getGenProperties()->get("INV2_LeakagePower_1").toDouble();
+ leakage_111 += getGenProperties()->get("INV3_LeakagePower_1").toDouble();
+ leakage_111 += getGenProperties()->get("INV4_LeakagePower_0").toDouble();
+ leakage_111 += getGenProperties()->get("INV5_LeakagePower_1").toDouble();
+ leakage_111 += getGenProperties()->get("INV6_LeakagePower_0").toDouble();
+ leakage_111 += getGenProperties()->get("INVZ1_LeakagePower_010_1").toDouble();
+ leakage_111 += getGenProperties()->get("INVZ2_LeakagePower_100_1").toDouble();
+ leakage_111 += getGenProperties()->get("INVZ3_LeakagePower_100_1").toDouble();
+ leakage_111 += getGenProperties()->get("INVZ4_LeakagePower_010_1").toDouble();
+
+ cache->set(cell_name + "->Leakage->!D!CK!Q", leakage_000);
+ cache->set(cell_name + "->Leakage->!D!CKQ", leakage_001);
+ cache->set(cell_name + "->Leakage->!DCK!Q", leakage_010);
+ cache->set(cell_name + "->Leakage->!DCKQ", leakage_011);
+ cache->set(cell_name + "->Leakage->D!CK!Q", leakage_100);
+ cache->set(cell_name + "->Leakage->D!CKQ", leakage_101);
+ cache->set(cell_name + "->Leakage->DCK!Q", leakage_110);
+ cache->set(cell_name + "->Leakage->DCKQ", leakage_111);
+ Log::printLine(cell_name + "->Leakage->!D!CK!Q=" + (String) leakage_000);
+ Log::printLine(cell_name + "->Leakage->!D!CKQ=" + (String) leakage_001);
+ Log::printLine(cell_name + "->Leakage->!DCK!Q=" + (String) leakage_010);
+ Log::printLine(cell_name + "->Leakage->!DCKQ=" + (String) leakage_011);
+ Log::printLine(cell_name + "->Leakage->D!CK!Q=" + (String) leakage_100);
+ Log::printLine(cell_name + "->Leakage->D!CKQ=" + (String) leakage_101);
+ Log::printLine(cell_name + "->Leakage->DCK!Q=" + (String) leakage_110);
+ Log::printLine(cell_name + "->Leakage->DCKQ=" + (String) leakage_111);
+ // --------------------------------------------------------------------
+
+ /*
+ // Cache event energy results
+ double event_ck_flip = 0.0;
+ event_ck_flip += getGenProperties()->get("INV5_A_Flip").toDouble() + getGenProperties()->get("INV5_ZN_Flip").toDouble();
+ event_ck_flip += getGenProperties()->get("INV6_A_Flip").toDouble() + getGenProperties()->get("INV6_ZN_Flip").toDouble();
+ event_ck_flip += getGenProperties()->get("INVZ1_OE_Flip").toDouble() + getGenProperties()->get("INVZ1_OEN_Flip").toDouble();
+ event_ck_flip += getGenProperties()->get("INVZ2_OE_Flip").toDouble() + getGenProperties()->get("INVZ2_OEN_Flip").toDouble();
+ event_ck_flip += getGenProperties()->get("INVZ3_OE_Flip").toDouble() + getGenProperties()->get("INVZ3_OEN_Flip").toDouble();
+ event_ck_flip += getGenProperties()->get("INVZ4_OE_Flip").toDouble() + getGenProperties()->get("INVZ4_OEN_Flip").toDouble();
+ cache->set(cell_name + "->Event_CK_Flip", event_ck_flip);
+ Log::printLine(cell_name + "->Event_CK_Flip=" + (String) event_ck_flip);
+
+ // Update D flip results
+ double event_d_flip = 0.0;
+ event_d_flip += getGenProperties()->get("INV1_A_Flip").toDouble() + getGenProperties()->get("INV1_ZN_Flip").toDouble();
+ event_d_flip += getGenProperties()->get("INVZ1_A_Flip").toDouble();
+ cache->set(cell_name + "->Event_D_Flip", event_d_flip);
+ Log::printLine(cell_name + "->Event_D_Flip=" + (String) event_d_flip);
+ // Update M flip results
+ double event_m_flip = 0.0;
+ event_m_flip += getGenProperties()->get("INVZ1_ZN_Flip").toDouble();
+ event_m_flip += getGenProperties()->get("INV2_A_Flip").toDouble() + getGenProperties()->get("INV2_ZN_Flip").toDouble();
+ event_m_flip += getGenProperties()->get("INVZ2_A_Flip").toDouble() + getGenProperties()->get("INVZ2_ZN_Flip").toDouble();
+ event_m_flip += getGenProperties()->get("INVZ3_A_Flip").toDouble();
+ cache->set(cell_name + "->Event_M_Flip", event_m_flip);
+ Log::printLine(cell_name + "->Event_M_Flip=" + (String) event_m_flip);
+ // Update Q flip results
+ double event_q_flip = 0.0;
+ event_q_flip += getGenProperties()->get("INVZ3_ZN_Flip").toDouble();
+ event_q_flip += getGenProperties()->get("INV3_A_Flip").toDouble() + getGenProperties()->get("INV3_ZN_Flip").toDouble();
+ event_q_flip += getGenProperties()->get("INVZ4_A_Flip").toDouble() + getGenProperties()->get("INVZ4_ZN_Flip").toDouble();
+ event_q_flip += getGenProperties()->get("INV4_A_Flip").toDouble() + getGenProperties()->get("INV4_ZN_Flip").toDouble();
+ cache->set(cell_name + "->Event_Q_Flip", event_q_flip);
+ Log::printLine(cell_name + "->Event_Q_Flip=" + (String) event_q_flip);
+ */
+
+ // --------------------------------------------------------------------
+ // Get Node Capacitances
+ // --------------------------------------------------------------------
+ double d_cap = getNet("D")->getTotalDownstreamCap();
+ double d_b_cap = getNet("D_b")->getTotalDownstreamCap();
+ double m_b_cap = getNet("M_b")->getTotalDownstreamCap();
+ double m_cap = getNet("M")->getTotalDownstreamCap();
+ double m_i_cap = getNet("M_i")->getTotalDownstreamCap();
+ double q_b_cap = getNet("Q_b")->getTotalDownstreamCap();
+ double q_cap = getNet("Q")->getTotalDownstreamCap();
+ double ck_cap = getNet("CK")->getTotalDownstreamCap();
+ double ck_b_cap = getNet("CK_b")->getTotalDownstreamCap();
+ double ck_i_cap = getNet("CK_i")->getTotalDownstreamCap();
+
+ cache->set(cell_name + "->Cap->D", d_cap);
+ cache->set(cell_name + "->Cap->D_b", d_b_cap);
+ cache->set(cell_name + "->Cap->M_b", m_b_cap);
+ cache->set(cell_name + "->Cap->M", m_cap);
+ cache->set(cell_name + "->Cap->M_i", m_i_cap);
+ cache->set(cell_name + "->Cap->Q_b", q_b_cap);
+ cache->set(cell_name + "->Cap->Q", q_cap);
+ cache->set(cell_name + "->Cap->CK", ck_cap);
+ cache->set(cell_name + "->Cap->CK_b", ck_b_cap);
+ cache->set(cell_name + "->Cap->CK_i", ck_i_cap);
+
+ Log::printLine(cell_name + "->Cap->D=" + (String) d_cap);
+ Log::printLine(cell_name + "->Cap->D_b=" + (String) d_b_cap);
+ Log::printLine(cell_name + "->Cap->M_b=" + (String) m_b_cap);
+ Log::printLine(cell_name + "->Cap->M=" + (String) m_cap);
+ Log::printLine(cell_name + "->Cap->M_i=" + (String) m_i_cap);
+ Log::printLine(cell_name + "->Cap->Q_b=" + (String) q_b_cap);
+ Log::printLine(cell_name + "->Cap->Q=" + (String) q_cap);
+ Log::printLine(cell_name + "->Cap->CK=" + (String) ck_cap);
+ Log::printLine(cell_name + "->Cap->CK_b=" + (String) ck_b_cap);
+ Log::printLine(cell_name + "->Cap->CK_i=" + (String) ck_i_cap);
+ // --------------------------------------------------------------------
+
+ // --------------------------------------------------------------------
+ // Build Internal Delay Model
+ // --------------------------------------------------------------------
+ double q_ron = getDriver("INV4_RonZN")->getOutputRes();
+
+ double d_setup_delay = getDriver("INV1_RonZN")->calculateDelay() +
+ getDriver("INVZ1_RonZN")->calculateDelay() +
+ getDriver("INV2_RonZN")->calculateDelay();
+ double ck_to_q_delay = getDriver("INV5_RonZN")->calculateDelay() +
+ getDriver("INV6_RonZN")->calculateDelay() +
+ getDriver("INVZ3_RonZN")->calculateDelay() +
+ getDriver("INV3_RonZN")->calculateDelay() +
+ getDriver("INV4_RonZN")->calculateDelay();
+
+ cache->set(cell_name + "->DriveRes->Q", q_ron);
+ cache->set(cell_name + "->Delay->D_Setup", d_setup_delay);
+ cache->set(cell_name + "->Delay->CK_to_Q", ck_to_q_delay);
+ Log::printLine(cell_name + "->DriveRes->Q=" + (String) q_ron);
+ Log::printLine(cell_name + "->Delay->D_Setup=" + (String) d_setup_delay);
+ Log::printLine(cell_name + "->Delay->CK_to_Q=" + (String) ck_to_q_delay);
+
+ return;
+ // --------------------------------------------------------------------
+ }
+
+} // namespace DSENT
+
diff --git a/ext/dsent/model/std_cells/DFFQ.h b/ext/dsent/model/std_cells/DFFQ.h
new file mode 100644
index 000000000..699e48627
--- /dev/null
+++ b/ext/dsent/model/std_cells/DFFQ.h
@@ -0,0 +1,38 @@
+#ifndef __DSENT_MODEL_STD_CELLS_DFFQ_H__
+#define __DSENT_MODEL_STD_CELLS_DFFQ_H__
+
+#include "util/CommonType.h"
+#include "model/std_cells/StdCell.h"
+#include "model/TransitionInfo.h"
+
+namespace DSENT
+{
+ class DFFQ : public StdCell
+ {
+ // A DQ flip-flop
+ public:
+ DFFQ(const String& instance_name_, const TechModel* tech_model_);
+ virtual ~DFFQ();
+
+ public:
+ // Set a list of properties' name needed to construct model
+ void initProperties();
+ // Cache the standard cell
+ void cacheStdCell(StdCellLib* cell_lib_, double drive_strength_);
+
+ private:
+ TransitionInfo m_trans_M_;
+
+ protected:
+ // Build the model
+ virtual void constructModel();
+ virtual void updateModel();
+ virtual void evaluateModel();
+ virtual void useModel();
+ virtual void propagateTransitionInfo();
+
+ }; // class DFFQ
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_STD_CELLS_INV_H__
+
diff --git a/ext/dsent/model/std_cells/INV.cc b/ext/dsent/model/std_cells/INV.cc
new file mode 100644
index 000000000..a6ea6c4f4
--- /dev/null
+++ b/ext/dsent/model/std_cells/INV.cc
@@ -0,0 +1,219 @@
+#include "model/std_cells/INV.h"
+
+#include <cmath>
+
+#include "model/PortInfo.h"
+#include "model/TransitionInfo.h"
+#include "model/EventInfo.h"
+#include "model/std_cells/CellMacros.h"
+#include "model/std_cells/StdCellLib.h"
+#include "model/timing_graph/ElectricalNet.h"
+#include "model/timing_graph/ElectricalDriver.h"
+#include "model/timing_graph/ElectricalLoad.h"
+#include "model/timing_graph/ElectricalDelay.h"
+
+namespace DSENT
+{
+ using std::ceil;
+ using std::max;
+
+ INV::INV(const String& instance_name_, const TechModel* tech_model_)
+ : StdCell(instance_name_, tech_model_)
+ {
+ initProperties();
+ }
+
+ INV::~INV()
+ {}
+
+ void INV::initProperties()
+ {
+ return;
+ }
+
+ void INV::constructModel()
+ {
+ // All constructModel should do is create Area/NDDPower/Energy Results as
+ // well as instantiate any sub-instances using only the hard parameters
+
+ // Build Electrical Connectivity
+ createInputPort("A");
+ createOutputPort("Y");
+
+ createLoad("A_Cap");
+ createDelay("A_to_Y_delay");
+ createDriver("Y_Ron", true);
+
+ ElectricalLoad* a_cap = getLoad("A_Cap");
+ ElectricalDelay* a_to_y_delay = getDelay("A_to_Y_delay");
+ ElectricalDriver* y_ron = getDriver("Y_Ron");
+
+ getNet("A")->addDownstreamNode(a_cap);
+ a_cap->addDownstreamNode(a_to_y_delay);
+ a_to_y_delay->addDownstreamNode(y_ron);
+ y_ron->addDownstreamNode(getNet("Y"));
+
+ // Create Area result
+ // Create NDD Power result
+ createElectricalAtomicResults();
+ // Create INV Event Energy Result
+ createElectricalEventAtomicResult("INV");
+
+ getEventInfo("Idle")->setStaticTransitionInfos();
+
+ return;
+ }
+
+ void INV::updateModel()
+ {
+ // All updateModel should do is calculate numbers for the Area/NDDPower/Energy
+ // Results as anything else that needs to be done using either soft or hard parameters
+
+ // Get parameters
+ double drive_strength = getDrivingStrength();
+ Map<double>* cache = getTechModel()->getStdCellLib()->getStdCellCache();
+
+ // Standard cell cache string
+ String cell_name = "INV_X" + (String) drive_strength;
+
+ // Get timing parameters
+ getLoad("A_Cap")->setLoadCap(cache->get(cell_name + "->Cap->A"));
+ getDriver("Y_Ron")->setOutputRes(cache->get(cell_name + "->DriveRes->Y"));
+ getDelay("A_to_Y_delay")->setDelay(cache->get(cell_name + "->Delay->A_to_Y"));
+
+ // Set the cell area
+ getAreaResult("Active")->setValue(cache->get(cell_name + "->Area->Active"));
+ getAreaResult("Metal1Wire")->setValue(cache->get(cell_name + "->Area->Metal1Wire"));
+
+ return;
+ }
+
+ void INV::evaluateModel()
+ {
+ return;
+ }
+
+ void INV::useModel()
+ {
+ // Get parameters
+ double drive_strength = getDrivingStrength();
+ Map<double>* cache = getTechModel()->getStdCellLib()->getStdCellCache();
+
+ // Standard cell cache string
+ String cell_name = "INV_X" + (String) drive_strength;
+
+ // Propagate the transition info and get the 0->1 transtion count
+ propagateTransitionInfo();
+ double P_A = getInputPort("A")->getTransitionInfo().getProbability1();
+ double Y_num_trans_01 = getOutputPort("Y")->getTransitionInfo().getNumberTransitions01();
+
+ // Calculate leakage
+ double leakage = 0;
+ leakage += cache->get(cell_name + "->Leakage->!A") * (1 - P_A);
+ leakage += cache->get(cell_name + "->Leakage->A") * P_A;
+ getNddPowerResult("Leakage")->setValue(leakage);
+
+ // Get VDD
+ double vdd = getTechModel()->get("Vdd");
+
+ // Get capacitances
+ //double a_cap = cache->get(cell_name + "->Cap->A");
+ double y_cap = cache->get(cell_name + "->Cap->Y");
+ double y_load_cap = getNet("Y")->getTotalDownstreamCap();
+
+ // Calculate INV Event energy
+ double energy_per_trans_01 = (y_cap + y_load_cap) * vdd * vdd;
+ getEventResult("INV")->setValue(energy_per_trans_01 * Y_num_trans_01);
+ return;
+ }
+
+ void INV::propagateTransitionInfo()
+ {
+ // Get input transition info
+ const TransitionInfo& trans_A = getInputPort("A")->getTransitionInfo();
+
+ // Set output transition info
+ double Y_num_trans_00 = trans_A.getNumberTransitions11();
+ double Y_num_trans_01 = trans_A.getNumberTransitions01();
+ double Y_num_trans_11 = trans_A.getNumberTransitions00();
+
+ TransitionInfo trans_Y(Y_num_trans_00, Y_num_trans_01, Y_num_trans_11);
+ getOutputPort("Y")->setTransitionInfo(trans_Y);
+ return;
+ }
+
+ // Creates the standard cell, characterizes and abstracts away the details
+ void INV::cacheStdCell(StdCellLib* cell_lib_, double drive_strength_)
+ {
+ // Standard cell cache string
+ String cell_name = "INV_X" + (String) drive_strength_;
+
+ Log::printLine("=== " + cell_name + " ===");
+
+ // Get parameters
+ double gate_pitch = cell_lib_->getTechModel()->get("Gate->PitchContacted");
+ Map<double>* cache = cell_lib_->getStdCellCache();
+
+ // Now actually build the full standard cell model
+ // Create the two input ports
+ createInputPort("A");
+ createOutputPort("Y");
+
+ // Adds macros
+ CellMacros::addInverter(this, "INV", true, true, "A", "Y");
+ CellMacros::updateInverter(this, "INV", drive_strength_);
+
+ // Cache area result
+ double area = gate_pitch * getTotalHeight() * (1 + getGenProperties()->get("INV_GatePitches").toDouble());
+ cache->set(cell_name + "->Area->Active", area);
+ cache->set(cell_name + "->Area->Metal1Wire", area);
+ Log::printLine(cell_name + "->Area->Active=" + (String) area);
+ Log::printLine(cell_name + "->Area->Metal1Wire=" + (String) area);
+
+ // --------------------------------------------------------------------
+ // Leakage Model Calculation
+ // --------------------------------------------------------------------
+ double leakage_a0 = getGenProperties()->get("INV_LeakagePower_0").toDouble();
+ double leakage_a1 = getGenProperties()->get("INV_LeakagePower_1").toDouble();
+ cache->set(cell_name + "->Leakage->!A", leakage_a0);
+ cache->set(cell_name + "->Leakage->A", leakage_a1);
+ Log::printLine(cell_name + "->Leakage->!A=" + (String) leakage_a0);
+ Log::printLine(cell_name + "->Leakage->A=" + (String) leakage_a1);
+ // --------------------------------------------------------------------
+
+ /*
+ // Cache event energy results
+ double event_a_flip = getGenProperties()->get("INV_A_Flip").toDouble() + getGenProperties()->get("INV_ZN_Flip").toDouble();
+ cache->set(cell_name + "->Event_A_Flip", event_a_flip);
+ Log::printLine(cell_name + "->Event_A_Flip=" + (String) event_a_flip);
+ */
+
+ // --------------------------------------------------------------------
+ // Get Node Capacitances
+ // --------------------------------------------------------------------
+ double a_cap = getNet("A")->getTotalDownstreamCap();
+ double y_cap = getNet("Y")->getTotalDownstreamCap();
+
+ cache->set(cell_name + "->Cap->A", a_cap);
+ cache->set(cell_name + "->Cap->Y", y_cap);
+ Log::printLine(cell_name + "->Cap->A=" + (String) a_cap);
+ Log::printLine(cell_name + "->Cap->Y=" + (String) y_cap);
+ // --------------------------------------------------------------------
+
+ // --------------------------------------------------------------------
+ // Build Internal Delay Model
+ // --------------------------------------------------------------------
+ double y_ron = getDriver("INV_RonZN")->getOutputRes();
+ double a_to_y_delay = getDriver("INV_RonZN")->calculateDelay();
+ cache->set(cell_name + "->DriveRes->Y", y_ron);
+ cache->set(cell_name + "->Delay->A_to_Y", a_to_y_delay);
+ Log::printLine(cell_name + "->DriveRes->Y=" + (String) y_ron);
+ Log::printLine(cell_name + "->Delay->A_to_Y=" + (String) a_to_y_delay);
+ // --------------------------------------------------------------------
+
+ return;
+
+ }
+
+} // namespace DSENT
+
diff --git a/ext/dsent/model/std_cells/INV.h b/ext/dsent/model/std_cells/INV.h
new file mode 100644
index 000000000..d81d207c6
--- /dev/null
+++ b/ext/dsent/model/std_cells/INV.h
@@ -0,0 +1,34 @@
+#ifndef __DSENT_MODEL_STD_CELLS_INV_H__
+#define __DSENT_MODEL_STD_CELLS_INV_H__
+
+#include "util/CommonType.h"
+#include "model/std_cells/StdCell.h"
+
+namespace DSENT
+{
+ class INV : public StdCell
+ {
+ public:
+ INV(const String& instance_name_, const TechModel* tech_model_);
+ virtual ~INV();
+
+ public:
+ // Set a list of properties' name needed to construct model
+ void initProperties();
+
+ // Cache the standard cell
+ void cacheStdCell(StdCellLib* cell_lib_, double drive_strength_);
+
+ protected:
+ // Build the model
+ virtual void constructModel();
+ virtual void updateModel();
+ virtual void evaluateModel();
+ virtual void useModel();
+ virtual void propagateTransitionInfo();
+
+ }; // class INV
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_STD_CELLS_INV_H__
+
diff --git a/ext/dsent/model/std_cells/LATQ.cc b/ext/dsent/model/std_cells/LATQ.cc
new file mode 100644
index 000000000..b2548d07b
--- /dev/null
+++ b/ext/dsent/model/std_cells/LATQ.cc
@@ -0,0 +1,380 @@
+#include "model/std_cells/LATQ.h"
+
+#include <cmath>
+
+#include "model/PortInfo.h"
+#include "model/TransitionInfo.h"
+#include "model/EventInfo.h"
+#include "model/std_cells/StdCellLib.h"
+#include "model/std_cells/CellMacros.h"
+#include "model/timing_graph/ElectricalNet.h"
+#include "model/timing_graph/ElectricalDriver.h"
+#include "model/timing_graph/ElectricalLoad.h"
+#include "model/timing_graph/ElectricalDelay.h"
+
+namespace DSENT
+{
+ using std::ceil;
+ using std::max;
+ using std::min;
+
+ LATQ::LATQ(const String& instance_name_, const TechModel* tech_model_)
+ : StdCell(instance_name_, tech_model_)
+ {
+ initProperties();
+ }
+
+ LATQ::~LATQ()
+ {}
+
+ void LATQ::initProperties()
+ {
+ return;
+ }
+
+ void LATQ::constructModel()
+ {
+ // All constructModel should do is create Area/NDDPower/Energy Results as
+ // well as instantiate any sub-instances using only the hard parameters
+
+ createInputPort("D");
+ createInputPort("G");
+ createOutputPort("Q");
+
+ createLoad("D_Cap");
+ createLoad("G_Cap");
+ createDelay("D_to_Q_delay");
+ createDelay("G_to_Q_delay");
+ createDriver("Q_Ron", true);
+
+ ElectricalLoad* d_cap = getLoad("D_Cap");
+ ElectricalLoad* g_cap = getLoad("G_Cap");
+ ElectricalDelay* d_to_q_delay = getDelay("D_to_Q_delay");
+ ElectricalDelay* g_to_q_delay = getDelay("G_to_Q_delay");
+ ElectricalDriver* q_ron = getDriver("Q_Ron");
+
+ getNet("D")->addDownstreamNode(d_cap);
+ getNet("G")->addDownstreamNode(g_cap);
+ d_cap->addDownstreamNode(d_to_q_delay);
+ g_cap->addDownstreamNode(g_to_q_delay);
+ g_to_q_delay->addDownstreamNode(q_ron);
+ q_ron->addDownstreamNode(getNet("Q"));
+
+ // Create Area result
+ // Create NDD Power result
+ createElectricalAtomicResults();
+ // Create G Event Energy Result
+ createElectricalEventAtomicResult("G");
+ // Create DFF Event Energy Result
+ createElectricalEventAtomicResult("LATD");
+ createElectricalEventAtomicResult("LATQ");
+ // Create Idle event for leakage
+ // G pin is assumed to be on all the time
+ //createElectricalEventAtomicResult("Idle");
+ getEventInfo("Idle")->setStaticTransitionInfos();
+ return;
+ }
+
+ void LATQ::updateModel()
+ {
+ // Get parameters
+ double drive_strength = getDrivingStrength();
+ Map<double>* cache = getTechModel()->getStdCellLib()->getStdCellCache();
+
+ // Standard cell cache string
+ String cell_name = "LATQ_X" + (String) drive_strength;
+
+ // Get timing parameters
+ getLoad("D_Cap")->setLoadCap(cache->get(cell_name + "->Cap->D"));
+ getLoad("G_Cap")->setLoadCap(cache->get(cell_name + "->Cap->G"));
+ getDriver("Q_Ron")->setOutputRes(cache->get(cell_name + "->DriveRes->Q"));
+ getDelay("G_to_Q_delay")->setDelay(cache->get(cell_name + "->Delay->G_to_Q"));
+ getDelay("D_to_Q_delay")->setDelay(cache->get(cell_name + "->Delay->D_to_Q"));
+
+ // Set the cell area
+ getAreaResult("Active")->setValue(cache->get(cell_name + "->Area->Active"));
+ getAreaResult("Metal1Wire")->setValue(cache->get(cell_name + "->Area->Metal1Wire"));
+
+ return;
+ }
+
+ void LATQ::evaluateModel()
+ {
+ return;
+ }
+
+ void LATQ::useModel()
+ {
+ // Get parameters
+ double drive_strength = getDrivingStrength();
+ Map<double>* cache = getTechModel()->getStdCellLib()->getStdCellCache();
+
+ // Standard cell cache string
+ String cell_name = "LATQ_X" + (String) drive_strength;
+
+ // Propagate the transition info and get P_D, P_M, and P_Q
+ propagateTransitionInfo();
+ double P_D = getInputPort("D")->getTransitionInfo().getProbability1();
+ double P_G = getInputPort("G")->getTransitionInfo().getProbability1();
+ double P_Q = getOutputPort("Q")->getTransitionInfo().getProbability1();
+ double G_num_trans_01 = getInputPort("G")->getTransitionInfo().getNumberTransitions01();
+ double D_num_trans_01 = getInputPort("D")->getTransitionInfo().getNumberTransitions01();
+ double Q_num_trans_01 = getOutputPort("Q")->getTransitionInfo().getNumberTransitions01();
+
+ // Calculate leakage
+ double leakage = 0;
+ leakage += cache->get(cell_name + "->Leakage->!D!G!Q") * (1 - P_D) * (1 - P_G) * (1 - P_Q);
+ leakage += cache->get(cell_name + "->Leakage->!D!GQ") * (1 - P_D) * (1 - P_G) * P_Q;
+ leakage += cache->get(cell_name + "->Leakage->!DG!Q") * (1 - P_D) * P_G * (1 - P_Q);
+ leakage += cache->get(cell_name + "->Leakage->D!G!Q") * P_D * (1 - P_G) * (1 - P_Q);
+ leakage += cache->get(cell_name + "->Leakage->D!GQ") * P_D * (1 - P_G) * P_Q;
+ leakage += cache->get(cell_name + "->Leakage->DGQ") * P_D * P_G * P_Q;
+ getNddPowerResult("Leakage")->setValue(leakage);
+
+ // Get VDD
+ double vdd = getTechModel()->get("Vdd");
+
+ // Get capacitances
+ double g_b_cap = cache->get(cell_name + "->Cap->G_b");
+ double d_b_cap = cache->get(cell_name + "->Cap->D_b");
+ double q_i_cap = cache->get(cell_name + "->Cap->Q_i");
+ double q_b_cap = cache->get(cell_name + "->Cap->Q_b");
+ double q_cap = cache->get(cell_name + "->Cap->Q");
+ double q_load_cap = getNet("Q")->getTotalDownstreamCap();
+
+ // Calculate G Event energy
+ double g_event_energy = 0.0;
+ g_event_energy += (g_b_cap) * G_num_trans_01;
+ g_event_energy *= vdd * vdd;
+ getEventResult("G")->setValue(g_event_energy);
+ // Calculate LATD Event energy
+ double latd_event_energy = 0.0;
+ latd_event_energy += (d_b_cap) * D_num_trans_01;
+ latd_event_energy *= vdd * vdd;
+ getEventResult("LATD")->setValue(latd_event_energy);
+ // Calculate LATQ Event energy
+ double latq_event_energy = 0.0;
+ latq_event_energy += (q_i_cap + q_b_cap + q_cap + q_load_cap) * Q_num_trans_01;
+ latq_event_energy *= vdd * vdd;
+ getEventResult("LATQ")->setValue(latq_event_energy);
+
+ return;
+ }
+
+ void LATQ::propagateTransitionInfo()
+ {
+ const TransitionInfo& trans_G = getInputPort("G")->getTransitionInfo();
+ const TransitionInfo& trans_D = getInputPort("D")->getTransitionInfo();
+
+ double G_num_trans_01 = trans_G.getNumberTransitions01();
+ double G_num_trans_10 = G_num_trans_01;
+ double G_num_trans_00 = trans_G.getNumberTransitions00();
+ double D_freq_mult = trans_D.getFrequencyMultiplier();
+
+ // If the latch is sampling just as fast or faster than input data signal
+ // Then it can capture all transitions (though it should be normalized to clock)
+ if((G_num_trans_10 + G_num_trans_00) >= D_freq_mult)
+ {
+ const TransitionInfo& trans_Q = trans_D.scaleFrequencyMultiplier(G_num_trans_10 + G_num_trans_00);
+ getOutputPort("Q")->setTransitionInfo(trans_Q);
+ }
+ // If the latch is sampling slower than the input data signal, then input
+ // will look like they transition more
+ else
+ {
+ // Calculate scale ratio
+ double scale_ratio = (G_num_trans_10 + G_num_trans_00) / D_freq_mult;
+ // 00 and 11 transitions become fewer
+ double D_scaled_diff = 0.5 * (1 - scale_ratio) * (trans_D.getNumberTransitions00() + trans_D.getNumberTransitions11());
+ double D_scaled_num_trans_00 = trans_D.getNumberTransitions00() * scale_ratio;
+ double D_scaled_num_trans_11 = trans_D.getNumberTransitions11() * scale_ratio;
+ // 01 and 10 transitions become more frequent
+ double D_scaled_num_trans_10 = trans_D.getNumberTransitions01() + D_scaled_diff;
+
+ // Create final transition info, remembering to apply scaling ratio to normalize to G
+ const TransitionInfo trans_Q( D_scaled_num_trans_00 * scale_ratio,
+ D_scaled_num_trans_10 * scale_ratio,
+ D_scaled_num_trans_11 * scale_ratio);
+ getOutputPort("Q")->setTransitionInfo(trans_Q);
+ }
+
+ return;
+ }
+
+ // Creates the standard cell, characterizes and abstracts away the details
+ void LATQ::cacheStdCell(StdCellLib* cell_lib_, double drive_strength_)
+ {
+ // Get parameters
+ double gate_pitch = cell_lib_->getTechModel()->get("Gate->PitchContacted");
+ Map<double>* cache = cell_lib_->getStdCellCache();
+
+ // Standard cell cache string
+ String cell_name = "LATQ_X" + (String) drive_strength_;
+
+ Log::printLine("=== " + cell_name + " ===");
+
+
+ // Now actually build the full standard cell model
+ createInputPort("D");
+ createInputPort("G");
+ createOutputPort("Q");
+
+ createNet("D_b");
+ createNet("Q_i");
+ createNet("Q_b");
+ createNet("G_b");
+
+ // Adds macros
+ CellMacros::addInverter(this, "INV1", false, true, "D", "D_b");
+ CellMacros::addInverter(this, "INV2", false, true, "Q_i", "Q_b");
+ CellMacros::addInverter(this, "INV3", false, true, "Q_b", "Q");
+ CellMacros::addInverter(this, "INV4", false, true, "G", "G_b");
+ CellMacros::addTristate(this, "INVZ1", false, true, false, false, "D_b", "G", "G_b", "Q_i"); //trace timing through A->ZN path only
+ CellMacros::addTristate(this, "INVZ2", false, false, false, false, "Q_b", "G_b", "G", "Q_i"); //don't trace timing through the feedback path
+
+ // Update macros
+ CellMacros::updateInverter(this, "INV1", drive_strength_ * 0.125);
+ CellMacros::updateInverter(this, "INV2", drive_strength_ * 0.5);
+ CellMacros::updateInverter(this, "INV3", drive_strength_ * 1.0);
+ CellMacros::updateInverter(this, "INV4", drive_strength_ * 0.125);
+ CellMacros::updateTristate(this, "INVZ1", drive_strength_ * 0.5);
+ CellMacros::updateTristate(this, "INVZ2", drive_strength_ * 0.0625);
+
+ // Cache area result
+ double area = 0.0;
+ area += gate_pitch * getTotalHeight() * 1;
+ area += gate_pitch * getTotalHeight() * getGenProperties()->get("INV1_GatePitches").toDouble();
+ area += gate_pitch * getTotalHeight() * getGenProperties()->get("INV2_GatePitches").toDouble();
+ area += gate_pitch * getTotalHeight() * getGenProperties()->get("INV3_GatePitches").toDouble();
+ area += gate_pitch * getTotalHeight() * getGenProperties()->get("INV4_GatePitches").toDouble();
+ area += gate_pitch * getTotalHeight() * getGenProperties()->get("INVZ1_GatePitches").toDouble();
+ area += gate_pitch * getTotalHeight() * getGenProperties()->get("INVZ2_GatePitches").toDouble();
+ cache->set(cell_name + "->Area->Active", area);
+ cache->set(cell_name + "->Area->Metal1Wire", area); //Cover-block m1 area
+ Log::printLine(cell_name + "->Area->Active=" + (String) area);
+ Log::printLine(cell_name + "->Area->Metal1Wire=" + (String) area);
+
+ // --------------------------------------------------------------------
+ // Leakage Model Calculation
+ // --------------------------------------------------------------------
+ // Cache leakage power results (for every single signal combination)
+ double leakage_000 = 0; //!D, !G, !Q
+ double leakage_001 = 0; //!D, !G, Q
+ double leakage_010 = 0; //!D, G, !Q
+ double leakage_100 = 0; //D, !G, !Q
+ double leakage_101 = 0; //D, !G, Q
+ double leakage_111 = 0; //D, G, Q
+
+ //This is so painful...
+ leakage_000 += getGenProperties()->get("INV1_LeakagePower_0").toDouble();
+ leakage_000 += getGenProperties()->get("INV2_LeakagePower_0").toDouble();
+ leakage_000 += getGenProperties()->get("INV3_LeakagePower_1").toDouble();
+ leakage_000 += getGenProperties()->get("INV4_LeakagePower_0").toDouble();
+ leakage_000 += getGenProperties()->get("INVZ1_LeakagePower_011_0").toDouble();
+ leakage_000 += getGenProperties()->get("INVZ2_LeakagePower_101_0").toDouble();
+
+ leakage_001 += getGenProperties()->get("INV1_LeakagePower_0").toDouble();
+ leakage_001 += getGenProperties()->get("INV2_LeakagePower_0").toDouble();
+ leakage_001 += getGenProperties()->get("INV3_LeakagePower_0").toDouble();
+ leakage_001 += getGenProperties()->get("INV4_LeakagePower_0").toDouble();
+ leakage_001 += getGenProperties()->get("INVZ1_LeakagePower_011_1").toDouble();
+ leakage_001 += getGenProperties()->get("INVZ2_LeakagePower_100_1").toDouble();
+
+ leakage_010 += getGenProperties()->get("INV1_LeakagePower_0").toDouble();
+ leakage_010 += getGenProperties()->get("INV2_LeakagePower_0").toDouble();
+ leakage_010 += getGenProperties()->get("INV3_LeakagePower_1").toDouble();
+ leakage_010 += getGenProperties()->get("INV4_LeakagePower_1").toDouble();
+ leakage_010 += getGenProperties()->get("INVZ1_LeakagePower_101_0").toDouble();
+ leakage_010 += getGenProperties()->get("INVZ2_LeakagePower_011_0").toDouble();
+
+ leakage_100 += getGenProperties()->get("INV1_LeakagePower_1").toDouble();
+ leakage_100 += getGenProperties()->get("INV2_LeakagePower_1").toDouble();
+ leakage_100 += getGenProperties()->get("INV3_LeakagePower_1").toDouble();
+ leakage_100 += getGenProperties()->get("INV4_LeakagePower_0").toDouble();
+ leakage_100 += getGenProperties()->get("INVZ1_LeakagePower_010_0").toDouble();
+ leakage_100 += getGenProperties()->get("INVZ2_LeakagePower_101_0").toDouble();
+
+ leakage_101 += getGenProperties()->get("INV1_LeakagePower_1").toDouble();
+ leakage_101 += getGenProperties()->get("INV2_LeakagePower_1").toDouble();
+ leakage_101 += getGenProperties()->get("INV3_LeakagePower_0").toDouble();
+ leakage_101 += getGenProperties()->get("INV4_LeakagePower_0").toDouble();
+ leakage_101 += getGenProperties()->get("INVZ1_LeakagePower_010_1").toDouble();
+ leakage_101 += getGenProperties()->get("INVZ2_LeakagePower_100_1").toDouble();
+
+ leakage_111 += getGenProperties()->get("INV1_LeakagePower_1").toDouble();
+ leakage_111 += getGenProperties()->get("INV2_LeakagePower_1").toDouble();
+ leakage_111 += getGenProperties()->get("INV3_LeakagePower_0").toDouble();
+ leakage_111 += getGenProperties()->get("INV4_LeakagePower_1").toDouble();
+ leakage_111 += getGenProperties()->get("INVZ1_LeakagePower_100_1").toDouble();
+ leakage_111 += getGenProperties()->get("INVZ2_LeakagePower_010_1").toDouble();
+
+ cache->set(cell_name + "->Leakage->!D!G!Q", leakage_000);
+ cache->set(cell_name + "->Leakage->!D!GQ", leakage_001);
+ cache->set(cell_name + "->Leakage->!DG!Q", leakage_010);
+ cache->set(cell_name + "->Leakage->D!G!Q", leakage_100);
+ cache->set(cell_name + "->Leakage->D!GQ", leakage_101);
+ cache->set(cell_name + "->Leakage->DGQ", leakage_111);
+ Log::printLine(cell_name + "->Leakage->!D!G!Q=" + (String) leakage_000);
+ Log::printLine(cell_name + "->Leakage->!D!GQ=" + (String) leakage_001);
+ Log::printLine(cell_name + "->Leakage->!DG!Q=" + (String) leakage_010);
+ Log::printLine(cell_name + "->Leakage->D!G!Q=" + (String) leakage_100);
+ Log::printLine(cell_name + "->Leakage->D!GQ=" + (String) leakage_101);
+ Log::printLine(cell_name + "->Leakage->DGQ=" + (String) leakage_111);
+ // --------------------------------------------------------------------
+
+ // --------------------------------------------------------------------
+ // Get Node Capacitances
+ // --------------------------------------------------------------------
+ double d_cap = getNet("D")->getTotalDownstreamCap();
+ double d_b_cap = getNet("D_b")->getTotalDownstreamCap();
+ double q_i_cap = getNet("Q_i")->getTotalDownstreamCap();
+ double q_b_cap = getNet("Q_b")->getTotalDownstreamCap();
+ double q_cap = getNet("Q")->getTotalDownstreamCap();
+ double g_cap = getNet("G")->getTotalDownstreamCap();
+ double g_b_cap = getNet("G_b")->getTotalDownstreamCap();
+
+ cache->set(cell_name + "->Cap->D", d_cap);
+ cache->set(cell_name + "->Cap->D_b", d_b_cap);
+ cache->set(cell_name + "->Cap->Q_i", q_i_cap);
+ cache->set(cell_name + "->Cap->Q_b", q_b_cap);
+ cache->set(cell_name + "->Cap->Q", q_cap);
+ cache->set(cell_name + "->Cap->G", g_cap);
+ cache->set(cell_name + "->Cap->G_b", g_b_cap);
+
+ Log::printLine(cell_name + "->Cap->D=" + (String) d_cap);
+ Log::printLine(cell_name + "->Cap->D_b=" + (String) d_b_cap);
+ Log::printLine(cell_name + "->Cap->Q_i=" + (String) q_i_cap);
+ Log::printLine(cell_name + "->Cap->Q_b=" + (String) q_b_cap);
+ Log::printLine(cell_name + "->Cap->Q=" + (String) q_cap);
+ Log::printLine(cell_name + "->Cap->G=" + (String) g_cap);
+ Log::printLine(cell_name + "->Cap->G_b=" + (String) g_b_cap);
+ // --------------------------------------------------------------------
+
+ // --------------------------------------------------------------------
+ // Build Internal Delay Model
+ // --------------------------------------------------------------------
+ double q_ron = getDriver("INV3_RonZN")->getOutputRes();
+
+ double d_to_q_delay = getDriver("INV1_RonZN")->calculateDelay() +
+ getDriver("INVZ1_RonZN")->calculateDelay() +
+ getDriver("INV2_RonZN")->calculateDelay() +
+ getDriver("INV3_RonZN")->calculateDelay();
+ double g_to_q_delay = getDriver("INV4_RonZN")->calculateDelay() +
+ getDriver("INVZ1_RonZN")->calculateDelay() +
+ getDriver("INV2_RonZN")->calculateDelay() +
+ getDriver("INV3_RonZN")->calculateDelay();
+
+ cache->set(cell_name + "->DriveRes->Q", q_ron);
+ cache->set(cell_name + "->Delay->D_to_Q", d_to_q_delay);
+ cache->set(cell_name + "->Delay->G_to_Q", g_to_q_delay);
+ Log::printLine(cell_name + "->DriveRes->Q=" + (String) q_ron);
+ Log::printLine(cell_name + "->Delay->D_to_Q=" + (String) d_to_q_delay);
+ Log::printLine(cell_name + "->Delay->G_to_Q=" + (String) g_to_q_delay);
+
+ return;
+ // --------------------------------------------------------------------
+
+ }
+
+} // namespace DSENT
+
diff --git a/ext/dsent/model/std_cells/LATQ.h b/ext/dsent/model/std_cells/LATQ.h
new file mode 100644
index 000000000..7dcb26fd5
--- /dev/null
+++ b/ext/dsent/model/std_cells/LATQ.h
@@ -0,0 +1,34 @@
+#ifndef __DSENT_MODEL_STD_CELLS_LATQ_H__
+#define __DSENT_MODEL_STD_CELLS_LATQ_H__
+
+#include "util/CommonType.h"
+#include "model/std_cells/StdCell.h"
+
+namespace DSENT
+{
+ class LATQ : public StdCell
+ {
+ // A DQ flip-flop
+ public:
+ LATQ(const String& instance_name_, const TechModel* tech_model_);
+ virtual ~LATQ();
+
+ public:
+ // Set a list of properties' name needed to construct model
+ void initProperties();
+ // Cache the standard cell
+ void cacheStdCell(StdCellLib* cell_lib_, double drive_strength_);
+
+ protected:
+ // Build the model
+ virtual void constructModel();
+ virtual void updateModel();
+ virtual void evaluateModel();
+ virtual void useModel();
+ virtual void propagateTransitionInfo();
+
+ }; // class LATQ
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_STD_CELLS_LATQ_H__
+
diff --git a/ext/dsent/model/std_cells/MUX2.cc b/ext/dsent/model/std_cells/MUX2.cc
new file mode 100644
index 000000000..73f18f7b6
--- /dev/null
+++ b/ext/dsent/model/std_cells/MUX2.cc
@@ -0,0 +1,420 @@
+#include "model/std_cells/MUX2.h"
+
+#include <cmath>
+
+#include "model/PortInfo.h"
+#include "model/TransitionInfo.h"
+#include "model/EventInfo.h"
+#include "model/std_cells/StdCellLib.h"
+#include "model/std_cells/CellMacros.h"
+#include "model/timing_graph/ElectricalNet.h"
+#include "model/timing_graph/ElectricalDriver.h"
+#include "model/timing_graph/ElectricalLoad.h"
+#include "model/timing_graph/ElectricalDelay.h"
+
+namespace DSENT
+{
+ using std::ceil;
+ using std::max;
+
+ MUX2::MUX2(const String& instance_name_, const TechModel* tech_model_)
+ : StdCell(instance_name_, tech_model_)
+ {
+ initProperties();
+ }
+
+ MUX2::~MUX2()
+ {}
+
+ void MUX2::initProperties()
+ {
+ return;
+ }
+
+ void MUX2::constructModel()
+ {
+ // All constructModel should do is create Area/NDDPower/Energy Results as
+ // well as instantiate any sub-instances using only the hard parameters
+
+ createInputPort("A");
+ createInputPort("B");
+ createInputPort("S0");
+ createOutputPort("Y");
+
+ createLoad("A_Cap");
+ createLoad("B_Cap");
+ createLoad("S0_Cap");
+ createDelay("A_to_Y_delay");
+ createDelay("B_to_Y_delay");
+ createDelay("S0_to_Y_delay");
+ createDriver("Y_Ron", true);
+
+ ElectricalLoad* a_cap = getLoad("A_Cap");
+ ElectricalLoad* b_cap = getLoad("B_Cap");
+ ElectricalLoad* s0_cap = getLoad("S0_Cap");
+ ElectricalDelay* a_to_y_delay = getDelay("A_to_Y_delay");
+ ElectricalDelay* b_to_y_delay = getDelay("B_to_Y_delay");
+ ElectricalDelay* s0_to_y_delay = getDelay("S0_to_Y_delay");
+ ElectricalDriver* y_ron = getDriver("Y_Ron");
+
+ getNet("A")->addDownstreamNode(a_cap);
+ getNet("B")->addDownstreamNode(b_cap);
+ getNet("S0")->addDownstreamNode(s0_cap);
+ a_cap->addDownstreamNode(a_to_y_delay);
+ b_cap->addDownstreamNode(b_to_y_delay);
+ s0_cap->addDownstreamNode(s0_to_y_delay);
+ a_to_y_delay->addDownstreamNode(y_ron);
+ b_to_y_delay->addDownstreamNode(y_ron);
+ s0_to_y_delay->addDownstreamNode(y_ron);
+ y_ron->addDownstreamNode(getNet("Y"));
+
+ // Create Area result
+ createElectricalAtomicResults();
+ getEventInfo("Idle")->setStaticTransitionInfos();
+ // Create MUX2 Event Energy Result
+ createElectricalEventAtomicResult("MUX2");
+
+
+ return;
+ }
+
+ void MUX2::updateModel()
+ {
+ // Get parameters
+ double drive_strength = getDrivingStrength();
+ Map<double>* cache = getTechModel()->getStdCellLib()->getStdCellCache();
+
+ // Standard cell cache string
+ String cell_name = "MUX2_X" + (String) drive_strength;
+
+ // Get timing parameters
+ getLoad("A_Cap")->setLoadCap(cache->get(cell_name + "->Cap->A"));
+ getLoad("B_Cap")->setLoadCap(cache->get(cell_name + "->Cap->B"));
+ getLoad("S0_Cap")->setLoadCap(cache->get(cell_name + "->Cap->S0"));
+
+ getDelay("A_to_Y_delay")->setDelay(cache->get(cell_name + "->Delay->A_to_Y"));
+ getDelay("B_to_Y_delay")->setDelay(cache->get(cell_name + "->Delay->B_to_Y"));
+ getDelay("S0_to_Y_delay")->setDelay(cache->get(cell_name + "->Delay->S0_to_Y"));
+
+ getDriver("Y_Ron")->setOutputRes(cache->get(cell_name + "->DriveRes->Y"));
+
+ // Set the cell area
+ getAreaResult("Active")->setValue(cache->get(cell_name + "->ActiveArea"));
+ getAreaResult("Metal1Wire")->setValue(cache->get(cell_name + "->ActiveArea"));
+
+ return;
+ }
+
+ void MUX2::evaluateModel()
+ {
+ return;
+ }
+
+ void MUX2::useModel()
+ {
+ // Get parameters
+ double drive_strength = getDrivingStrength();
+ Map<double>* cache = getTechModel()->getStdCellLib()->getStdCellCache();
+
+ // Standard cell cache string
+ String cell_name = "MUX2_X" + (String) drive_strength;
+
+ // Propagate the transition and get the 0->1 transition count
+ propagateTransitionInfo();
+ double P_A = getInputPort("A")->getTransitionInfo().getProbability1();
+ double P_B = getInputPort("B")->getTransitionInfo().getProbability1();
+ double P_S0 = getInputPort("S0")->getTransitionInfo().getProbability1();
+ double S0_num_trans_01 = getInputPort("S0")->getTransitionInfo().getNumberTransitions01();
+ double Y_num_trans_01 = getOutputPort("Y")->getTransitionInfo().getNumberTransitions01();
+
+ // Calculate leakage
+ double leakage = 0;
+ leakage += cache->get(cell_name + "->Leakage->!A!B!S0") * (1 - P_A) * (1 - P_B) * (1 - P_S0);
+ leakage += cache->get(cell_name + "->Leakage->!A!BS0") * (1 - P_A) * (1 - P_B) * P_S0;
+ leakage += cache->get(cell_name + "->Leakage->!AB!S0") * (1 - P_A) * P_B * (1 - P_S0);
+ leakage += cache->get(cell_name + "->Leakage->!ABS0") * (1 - P_A) * P_B * P_S0;
+ leakage += cache->get(cell_name + "->Leakage->A!B!S0") * P_A * (1 - P_B) * (1 - P_S0);
+ leakage += cache->get(cell_name + "->Leakage->A!BS0") * P_A * (1 - P_B) * P_S0;
+ leakage += cache->get(cell_name + "->Leakage->AB!S0") * P_A * P_B * (1 - P_S0);
+ leakage += cache->get(cell_name + "->Leakage->ABS0") * P_A * P_B * P_S0;
+ getNddPowerResult("Leakage")->setValue(leakage);
+
+ // Get VDD
+ double vdd = getTechModel()->get("Vdd");
+
+ // Get capacitances
+ double s0_b_cap = cache->get(cell_name + "->Cap->S0_b");
+ double y_bar_cap = cache->get(cell_name + "->Cap->Y_b");
+ double y_cap = cache->get(cell_name + "->Cap->Y");
+ double y_load_cap = getNet("Y")->getTotalDownstreamCap();
+ // Create mux2 event energy
+ double mux2_event_energy = 0.0;
+ mux2_event_energy += (s0_b_cap) * S0_num_trans_01;
+ mux2_event_energy += (y_bar_cap + y_cap + y_load_cap) * Y_num_trans_01;
+ mux2_event_energy *= vdd * vdd;
+ getEventResult("MUX2")->setValue(mux2_event_energy);
+
+ return;
+ }
+
+ void MUX2::propagateTransitionInfo()
+ {
+ // Get input signal transition info
+ const TransitionInfo& trans_A = getInputPort("A")->getTransitionInfo();
+ const TransitionInfo& trans_B = getInputPort("B")->getTransitionInfo();
+ const TransitionInfo& trans_S0 = getInputPort("S0")->getTransitionInfo();
+
+ // Scale all transition information to the highest freq multiplier
+ double max_freq_mult = max(max(trans_A.getFrequencyMultiplier(), trans_B.getFrequencyMultiplier()), trans_S0.getFrequencyMultiplier());
+ const TransitionInfo& scaled_trans_A = trans_A.scaleFrequencyMultiplier(max_freq_mult);
+ const TransitionInfo& scaled_trans_B = trans_B.scaleFrequencyMultiplier(max_freq_mult);
+ const TransitionInfo& scaled_trans_S0 = trans_S0.scaleFrequencyMultiplier(max_freq_mult);
+
+ // Compute the probability of each transition on a given cycle
+ double A_prob_00 = scaled_trans_A.getNumberTransitions00() / max_freq_mult;
+ double A_prob_01 = scaled_trans_A.getNumberTransitions01() / max_freq_mult;
+ double A_prob_10 = A_prob_01;
+ double A_prob_11 = scaled_trans_A.getNumberTransitions11() / max_freq_mult;
+ double B_prob_00 = scaled_trans_B.getNumberTransitions00() / max_freq_mult;
+ double B_prob_01 = scaled_trans_B.getNumberTransitions01() / max_freq_mult;
+ double B_prob_10 = B_prob_01;
+ double B_prob_11 = scaled_trans_B.getNumberTransitions11() / max_freq_mult;
+ double S0_prob_00 = scaled_trans_S0.getNumberTransitions00() / max_freq_mult;
+ double S0_prob_01 = scaled_trans_S0.getNumberTransitions01() / max_freq_mult;
+ double S0_prob_10 = S0_prob_01;
+ double S0_prob_11 = scaled_trans_S0.getNumberTransitions11() / max_freq_mult;
+
+ // Compute output probabilities
+ double Y_prob_00 = S0_prob_00 * A_prob_00 +
+ S0_prob_01 * (A_prob_00 + A_prob_01) * (B_prob_00 + B_prob_10) +
+ S0_prob_10 * (A_prob_00 + A_prob_10) * (B_prob_00 + B_prob_01) +
+ S0_prob_11 * B_prob_00;
+ double Y_prob_01 = S0_prob_00 * A_prob_01 +
+ S0_prob_01 * (A_prob_00 + A_prob_01) * (B_prob_01 + B_prob_11) +
+ S0_prob_10 * (A_prob_01 + A_prob_11) * (B_prob_00 + B_prob_01) +
+ S0_prob_11 * B_prob_01;
+ double Y_prob_11 = S0_prob_00 * A_prob_11 +
+ S0_prob_01 * (A_prob_10 + A_prob_11) * (B_prob_01 + B_prob_11) +
+ S0_prob_10 * (A_prob_01 + A_prob_11) * (B_prob_10 + B_prob_11) +
+ S0_prob_11 * B_prob_11;
+
+ // Check that probabilities add up to 1.0 with some finite tolerance
+ ASSERT(LibUtil::Math::isEqual((Y_prob_00 + Y_prob_01 + Y_prob_01 + Y_prob_11), 1.0),
+ "[Error] " + getInstanceName() + "Output transition probabilities must add up to 1 (" +
+ (String) Y_prob_00 + ", " + (String) Y_prob_01 + ", " + (String) Y_prob_11 + ")!");
+
+ // Turn probability of transitions per cycle into number of transitions per time unit
+ TransitionInfo trans_Y(Y_prob_00 * max_freq_mult, Y_prob_01 * max_freq_mult, Y_prob_11 * max_freq_mult);
+ getOutputPort("Y")->setTransitionInfo(trans_Y);
+
+ return;
+ }
+
+ // Creates the standard cell, characterizes and abstracts away the details
+ void MUX2::cacheStdCell(StdCellLib* cell_lib_, double drive_strength_)
+ {
+ // Get parameters
+ double gate_pitch = cell_lib_->getTechModel()->get("Gate->PitchContacted");
+ Map<double>* cache = cell_lib_->getStdCellCache();
+
+ // Standard cell cache string
+ String cell_name = "MUX2_X" + (String) drive_strength_;
+
+ Log::printLine("=== " + cell_name + " ===");
+
+ // Now actually build the full standard cell model
+ createInputPort("A");
+ createInputPort("B");
+ createInputPort("S0");
+ createOutputPort("Y");
+
+ createNet("S0_b");
+ createNet("Y_b");
+
+ // Adds macros
+ CellMacros::addInverter(this, "INV1", false, true, "S0", "S0_b");
+ CellMacros::addInverter(this, "INV2", false, true, "Y_b", "Y");
+ CellMacros::addTristate(this, "INVZ1", true, true, true, true, "A", "S0_b", "S0", "Y_b");
+ CellMacros::addTristate(this, "INVZ2", true, true, true, true, "B", "S0", "S0_b", "Y_b");
+
+ // I have no idea how to size each of the parts haha
+ CellMacros::updateInverter(this, "INV1", drive_strength_ * 0.250);
+ CellMacros::updateInverter(this, "INV2", drive_strength_ * 1.000);
+ CellMacros::updateTristate(this, "INVZ1", drive_strength_ * 0.500);
+ CellMacros::updateTristate(this, "INVZ2", drive_strength_ * 0.500);
+
+ // Cache area result
+ double area = 0.0;
+ area += gate_pitch * getTotalHeight() * 1;
+ area += gate_pitch * getTotalHeight() * getGenProperties()->get("INV1_GatePitches").toDouble();
+ area += gate_pitch * getTotalHeight() * getGenProperties()->get("INV2_GatePitches").toDouble();
+ area += gate_pitch * getTotalHeight() * getGenProperties()->get("INVZ1_GatePitches").toDouble();
+ area += gate_pitch * getTotalHeight() * getGenProperties()->get("INVZ2_GatePitches").toDouble();
+ cache->set(cell_name + "->ActiveArea", area);
+ Log::printLine(cell_name + "->ActiveArea=" + (String) area);
+
+ // --------------------------------------------------------------------
+ // Cache Leakage Power (for every single signal combination)
+ // --------------------------------------------------------------------
+ double leakage_000 = 0; //!A, !B, !S0
+ double leakage_001 = 0; //!A, !B, S0
+ double leakage_010 = 0; //!A, B, !S0
+ double leakage_011 = 0; //!A, B, S0
+ double leakage_100 = 0; //A, !B, !S0
+ double leakage_101 = 0; //A, !B, S0
+ double leakage_110 = 0; //A, B, !S0
+ double leakage_111 = 0; //A, B, S0
+
+ //This is so painful...
+ leakage_000 += getGenProperties()->get("INV1_LeakagePower_0").toDouble();
+ leakage_000 += getGenProperties()->get("INV2_LeakagePower_1").toDouble();
+ leakage_000 += getGenProperties()->get("INVZ1_LeakagePower_100_1").toDouble();
+ leakage_000 += getGenProperties()->get("INVZ2_LeakagePower_010_1").toDouble();
+
+ leakage_001 += getGenProperties()->get("INV1_LeakagePower_1").toDouble();
+ leakage_001 += getGenProperties()->get("INV2_LeakagePower_1").toDouble();
+ leakage_001 += getGenProperties()->get("INVZ1_LeakagePower_010_1").toDouble();
+ leakage_001 += getGenProperties()->get("INVZ2_LeakagePower_100_1").toDouble();
+
+ leakage_010 += getGenProperties()->get("INV1_LeakagePower_0").toDouble();
+ leakage_010 += getGenProperties()->get("INV2_LeakagePower_1").toDouble();
+ leakage_010 += getGenProperties()->get("INVZ1_LeakagePower_100_1").toDouble();
+ leakage_010 += getGenProperties()->get("INVZ2_LeakagePower_011_1").toDouble();
+
+ leakage_011 += getGenProperties()->get("INV1_LeakagePower_1").toDouble();
+ leakage_011 += getGenProperties()->get("INV2_LeakagePower_0").toDouble();
+ leakage_011 += getGenProperties()->get("INVZ1_LeakagePower_010_0").toDouble();
+ leakage_011 += getGenProperties()->get("INVZ2_LeakagePower_101_0").toDouble();
+
+ leakage_100 += getGenProperties()->get("INV1_LeakagePower_0").toDouble();
+ leakage_100 += getGenProperties()->get("INV2_LeakagePower_0").toDouble();
+ leakage_100 += getGenProperties()->get("INVZ1_LeakagePower_101_0").toDouble();
+ leakage_100 += getGenProperties()->get("INVZ2_LeakagePower_010_0").toDouble();
+
+ leakage_101 += getGenProperties()->get("INV1_LeakagePower_1").toDouble();
+ leakage_101 += getGenProperties()->get("INV2_LeakagePower_0").toDouble();
+ leakage_101 += getGenProperties()->get("INVZ1_LeakagePower_011_1").toDouble();
+ leakage_101 += getGenProperties()->get("INVZ2_LeakagePower_100_1").toDouble();
+
+ leakage_110 += getGenProperties()->get("INV1_LeakagePower_1").toDouble();
+ leakage_110 += getGenProperties()->get("INV2_LeakagePower_1").toDouble();
+ leakage_110 += getGenProperties()->get("INVZ1_LeakagePower_101_0").toDouble();
+ leakage_110 += getGenProperties()->get("INVZ2_LeakagePower_011_0").toDouble();
+
+ leakage_111 += getGenProperties()->get("INV1_LeakagePower_1").toDouble();
+ leakage_111 += getGenProperties()->get("INV2_LeakagePower_1").toDouble();
+ leakage_111 += getGenProperties()->get("INVZ1_LeakagePower_011_0").toDouble();
+ leakage_111 += getGenProperties()->get("INVZ2_LeakagePower_101_0").toDouble();
+
+ cache->set(cell_name + "->Leakage->!A!B!S0", leakage_000);
+ cache->set(cell_name + "->Leakage->!A!BS0", leakage_001);
+ cache->set(cell_name + "->Leakage->!AB!S0", leakage_010);
+ cache->set(cell_name + "->Leakage->!ABS0", leakage_011);
+ cache->set(cell_name + "->Leakage->A!B!S0", leakage_100);
+ cache->set(cell_name + "->Leakage->A!BS0", leakage_101);
+ cache->set(cell_name + "->Leakage->AB!S0", leakage_110);
+ cache->set(cell_name + "->Leakage->ABS0", leakage_111);
+ Log::printLine(cell_name + "->Leakage->!A!B!S0=" + (String) leakage_000);
+ Log::printLine(cell_name + "->Leakage->!A!BS0=" + (String) leakage_001);
+ Log::printLine(cell_name + "->Leakage->!AB!S0=" + (String) leakage_010);
+ Log::printLine(cell_name + "->Leakage->!ABS0=" + (String) leakage_011);
+ Log::printLine(cell_name + "->Leakage->A!B!S0=" + (String) leakage_100);
+ Log::printLine(cell_name + "->Leakage->A!BS0=" + (String) leakage_101);
+ Log::printLine(cell_name + "->Leakage->AB!S0=" + (String) leakage_110);
+ Log::printLine(cell_name + "->Leakage->ABS0=" + (String) leakage_111);
+
+ // Cache event energy results
+ /*
+ double event_a_flip = 0.0;
+ event_a_flip += getGenProperties()->get("INVZ1_A_Flip").toDouble();
+ cache->set(cell_name + "->Event_A_Flip", event_a_flip);
+ Log::printLine(cell_name + "->Event_A_Flip=" + (String) event_a_flip);
+
+ double event_b_flip = 0.0;
+ event_b_flip += getGenProperties()->get("INVZ1_A_Flip").toDouble();
+ cache->set(cell_name + "->Event_B_Flip", event_b_flip);
+ Log::printLine(cell_name + "->Event_B_Flip=" + (String) event_b_flip);
+
+ double event_s0_flip = 0.0;
+ event_s0_flip += getGenProperties()->get("INV1_A_Flip").toDouble();
+ event_s0_flip += getGenProperties()->get("INV1_ZN_Flip").toDouble();
+ event_s0_flip += getGenProperties()->get("INVZ1_OE_Flip").toDouble() + getGenProperties()->get("INVZ1_OEN_Flip").toDouble();
+ event_s0_flip += getGenProperties()->get("INVZ2_OE_Flip").toDouble() + getGenProperties()->get("INVZ2_OEN_Flip").toDouble();
+ cache->set(cell_name + "->Event_S0_Flip", event_s0_flip);
+ Log::printLine(cell_name + "->Event_S0_Flip=" + (String) event_s0_flip);
+
+ double event_y_flip = 0.0;
+ event_y_flip += getGenProperties()->get("INVZ1_ZN_Flip").toDouble();
+ event_y_flip += getGenProperties()->get("INVZ2_ZN_Flip").toDouble();
+ event_y_flip += getGenProperties()->get("INV2_A_Flip").toDouble();
+ event_y_flip += getGenProperties()->get("INV2_ZN_Flip").toDouble();
+ cache->set(cell_name + "->Event_Y_Flip", event_y_flip);
+ Log::printLine(cell_name + "->Event_Y_Flip=" + (String) event_y_flip);
+
+ double a_cap = getLoad("INVZ1_CgA")->getLoadCap();
+ double b_cap = getLoad("INVZ2_CgA")->getLoadCap();
+ double s0_cap = getLoad("INV1_CgA")->getLoadCap() + getLoad("INVZ1_CgOEN")->getLoadCap() + getLoad("INVZ2_CgOE")->getLoadCap();
+ double y_ron = getDriver("INV2_RonZN")->getOutputRes();
+ */
+ // --------------------------------------------------------------------
+
+ // --------------------------------------------------------------------
+ // Get Node capacitances
+ // --------------------------------------------------------------------
+ double a_cap = getNet("A")->getTotalDownstreamCap();
+ double b_cap = getNet("B")->getTotalDownstreamCap();
+ double s0_cap = getNet("S0")->getTotalDownstreamCap();
+ double s0_b_cap = getNet("S0_b")->getTotalDownstreamCap();
+ double y_b_cap = getNet("Y_b")->getTotalDownstreamCap();
+ double y_cap = getNet("Y")->getTotalDownstreamCap();
+
+ cache->set(cell_name + "->Cap->A", a_cap);
+ cache->set(cell_name + "->Cap->B", b_cap);
+ cache->set(cell_name + "->Cap->S0", s0_cap);
+ cache->set(cell_name + "->Cap->S0_b", s0_b_cap);
+ cache->set(cell_name + "->Cap->Y_b", y_b_cap);
+ cache->set(cell_name + "->Cap->Y", y_cap);
+
+ Log::printLine(cell_name + "->Cap->A=" + (String) a_cap);
+ Log::printLine(cell_name + "->Cap->B=" + (String) b_cap);
+ Log::printLine(cell_name + "->Cap->S0=" + (String) s0_cap);
+ Log::printLine(cell_name + "->Cap->S0_b=" + (String) s0_b_cap);
+ Log::printLine(cell_name + "->Cap->Y_b=" + (String) y_b_cap);
+ Log::printLine(cell_name + "->Cap->Y=" + (String) y_cap);
+ // --------------------------------------------------------------------
+
+ // --------------------------------------------------------------------
+ // Build Internal Delay Model
+ // --------------------------------------------------------------------
+ // Build abstracted timing model
+ double y_ron = getDriver("INV2_RonZN")->getOutputRes();
+
+ double a_to_y_delay = 0.0;
+ a_to_y_delay += getDriver("INVZ1_RonZN")->calculateDelay();
+ a_to_y_delay += getDriver("INV2_RonZN")->calculateDelay();
+
+ double b_to_y_delay = 0.0;
+ b_to_y_delay += getDriver("INVZ1_RonZN")->calculateDelay();
+ b_to_y_delay += getDriver("INV2_RonZN")->calculateDelay();
+
+ double s0_to_y_delay = 0.0;
+ s0_to_y_delay += getDriver("INV1_RonZN")->calculateDelay();
+ s0_to_y_delay += max(getDriver("INVZ1_RonZN")->calculateDelay(), getDriver("INVZ1_RonZN")->calculateDelay());
+ s0_to_y_delay += getDriver("INV2_RonZN")->calculateDelay();
+
+ cache->set(cell_name + "->DriveRes->Y", y_ron);
+ cache->set(cell_name + "->Delay->A_to_Y", a_to_y_delay);
+ cache->set(cell_name + "->Delay->B_to_Y", b_to_y_delay);
+ cache->set(cell_name + "->Delay->S0_to_Y", s0_to_y_delay);
+
+ Log::printLine(cell_name + "->DriveRes->Y=" + (String) y_ron);
+ Log::printLine(cell_name + "->Delay->A_to_Y=" + (String) a_to_y_delay);
+ Log::printLine(cell_name + "->Delay->B_to_Y=" + (String) b_to_y_delay);
+ Log::printLine(cell_name + "->Delay->S0_to_Y=" + (String) s0_to_y_delay);
+ // --------------------------------------------------------------------
+
+ return;
+ }
+
+} // namespace DSENT
+
diff --git a/ext/dsent/model/std_cells/MUX2.h b/ext/dsent/model/std_cells/MUX2.h
new file mode 100644
index 000000000..63df6863e
--- /dev/null
+++ b/ext/dsent/model/std_cells/MUX2.h
@@ -0,0 +1,34 @@
+#ifndef __DSENT_MODEL_STD_CELLS_MUX2_H__
+#define __DSENT_MODEL_STD_CELLS_MUX2_H__
+
+#include "util/CommonType.h"
+#include "model/std_cells/StdCell.h"
+
+namespace DSENT
+{
+ class MUX2 : public StdCell
+ {
+ // A 2-input MUX standard cell
+ public:
+ MUX2(const String& instance_name_, const TechModel* tech_model_);
+ virtual ~MUX2();
+
+ public:
+ // Set a list of properties' name needed to construct model
+ void initProperties();
+ // Cache the standard cell
+ void cacheStdCell(StdCellLib* cell_lib_, double drive_strength_);
+
+ protected:
+ // Build the model
+ virtual void constructModel();
+ virtual void updateModel();
+ virtual void evaluateModel();
+ virtual void useModel();
+ virtual void propagateTransitionInfo();
+
+ }; // class MUX2
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_STD_CELLS_MUX2_H__
+
diff --git a/ext/dsent/model/std_cells/NAND2.cc b/ext/dsent/model/std_cells/NAND2.cc
new file mode 100644
index 000000000..2599f8527
--- /dev/null
+++ b/ext/dsent/model/std_cells/NAND2.cc
@@ -0,0 +1,267 @@
+#include "model/std_cells/NAND2.h"
+
+#include <cmath>
+
+#include "model/PortInfo.h"
+#include "model/TransitionInfo.h"
+#include "model/EventInfo.h"
+#include "model/std_cells/StdCellLib.h"
+#include "model/std_cells/CellMacros.h"
+#include "model/timing_graph/ElectricalNet.h"
+#include "model/timing_graph/ElectricalDriver.h"
+#include "model/timing_graph/ElectricalLoad.h"
+#include "model/timing_graph/ElectricalDelay.h"
+
+namespace DSENT
+{
+ using std::ceil;
+ using std::max;
+
+ NAND2::NAND2(const String& instance_name_, const TechModel* tech_model_)
+ : StdCell(instance_name_, tech_model_)
+ {
+ initProperties();
+ }
+
+ NAND2::~NAND2()
+ {}
+
+ void NAND2::initProperties()
+ {
+ return;
+ }
+
+ void NAND2::constructModel()
+ {
+ // All constructModel should do is create Area/NDDPower/Energy Results as
+ // well as instantiate any sub-instances using only the hard parameters
+
+ createInputPort("A");
+ createInputPort("B");
+ createOutputPort("Y");
+
+ createLoad("A_Cap");
+ createLoad("B_Cap");
+ createDelay("A_to_Y_delay");
+ createDelay("B_to_Y_delay");
+ createDriver("Y_Ron", true);
+
+ ElectricalLoad* a_cap = getLoad("A_Cap");
+ ElectricalLoad* b_cap = getLoad("A_Cap");
+ ElectricalDelay* a_to_y_delay = getDelay("A_to_Y_delay");
+ ElectricalDelay* b_to_y_delay = getDelay("B_to_Y_delay");
+ ElectricalDriver* y_ron = getDriver("Y_Ron");
+
+ getNet("A")->addDownstreamNode(a_cap);
+ getNet("B")->addDownstreamNode(b_cap);
+ a_cap->addDownstreamNode(a_to_y_delay);
+ b_cap->addDownstreamNode(b_to_y_delay);
+ a_to_y_delay->addDownstreamNode(y_ron);
+ b_to_y_delay->addDownstreamNode(y_ron);
+ y_ron->addDownstreamNode(getNet("Y"));
+
+ // Create Area result
+ // Create NDD Power result
+ createElectricalAtomicResults();
+ // Create NAND Event Energy Result
+ createElectricalEventAtomicResult("NAND2");
+
+ getEventInfo("Idle")->setStaticTransitionInfos();
+
+ return;
+ }
+
+ void NAND2::updateModel()
+ {
+ // All updateModel should do is calculate numbers for the Area/NDDPower/Energy
+ // Results as anything else that needs to be done using either soft or hard parameters
+
+ // Get parameters
+ double drive_strength = getDrivingStrength();
+ Map<double>* cache = getTechModel()->getStdCellLib()->getStdCellCache();
+
+ // Standard cell cache string
+ String cell_name = "NAND2_X" + (String) drive_strength;
+
+ // Get timing parameters
+ getLoad("A_Cap")->setLoadCap(cache->get(cell_name + "->Cap->A"));
+ getLoad("B_Cap")->setLoadCap(cache->get(cell_name + "->Cap->B"));
+ getDelay("A_to_Y_delay")->setDelay(cache->get(cell_name + "->Delay->A_to_Y"));
+ getDelay("B_to_Y_delay")->setDelay(cache->get(cell_name + "->Delay->B_to_Y"));
+ getDriver("Y_Ron")->setOutputRes(cache->get(cell_name + "->DriveRes->Y"));
+
+ // Set the cell area
+ getAreaResult("Active")->setValue(cache->get(cell_name + "->Area->Active"));
+ getAreaResult("Metal1Wire")->setValue(cache->get(cell_name + "->Area->Active"));
+
+ return;
+ }
+
+ void NAND2::useModel()
+ {
+ // Get parameters
+ double drive_strength = getDrivingStrength();
+ Map<double>* cache = getTechModel()->getStdCellLib()->getStdCellCache();
+
+ // Standard cell cache string
+ String cell_name = "NAND2_X" + (String) drive_strength;
+
+ // Propagate the transition info and get the 0->1 transtion count
+ propagateTransitionInfo();
+ double P_A = getInputPort("A")->getTransitionInfo().getProbability1();
+ double P_B = getInputPort("B")->getTransitionInfo().getProbability1();
+ double Y_num_trans_01 = getOutputPort("Y")->getTransitionInfo().getNumberTransitions01();
+
+ // Calculate leakage
+ double leakage = 0;
+ leakage += cache->get(cell_name + "->Leakage->!A!B") * (1 - P_A) * (1 - P_B);
+ leakage += cache->get(cell_name + "->Leakage->!AB") * (1 - P_A) * P_B;
+ leakage += cache->get(cell_name + "->Leakage->A!B") * P_A * (1 - P_B);
+ leakage += cache->get(cell_name + "->Leakage->AB") * P_A * P_B;
+ getNddPowerResult("Leakage")->setValue(leakage);
+
+ // Get capacitances
+ double y_cap = cache->get(cell_name + "->Cap->Y");
+ double y_load_cap = getNet("Y")->getTotalDownstreamCap();
+
+ // Get VDD
+ double vdd = getTechModel()->get("Vdd");
+
+ // Calculate NAND2Event energy
+ double energy_per_trans_01 = (y_cap + y_load_cap) * vdd * vdd;
+ getEventResult("NAND2")->setValue(energy_per_trans_01 * Y_num_trans_01);
+
+ return;
+ }
+
+ void NAND2::propagateTransitionInfo()
+ {
+ // Get input signal transition info
+ const TransitionInfo& trans_A = getInputPort("A")->getTransitionInfo();
+ const TransitionInfo& trans_B = getInputPort("B")->getTransitionInfo();
+
+ double max_freq_mult = max(trans_A.getFrequencyMultiplier(), trans_B.getFrequencyMultiplier());
+ const TransitionInfo& scaled_trans_A = trans_A.scaleFrequencyMultiplier(max_freq_mult);
+ const TransitionInfo& scaled_trans_B = trans_B.scaleFrequencyMultiplier(max_freq_mult);
+
+ double A_prob_00 = scaled_trans_A.getNumberTransitions00() / max_freq_mult;
+ double A_prob_01 = scaled_trans_A.getNumberTransitions01() / max_freq_mult;
+ double A_prob_10 = A_prob_01;
+ double A_prob_11 = scaled_trans_A.getNumberTransitions11() / max_freq_mult;
+ double B_prob_00 = scaled_trans_B.getNumberTransitions00() / max_freq_mult;
+ double B_prob_01 = scaled_trans_B.getNumberTransitions01() / max_freq_mult;
+ double B_prob_10 = B_prob_01;
+ double B_prob_11 = scaled_trans_B.getNumberTransitions11() / max_freq_mult;
+
+ // Set output transition info
+ double Y_prob_00 = A_prob_11 * B_prob_11;
+ double Y_prob_01 = A_prob_11 * B_prob_10 +
+ A_prob_10 * (B_prob_11 + B_prob_10);
+ double Y_prob_11 = A_prob_00 +
+ A_prob_01 * (B_prob_00 + B_prob_10) +
+ A_prob_10 * (B_prob_00 + B_prob_01) +
+ A_prob_11 * B_prob_00;
+
+ // Check that probabilities add up to 1.0 with some finite tolerance
+ ASSERT(LibUtil::Math::isEqual((Y_prob_00 + Y_prob_01 + Y_prob_01 + Y_prob_11), 1.0),
+ "[Error] " + getInstanceName() + "Output transition probabilities must add up to 1 (" +
+ (String) Y_prob_00 + ", " + (String) Y_prob_01 + ", " + (String) Y_prob_11 + ")!");
+
+ // Turn probability of transitions per cycle into number of transitions per time unit
+ TransitionInfo trans_Y(Y_prob_00 * max_freq_mult, Y_prob_01 * max_freq_mult, Y_prob_11 * max_freq_mult);
+ getOutputPort("Y")->setTransitionInfo(trans_Y);
+ return;
+ }
+
+ void NAND2::cacheStdCell(StdCellLib* cell_lib_, double drive_strength_)
+ {
+ // Standard cell cache string
+ String cell_name = "NAND2_X" + (String) drive_strength_;
+
+ Log::printLine("=== " + cell_name + " ===");
+
+ // Get parameters
+ double gate_pitch = cell_lib_->getTechModel()->get("Gate->PitchContacted");
+ Map<double>* cache = cell_lib_->getStdCellCache();
+
+ // Now actually build the full standard cell model
+ // Create the two input ports
+ createInputPort("A");
+ createInputPort("B");
+ createOutputPort("Y");
+
+ // Adds macros
+ CellMacros::addNand2(this, "NAND", true, true, true, "A", "B", "Y");
+ CellMacros::updateNand2(this, "NAND", drive_strength_);
+
+ // Cache area result
+ double area = gate_pitch * getTotalHeight() * (1 + getGenProperties()->get("NAND_GatePitches").toDouble());
+ cache->set(cell_name + "->Area->Active", area);
+ Log::printLine(cell_name + "->Area->Active=" + (String) area);
+
+ // --------------------------------------------------------------------
+ // Leakage Model Calculation
+ // --------------------------------------------------------------------
+ double leakage_00 = getGenProperties()->get("NAND_LeakagePower_00").toDouble();
+ double leakage_01 = getGenProperties()->get("NAND_LeakagePower_01").toDouble();
+ double leakage_10 = getGenProperties()->get("NAND_LeakagePower_10").toDouble();
+ double leakage_11 = getGenProperties()->get("NAND_LeakagePower_11").toDouble();
+ cache->set(cell_name + "->Leakage->!A!B", leakage_00);
+ cache->set(cell_name + "->Leakage->!AB", leakage_01);
+ cache->set(cell_name + "->Leakage->A!B", leakage_10);
+ cache->set(cell_name + "->Leakage->AB", leakage_11);
+ Log::printLine(cell_name + "->Leakage->!A!B=" + (String) leakage_00);
+ Log::printLine(cell_name + "->Leakage->!AB=" + (String) leakage_01);
+ Log::printLine(cell_name + "->Leakage->A!B=" + (String) leakage_10);
+ Log::printLine(cell_name + "->Leakage->AB=" + (String) leakage_11);
+ // --------------------------------------------------------------------
+
+ // Cache event energy results
+ /*
+ double event_a_flip = getGenProperties()->get("NAND_A1_Flip").toDouble();
+ double event_b_flip = getGenProperties()->get("NAND_A2_Flip").toDouble();
+ double event_y_flip = getGenProperties()->get("NAND_ZN_Flip").toDouble();
+
+ cache->set(cell_name + "->Event_A_Flip", event_a_flip);
+ cache->set(cell_name + "->Event_B_Flip", event_b_flip);
+ cache->set(cell_name + "->Event_Y_Flip", event_y_flip);
+ Log::printLine(cell_name + "->Event_A_Flip=" + (String) event_a_flip);
+ Log::printLine(cell_name + "->Event_B_Flip=" + (String) event_b_flip);
+ Log::printLine(cell_name + "->Event_Y_Flip=" + (String) event_y_flip);
+ */
+ // --------------------------------------------------------------------
+ // Get Node Capacitances
+ // --------------------------------------------------------------------
+ double a_cap = getNet("A")->getTotalDownstreamCap();
+ double b_cap = getNet("B")->getTotalDownstreamCap();
+ double y_cap = getNet("Y")->getTotalDownstreamCap();
+
+ cache->set(cell_name + "->Cap->A", a_cap);
+ cache->set(cell_name + "->Cap->B", b_cap);
+ cache->set(cell_name + "->Cap->Y", y_cap);
+ Log::printLine(cell_name + "->Cap->A=" + (String) a_cap);
+ Log::printLine(cell_name + "->Cap->B=" + (String) b_cap);
+ Log::printLine(cell_name + "->Cap->Y=" + (String) y_cap);
+ // --------------------------------------------------------------------
+
+ // --------------------------------------------------------------------
+ // Build Internal Delay Model
+ // --------------------------------------------------------------------
+ double y_ron = getDriver("NAND_RonZN")->getOutputRes();
+ double a_to_y_delay = getDriver("NAND_RonZN")->calculateDelay();
+ double b_to_y_delay = getDriver("NAND_RonZN")->calculateDelay();
+
+ cache->set(cell_name + "->DriveRes->Y", y_ron);
+ cache->set(cell_name + "->Delay->A_to_Y", a_to_y_delay);
+ cache->set(cell_name + "->Delay->B_to_Y", b_to_y_delay);
+ Log::printLine(cell_name + "->DriveRes->Y=" + (String) y_ron);
+ Log::printLine(cell_name + "->Delay->A_to_Y=" + (String) a_to_y_delay);
+ Log::printLine(cell_name + "->Delay->B_to_Y=" + (String) b_to_y_delay);
+ // --------------------------------------------------------------------
+
+ return;
+
+ }
+
+} // namespace DSENT
+
diff --git a/ext/dsent/model/std_cells/NAND2.h b/ext/dsent/model/std_cells/NAND2.h
new file mode 100644
index 000000000..75a6436ce
--- /dev/null
+++ b/ext/dsent/model/std_cells/NAND2.h
@@ -0,0 +1,33 @@
+#ifndef __DSENT_MODEL_STD_CELLS_NAND2_H__
+#define __DSENT_MODEL_STD_CELLS_NAND2_H__
+
+#include "util/CommonType.h"
+#include "model/std_cells/StdCell.h"
+
+namespace DSENT
+{
+ class NAND2 : public StdCell
+ {
+ public:
+ NAND2(const String& instance_name_, const TechModel* tech_model_);
+ virtual ~NAND2();
+
+ public:
+ // Set a list of properties' name needed to construct model
+ void initProperties();
+
+ // Cache the standard cell
+ void cacheStdCell(StdCellLib* cell_lib_, double drive_strength_);
+
+ protected:
+ // Build the model
+ virtual void constructModel();
+ virtual void updateModel();
+ virtual void useModel();
+ virtual void propagateTransitionInfo();
+
+ }; // class NAND2
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_STD_CELLS_NAND2_H__
+
diff --git a/ext/dsent/model/std_cells/NOR2.cc b/ext/dsent/model/std_cells/NOR2.cc
new file mode 100644
index 000000000..dd201b956
--- /dev/null
+++ b/ext/dsent/model/std_cells/NOR2.cc
@@ -0,0 +1,268 @@
+#include "model/std_cells/NOR2.h"
+
+#include <cmath>
+
+#include "model/PortInfo.h"
+#include "model/TransitionInfo.h"
+#include "model/EventInfo.h"
+#include "model/std_cells/StdCellLib.h"
+#include "model/std_cells/CellMacros.h"
+#include "model/timing_graph/ElectricalNet.h"
+#include "model/timing_graph/ElectricalDriver.h"
+#include "model/timing_graph/ElectricalLoad.h"
+#include "model/timing_graph/ElectricalDelay.h"
+
+namespace DSENT
+{
+ using std::ceil;
+ using std::max;
+
+ NOR2::NOR2(const String& instance_name_, const TechModel* tech_model_)
+ : StdCell(instance_name_, tech_model_)
+ {
+ initProperties();
+ }
+
+ NOR2::~NOR2()
+ {}
+
+ void NOR2::initProperties()
+ {
+ return;
+ }
+
+ void NOR2::constructModel()
+ {
+ // All constructModel should do is create Area/NDDPower/Energy Results as
+ // well as instantiate any sub-instances using only the hard parameters
+
+ createInputPort("A");
+ createInputPort("B");
+ createOutputPort("Y");
+
+ createLoad("A_Cap");
+ createLoad("B_Cap");
+ createDelay("A_to_Y_delay");
+ createDelay("B_to_Y_delay");
+ createDriver("Y_Ron", true);
+
+ ElectricalLoad* a_cap = getLoad("A_Cap");
+ ElectricalLoad* b_cap = getLoad("A_Cap");
+ ElectricalDelay* a_to_y_delay = getDelay("A_to_Y_delay");
+ ElectricalDelay* b_to_y_delay = getDelay("B_to_Y_delay");
+ ElectricalDriver* y_ron = getDriver("Y_Ron");
+
+ getNet("A")->addDownstreamNode(a_cap);
+ getNet("B")->addDownstreamNode(b_cap);
+ a_cap->addDownstreamNode(a_to_y_delay);
+ b_cap->addDownstreamNode(b_to_y_delay);
+ a_to_y_delay->addDownstreamNode(y_ron);
+ b_to_y_delay->addDownstreamNode(y_ron);
+ y_ron->addDownstreamNode(getNet("Y"));
+
+ // Create Area result
+ // Create NDD Power result
+ createElectricalAtomicResults();
+ // Create NOR Event Energy Result
+ createElectricalEventAtomicResult("NOR2");
+
+ getEventInfo("Idle")->setStaticTransitionInfos();
+
+ return;
+ }
+
+ void NOR2::updateModel()
+ {
+ // All updateModel should do is calculate numbers for the Area/NDDPower/Energy
+ // Results as anything else that needs to be done using either soft or hard parameters
+
+ // Get parameters
+ double drive_strength = getDrivingStrength();
+ Map<double>* cache = getTechModel()->getStdCellLib()->getStdCellCache();
+
+ // Standard cell cache string
+ String cell_name = "NOR2_X" + (String) drive_strength;
+
+ // Get timing parameters
+ getLoad("A_Cap")->setLoadCap(cache->get(cell_name + "->Cap->A"));
+ getLoad("B_Cap")->setLoadCap(cache->get(cell_name + "->Cap->B"));
+ getDelay("A_to_Y_delay")->setDelay(cache->get(cell_name + "->Delay->A_to_Y"));
+ getDelay("B_to_Y_delay")->setDelay(cache->get(cell_name + "->Delay->B_to_Y"));
+ getDriver("Y_Ron")->setOutputRes(cache->get(cell_name + "->DriveRes->Y"));
+
+ // Set the cell area
+ getAreaResult("Active")->setValue(cache->get(cell_name + "->ActiveArea"));
+ getAreaResult("Metal1Wire")->setValue(cache->get(cell_name + "->ActiveArea"));
+
+ return;
+ }
+
+ void NOR2::useModel()
+ {
+ // Get parameters
+ double drive_strength = getDrivingStrength();
+ Map<double>* cache = getTechModel()->getStdCellLib()->getStdCellCache();
+
+ // Standard cell cache string
+ String cell_name = "NOR2_X" + (String) drive_strength;
+
+ // Propagate the transition info and get the 0->1 transtion count
+ propagateTransitionInfo();
+ double P_A = getInputPort("A")->getTransitionInfo().getProbability1();
+ double P_B = getInputPort("B")->getTransitionInfo().getProbability1();
+ double Y_num_trans_01 = getOutputPort("Y")->getTransitionInfo().getNumberTransitions01();
+
+ // Calculate leakage
+ double leakage = 0;
+ leakage += cache->get(cell_name + "->Leakage->!A!B") * (1 - P_A) * (1 - P_B);
+ leakage += cache->get(cell_name + "->Leakage->!AB") * (1 - P_A) * P_B;
+ leakage += cache->get(cell_name + "->Leakage->A!B") * P_A * (1 - P_B);
+ leakage += cache->get(cell_name + "->Leakage->AB") * P_A * P_B;
+ getNddPowerResult("Leakage")->setValue(leakage);
+
+ // Get VDD
+ double vdd = getTechModel()->get("Vdd");
+ // Get capacitances
+ double y_cap = cache->get(cell_name + "->Cap->Y");
+ double y_load_cap = getNet("Y")->getTotalDownstreamCap();
+
+ // Calculate NOR2Event energy
+ double energy_per_trans_01 = (y_cap + y_load_cap) * vdd * vdd;
+ getEventResult("NOR2")->setValue(energy_per_trans_01 * Y_num_trans_01);
+
+ return;
+ }
+
+ void NOR2::propagateTransitionInfo()
+ {
+ // Get input signal transition info
+ const TransitionInfo& trans_A = getInputPort("A")->getTransitionInfo();
+ const TransitionInfo& trans_B = getInputPort("B")->getTransitionInfo();
+
+ double max_freq_mult = max(trans_A.getFrequencyMultiplier(), trans_B.getFrequencyMultiplier());
+ const TransitionInfo& scaled_trans_A = trans_A.scaleFrequencyMultiplier(max_freq_mult);
+ const TransitionInfo& scaled_trans_B = trans_B.scaleFrequencyMultiplier(max_freq_mult);
+
+ double A_prob_00 = scaled_trans_A.getNumberTransitions00() / max_freq_mult;
+ double A_prob_01 = scaled_trans_A.getNumberTransitions01() / max_freq_mult;
+ double A_prob_10 = A_prob_01;
+ double A_prob_11 = scaled_trans_A.getNumberTransitions11() / max_freq_mult;
+ double B_prob_00 = scaled_trans_B.getNumberTransitions00() / max_freq_mult;
+ double B_prob_01 = scaled_trans_B.getNumberTransitions01() / max_freq_mult;
+ double B_prob_10 = B_prob_01;
+ double B_prob_11 = scaled_trans_B.getNumberTransitions11() / max_freq_mult;
+
+ // Set output transition info
+ double Y_prob_00 = A_prob_00 * B_prob_11 +
+ A_prob_01 * (B_prob_10 + B_prob_11) +
+ A_prob_10 * (B_prob_01 + B_prob_11) +
+ A_prob_11;
+ double Y_prob_01 = A_prob_00 * B_prob_10 +
+ A_prob_10 * (B_prob_00 + B_prob_10);
+ double Y_prob_11 = A_prob_00 * B_prob_00;
+
+ // Check that probabilities add up to 1.0 with some finite tolerance
+ ASSERT(LibUtil::Math::isEqual((Y_prob_00 + Y_prob_01 + Y_prob_01 + Y_prob_11), 1.0),
+ "[Error] " + getInstanceName() + "Output transition probabilities must add up to 1 (" +
+ (String) Y_prob_00 + ", " + (String) Y_prob_01 + ", " + (String) Y_prob_11 + ")!");
+
+ // Turn probability of transitions per cycle into number of transitions per time unit
+ TransitionInfo trans_Y(Y_prob_00 * max_freq_mult, Y_prob_01 * max_freq_mult, Y_prob_11 * max_freq_mult);
+ getOutputPort("Y")->setTransitionInfo(trans_Y);
+ return;
+ }
+
+ void NOR2::cacheStdCell(StdCellLib* cell_lib_, double drive_strength_)
+ {
+ // Standard cell cache string
+ String cell_name = "NOR2_X" + (String) drive_strength_;
+
+ Log::printLine("=== " + cell_name + " ===");
+
+ // Get parameters
+ double gate_pitch = cell_lib_->getTechModel()->get("Gate->PitchContacted");
+ Map<double>* cache = cell_lib_->getStdCellCache();
+
+ // Now actually build the full standard cell model
+ // Create the two input ports
+ createInputPort("A");
+ createInputPort("B");
+ createOutputPort("Y");
+
+ // Adds macros
+ CellMacros::addNor2(this, "NOR", true, true, true, "A", "B", "Y");
+ CellMacros::updateNor2(this, "NOR", drive_strength_);
+
+ // Cache area result
+ double area = gate_pitch * getTotalHeight() * (1 + getGenProperties()->get("NOR_GatePitches").toDouble());
+ cache->set(cell_name + "->ActiveArea", area);
+ Log::printLine(cell_name + "->ActiveArea=" + (String) area);
+
+ // --------------------------------------------------------------------
+ // Leakage Model Calculation
+ // --------------------------------------------------------------------
+ double leakage_00 = getGenProperties()->get("NOR_LeakagePower_00").toDouble();
+ double leakage_01 = getGenProperties()->get("NOR_LeakagePower_01").toDouble();
+ double leakage_10 = getGenProperties()->get("NOR_LeakagePower_10").toDouble();
+ double leakage_11 = getGenProperties()->get("NOR_LeakagePower_11").toDouble();
+ cache->set(cell_name + "->Leakage->!A!B", leakage_00);
+ cache->set(cell_name + "->Leakage->!AB", leakage_01);
+ cache->set(cell_name + "->Leakage->A!B", leakage_10);
+ cache->set(cell_name + "->Leakage->AB", leakage_11);
+ Log::printLine(cell_name + "->Leakage->!A!B=" + (String) leakage_00);
+ Log::printLine(cell_name + "->Leakage->!AB=" + (String) leakage_01);
+ Log::printLine(cell_name + "->Leakage->A!B=" + (String) leakage_10);
+ Log::printLine(cell_name + "->Leakage->AB=" + (String) leakage_11);
+ // --------------------------------------------------------------------
+
+ /*
+ // Cache event energy results
+ double event_a_flip = getGenProperties()->get("NOR_A1_Flip").toDouble();
+ double event_b_flip = getGenProperties()->get("NOR_A2_Flip").toDouble();
+ double event_zn_flip = getGenProperties()->get("NOR_ZN_Flip").toDouble();
+
+ cache->set(cell_name + "->Event_A_Flip", event_a_flip);
+ cache->set(cell_name + "->Event_B_Flip", event_b_flip);
+ cache->set(cell_name + "->Event_ZN_Flip", event_zn_flip);
+ Log::printLine(cell_name + "->Event_A_Flip=" + (String) event_a_flip);
+ Log::printLine(cell_name + "->Event_B_Flip=" + (String) event_b_flip);
+ Log::printLine(cell_name + "->Event_ZN_Flip=" + (String) event_zn_flip);
+ */
+
+ // --------------------------------------------------------------------
+ // Get Node Capacitances
+ // --------------------------------------------------------------------
+ // Build abstracted timing model
+ double a_cap = getNet("A")->getTotalDownstreamCap();
+ double b_cap = getNet("B")->getTotalDownstreamCap();
+ double y_cap = getNet("Y")->getTotalDownstreamCap();
+
+ cache->set(cell_name + "->Cap->A", a_cap);
+ cache->set(cell_name + "->Cap->B", b_cap);
+ cache->set(cell_name + "->Cap->Y", y_cap);
+ Log::printLine(cell_name + "->Cap->A_Cap=" + (String) a_cap);
+ Log::printLine(cell_name + "->Cap->B_Cap=" + (String) b_cap);
+ Log::printLine(cell_name + "->Cap->Y_Cap=" + (String) y_cap);
+ // --------------------------------------------------------------------
+
+ // --------------------------------------------------------------------
+ // Build Internal Delay Model
+ // --------------------------------------------------------------------
+ double y_ron = getDriver("NOR_RonZN")->getOutputRes();
+ double a_to_y_delay = getDriver("NOR_RonZN")->calculateDelay();
+ double b_to_y_delay = getDriver("NOR_RonZN")->calculateDelay();
+
+ cache->set(cell_name + "->DriveRes->Y", y_ron);
+ cache->set(cell_name + "->Delay->A_to_Y", a_to_y_delay);
+ cache->set(cell_name + "->Delay->B_to_Y", b_to_y_delay);
+ Log::printLine(cell_name + "->DriveRes->Y=" + (String) y_ron);
+ Log::printLine(cell_name + "->Delay->A_to_Y=" + (String) a_to_y_delay);
+ Log::printLine(cell_name + "->Delay->B_to_Y=" + (String) b_to_y_delay);
+ // --------------------------------------------------------------------
+
+ return;
+
+ }
+
+} // namespace DSENT
+
diff --git a/ext/dsent/model/std_cells/NOR2.h b/ext/dsent/model/std_cells/NOR2.h
new file mode 100644
index 000000000..b43740717
--- /dev/null
+++ b/ext/dsent/model/std_cells/NOR2.h
@@ -0,0 +1,33 @@
+#ifndef __DSENT_MODEL_STD_CELLS_NOR2_H__
+#define __DSENT_MODEL_STD_CELLS_NOR2_H__
+
+#include "util/CommonType.h"
+#include "model/std_cells/StdCell.h"
+
+namespace DSENT
+{
+ class NOR2 : public StdCell
+ {
+ public:
+ NOR2(const String& instance_name_, const TechModel* tech_model_);
+ virtual ~NOR2();
+
+ public:
+ // Set a list of properties' name needed to construct model
+ void initProperties();
+
+ // Cache the standard cell
+ void cacheStdCell(StdCellLib* cell_lib_, double drive_strength_);
+
+ protected:
+ // Build the model
+ virtual void constructModel();
+ virtual void updateModel();
+ virtual void useModel();
+ virtual void propagateTransitionInfo();
+
+ }; // class NOR2
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_STD_CELLS_NOR2_H__
+
diff --git a/ext/dsent/model/std_cells/OR2.cc b/ext/dsent/model/std_cells/OR2.cc
new file mode 100644
index 000000000..1271ad091
--- /dev/null
+++ b/ext/dsent/model/std_cells/OR2.cc
@@ -0,0 +1,279 @@
+#include "model/std_cells/OR2.h"
+
+#include <cmath>
+
+#include "model/PortInfo.h"
+#include "model/TransitionInfo.h"
+#include "model/EventInfo.h"
+#include "model/std_cells/StdCellLib.h"
+#include "model/std_cells/CellMacros.h"
+#include "model/timing_graph/ElectricalNet.h"
+#include "model/timing_graph/ElectricalDriver.h"
+#include "model/timing_graph/ElectricalLoad.h"
+#include "model/timing_graph/ElectricalDelay.h"
+
+namespace DSENT
+{
+ using std::max;
+
+ OR2::OR2(const String& instance_name_, const TechModel* tech_model_)
+ : StdCell(instance_name_, tech_model_)
+ {
+ initProperties();
+ }
+
+ OR2::~OR2()
+ {}
+
+ void OR2::initProperties()
+ {
+ return;
+ }
+
+ void OR2::constructModel()
+ {
+ createInputPort("A");
+ createInputPort("B");
+ createOutputPort("Y");
+
+ createLoad("A_Cap");
+ createLoad("B_Cap");
+ createDelay("A_to_Y_delay");
+ createDelay("B_to_Y_delay");
+ createDriver("Y_Ron", true);
+
+ ElectricalLoad* a_cap = getLoad("A_Cap");
+ ElectricalLoad* b_cap = getLoad("B_Cap");
+ ElectricalDelay* a_to_y_delay = getDelay("A_to_Y_delay");
+ ElectricalDelay* b_to_y_delay = getDelay("B_to_Y_delay");
+ ElectricalDriver* y_ron = getDriver("Y_Ron");
+
+ getNet("A")->addDownstreamNode(a_cap);
+ getNet("B")->addDownstreamNode(b_cap);
+ a_cap->addDownstreamNode(a_to_y_delay);
+ b_cap->addDownstreamNode(b_to_y_delay);
+ a_to_y_delay->addDownstreamNode(y_ron);
+ b_to_y_delay->addDownstreamNode(y_ron);
+ y_ron->addDownstreamNode(getNet("Y"));
+
+ // Create Area result
+ // Create NDD Power result
+ createElectricalAtomicResults();
+ // Create OR Event Energy Result
+ createElectricalEventAtomicResult("OR2");
+
+ getEventInfo("Idle")->setStaticTransitionInfos();
+
+ return;
+ }
+
+ void OR2::updateModel()
+ {
+ // Get parameters
+ double drive_strength = getDrivingStrength();
+ Map<double>* cache = getTechModel()->getStdCellLib()->getStdCellCache();
+
+ // Standard cell cache string
+ const String& cell_name = "OR2_X" + (String) drive_strength;
+
+ // Get timing parameters
+ getLoad("A_Cap")->setLoadCap(cache->get(cell_name + "->Cap->A"));
+ getLoad("B_Cap")->setLoadCap(cache->get(cell_name + "->Cap->B"));
+ getDelay("A_to_Y_delay")->setDelay(cache->get(cell_name + "->Delay->A_to_Y"));
+ getDelay("B_to_Y_delay")->setDelay(cache->get(cell_name + "->Delay->B_to_Y"));
+ getDriver("Y_Ron")->setOutputRes(cache->get(cell_name + "->DriveRes->Y"));
+
+ // Set the cell area
+ getAreaResult("Active")->setValue(cache->get(cell_name + "->ActiveArea"));
+ getAreaResult("Metal1Wire")->setValue(cache->get(cell_name + "->ActiveArea"));
+
+ return;
+ }
+
+ void OR2::evaluateModel()
+ {
+ return;
+ }
+
+ void OR2::useModel()
+ {
+ // Get parameters
+ double drive_strength = getDrivingStrength();
+ Map<double>* cache = getTechModel()->getStdCellLib()->getStdCellCache();
+
+ // Stadard cell cache string
+ const String& cell_name = "OR2_X" + (String) drive_strength;
+
+ // Propagate the transition info and get the 0->1 transtion count
+ propagateTransitionInfo();
+ double P_A = getInputPort("A")->getTransitionInfo().getProbability1();
+ double P_B = getInputPort("B")->getTransitionInfo().getProbability1();
+ double Y_num_trans_01 = getOutputPort("Y")->getTransitionInfo().getNumberTransitions01();
+
+ // Calculate leakage
+ double leakage = 0;
+ leakage += cache->get(cell_name + "->Leakage->!A!B") * (1 - P_A) * (1 - P_B);
+ leakage += cache->get(cell_name + "->Leakage->!AB") * (1 - P_A) * P_B;
+ leakage += cache->get(cell_name + "->Leakage->A!B") * P_A * (1 - P_B);
+ leakage += cache->get(cell_name + "->Leakage->AB") * P_A * P_B;
+ getNddPowerResult("Leakage")->setValue(leakage);
+
+ // Get VDD
+ double vdd = getTechModel()->get("Vdd");
+
+ // Get capacitances
+ double y_b_cap = cache->get(cell_name + "->Cap->Y_b");
+ double y_cap = cache->get(cell_name + "->Cap->Y");
+ double y_load_cap = getNet("Y")->getTotalDownstreamCap();
+
+ // Calculate OR2Event energy
+ double energy_per_trans_01 = (y_b_cap + y_cap + y_load_cap) * vdd * vdd;
+ getEventResult("OR2")->setValue(energy_per_trans_01 * Y_num_trans_01);
+
+ return;
+ }
+
+ void OR2::propagateTransitionInfo()
+ {
+ // Get input signal transition info
+ const TransitionInfo& trans_A = getInputPort("A")->getTransitionInfo();
+ const TransitionInfo& trans_B = getInputPort("B")->getTransitionInfo();
+
+ double max_freq_mult = max(trans_A.getFrequencyMultiplier(), trans_B.getFrequencyMultiplier());
+ const TransitionInfo& scaled_trans_A = trans_A.scaleFrequencyMultiplier(max_freq_mult);
+ const TransitionInfo& scaled_trans_B = trans_B.scaleFrequencyMultiplier(max_freq_mult);
+
+ double A_prob_00 = scaled_trans_A.getNumberTransitions00() / max_freq_mult;
+ double A_prob_01 = scaled_trans_A.getNumberTransitions01() / max_freq_mult;
+ double A_prob_10 = A_prob_01;
+ double A_prob_11 = scaled_trans_A.getNumberTransitions11() / max_freq_mult;
+ double B_prob_00 = scaled_trans_B.getNumberTransitions00() / max_freq_mult;
+ double B_prob_01 = scaled_trans_B.getNumberTransitions01() / max_freq_mult;
+ double B_prob_10 = B_prob_01;
+ double B_prob_11 = scaled_trans_B.getNumberTransitions11() / max_freq_mult;
+
+ // Set output transition info
+ double Y_prob_00 = A_prob_00 * B_prob_00;
+ double Y_prob_01 = A_prob_00 * B_prob_01 +
+ A_prob_01 * (B_prob_00 + B_prob_01);
+ double Y_prob_11 = A_prob_00 * B_prob_11 +
+ A_prob_01 * (B_prob_10 + B_prob_11) +
+ A_prob_10 * (B_prob_01 + B_prob_11) +
+ A_prob_11;
+
+ // Check that probabilities add up to 1.0 with some finite tolerance
+ ASSERT(LibUtil::Math::isEqual((Y_prob_00 + Y_prob_01 + Y_prob_01 + Y_prob_11), 1.0), "[Error] " + getInstanceName() +
+ "Output transition probabilities must add up to 1 (" + (String) Y_prob_00 + ", " +
+ (String) Y_prob_01 + ", " + (String) Y_prob_11 + ")!");
+
+ // Turn probability of transitions per cycle into number of transitions per time unit
+ TransitionInfo trans_Y(Y_prob_00 * max_freq_mult, Y_prob_01 * max_freq_mult, Y_prob_11 * max_freq_mult);
+ getOutputPort("Y")->setTransitionInfo(trans_Y);
+ return;
+ }
+
+ // Creates the standard cell, characterizes and abstracts away the details
+ void OR2::cacheStdCell(StdCellLib* cell_lib_, double drive_strength_)
+ {
+ // Get parameters
+ double gate_pitch = cell_lib_->getTechModel()->get("Gate->PitchContacted");
+ Map<double>* cache = cell_lib_->getStdCellCache();
+
+ // Stadard cell cache string
+ const String& cell_name = "OR2_X" + (String) drive_strength_;
+
+ Log::printLine("=== " + cell_name + " ===");
+
+ // Now actually build the full standard cell model
+ createInputPort("A");
+ createInputPort("B");
+ createOutputPort("Y");
+
+ createNet("Y_b");
+
+ // Adds macros
+ CellMacros::addNor2(this, "NOR2", false, true, true, "A", "B", "Y_b");
+ CellMacros::addInverter(this, "INV", false, true, "Y_b", "Y");
+
+ // Update macros
+ CellMacros::updateNor2(this, "NOR2", drive_strength_ * 0.66);
+ CellMacros::updateInverter(this, "INV", drive_strength_ * 1.0);
+
+ // Cache area result
+ double area = 0.0;
+ area += gate_pitch * getTotalHeight() * 1;
+ area += gate_pitch * getTotalHeight() * getGenProperties()->get("NOR2_GatePitches").toDouble();
+ area += gate_pitch * getTotalHeight() * getGenProperties()->get("INV_GatePitches").toDouble();
+ cache->set(cell_name + "->ActiveArea", area);
+ Log::printLine(cell_name + "->ActiveArea=" + (String)area);
+
+ // --------------------------------------------------------------------
+ // Leakage Model Calculation
+ // --------------------------------------------------------------------
+ // Cache leakage power results (for every single signal combination)
+ double leakage_00 = 0.0; // !A, !B
+ double leakage_01 = 0.0; // !A, B
+ double leakage_10 = 0.0; // A, !B
+ double leakage_11 = 0.0; // A, B
+
+ leakage_00 += getGenProperties()->get("NOR2_LeakagePower_00").toDouble();
+ leakage_00 += getGenProperties()->get("INV_LeakagePower_1").toDouble();
+
+ leakage_01 += getGenProperties()->get("NOR2_LeakagePower_01").toDouble();
+ leakage_01 += getGenProperties()->get("INV_LeakagePower_0").toDouble();
+
+ leakage_10 += getGenProperties()->get("NOR2_LeakagePower_10").toDouble();
+ leakage_10 += getGenProperties()->get("INV_LeakagePower_0").toDouble();
+
+ leakage_11 += getGenProperties()->get("NOR2_LeakagePower_11").toDouble();
+ leakage_11 += getGenProperties()->get("INV_LeakagePower_0").toDouble();
+
+ cache->set(cell_name + "->Leakage->!A!B", leakage_00);
+ cache->set(cell_name + "->Leakage->!AB", leakage_01);
+ cache->set(cell_name + "->Leakage->A!B", leakage_10);
+ cache->set(cell_name + "->Leakage->AB", leakage_11);
+ Log::printLine(cell_name + "->Leakage->!A!B=" + (String) leakage_00);
+ Log::printLine(cell_name + "->Leakage->!AB=" + (String) leakage_01);
+ Log::printLine(cell_name + "->Leakage->A!B=" + (String) leakage_10);
+ Log::printLine(cell_name + "->Leakage->AB=" + (String) leakage_11);
+ // --------------------------------------------------------------------
+
+ // --------------------------------------------------------------------
+ // Get Node Capacitances
+ // --------------------------------------------------------------------
+ double a_cap = getNet("A")->getTotalDownstreamCap();
+ double b_cap = getNet("B")->getTotalDownstreamCap();
+ double y_b_cap = getNet("Y_b")->getTotalDownstreamCap();
+ double y_cap = getNet("Y")->getTotalDownstreamCap();
+
+ cache->set(cell_name + "->Cap->A", a_cap);
+ cache->set(cell_name + "->Cap->B", b_cap);
+ cache->set(cell_name + "->Cap->Y_b", y_b_cap);
+ cache->set(cell_name + "->Cap->Y", y_cap);
+ Log::printLine(cell_name + "->Cap->A_Cap=" + (String) a_cap);
+ Log::printLine(cell_name + "->Cap->B_Cap=" + (String) b_cap);
+ Log::printLine(cell_name + "->Cap->Y_b_Cap=" + (String) y_b_cap);
+ Log::printLine(cell_name + "->Cap->Y_Cap=" + (String) y_cap);
+ // --------------------------------------------------------------------
+
+ // --------------------------------------------------------------------
+ // Build Internal Delay Model
+ // --------------------------------------------------------------------
+ double y_ron = getDriver("INV_RonZN")->getOutputRes();
+ double a_to_y_delay = getDriver("NOR2_RonZN")->calculateDelay() +
+ getDriver("INV_RonZN")->calculateDelay();
+ double b_to_y_delay = getDriver("NOR2_RonZN")->calculateDelay() +
+ getDriver("INV_RonZN")->calculateDelay();
+
+ cache->set(cell_name + "->DriveRes->Y", y_ron);
+ cache->set(cell_name + "->Delay->A_to_Y", a_to_y_delay);
+ cache->set(cell_name + "->Delay->B_to_Y", b_to_y_delay);
+ Log::printLine(cell_name + "->DriveRes->Y=" + (String) y_ron);
+ Log::printLine(cell_name + "->Delay->A_to_Y=" + (String) a_to_y_delay);
+ Log::printLine(cell_name + "->Delay->B_to_Y=" + (String) b_to_y_delay);
+ // --------------------------------------------------------------------
+
+ return;
+ }
+} // namespace DSENT
+
diff --git a/ext/dsent/model/std_cells/OR2.h b/ext/dsent/model/std_cells/OR2.h
new file mode 100644
index 000000000..8e08131f1
--- /dev/null
+++ b/ext/dsent/model/std_cells/OR2.h
@@ -0,0 +1,33 @@
+#ifndef __DSENT_MODEL_STD_CELLS_OR2_H__
+#define __DSENT_MODEL_STD_CELLS_OR2_H__
+
+#include "util/CommonType.h"
+#include "model/std_cells/StdCell.h"
+
+namespace DSENT
+{
+ class OR2 : public StdCell
+ {
+ public:
+ OR2(const String& instance_name_, const TechModel* tech_model_);
+ virtual ~OR2();
+
+ public:
+ // Set a list of properties' name needed to construct model
+ void initProperties();
+ // Cache the standard cell
+ void cacheStdCell(StdCellLib* cell_lib_, double drive_strength_);
+
+ protected:
+ // Build the model
+ virtual void constructModel();
+ virtual void updateModel();
+ virtual void evaluateModel();
+ virtual void useModel();
+ virtual void propagateTransitionInfo();
+
+ }; // class OR2
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_STD_CELLS_OR2_H__
+
diff --git a/ext/dsent/model/std_cells/StdCell.cc b/ext/dsent/model/std_cells/StdCell.cc
new file mode 100644
index 000000000..bc95f97c3
--- /dev/null
+++ b/ext/dsent/model/std_cells/StdCell.cc
@@ -0,0 +1,71 @@
+#include "model/std_cells/StdCell.h"
+
+#include "model/timing_graph/ElectricalNet.h"
+#include "model/timing_graph/ElectricalDriver.h"
+#include "model/timing_graph/ElectricalLoad.h"
+
+#include <cmath>
+#include <algorithm>
+
+namespace DSENT
+{
+ StdCell::StdCell(const String& instance_name_, const TechModel* tech_model_)
+ : ElectricalModel(instance_name_, tech_model_)
+ {
+ initParameters();
+ initProperties();
+ }
+
+ StdCell::~StdCell()
+ {
+
+ }
+
+
+ void StdCell::initParameters()
+ {
+ addParameterName("AvailableDrivingStrengths");
+ return;
+ }
+
+ void StdCell::initProperties()
+ {
+ addPropertyName("DrivingStrength");
+ return;
+ }
+
+ // Get PMOS to NMOS ratio
+ double StdCell::getPToNRatio() const
+ {
+ return m_p_to_n_ratio_;
+ }
+
+ void StdCell::setPToNRatio(double p_to_n_ratio_)
+ {
+ m_p_to_n_ratio_ = p_to_n_ratio_;
+ }
+
+ // Get height of the standard cell taken by active transistors
+ double StdCell::getActiveHeight() const
+ {
+ return m_active_height_;
+ }
+
+ void StdCell::setActiveHeight(double active_height_)
+ {
+ m_active_height_ = active_height_;
+ }
+
+ // Get total height of the standard cell including overheads
+ double StdCell::getTotalHeight() const
+ {
+ return m_total_height_;
+ }
+
+ void StdCell::setTotalHeight(double total_height_)
+ {
+ m_total_height_ = total_height_;
+ }
+
+} // namespace DSENT
+
diff --git a/ext/dsent/model/std_cells/StdCell.h b/ext/dsent/model/std_cells/StdCell.h
new file mode 100644
index 000000000..25a65768a
--- /dev/null
+++ b/ext/dsent/model/std_cells/StdCell.h
@@ -0,0 +1,53 @@
+#ifndef __DSENT_MODEL_STD_CELLS_STDCELL_H__
+#define __DSENT_MODEL_STD_CELLS_STDCELL_H__
+
+#include "util/CommonType.h"
+#include "model/ElectricalModel.h"
+
+namespace DSENT
+{
+ class StdCell : public ElectricalModel
+ {
+ public:
+ StdCell(const String& instance_name_, const TechModel* tech_model_);
+ virtual ~StdCell();
+
+ public:
+ // Set a list of parameters needed to construct model
+ virtual void initParameters();
+ // Set a list of properties needed to update model
+ virtual void initProperties();
+
+ // Get PMOS to NMOS ratio
+ double getPToNRatio() const;
+ void setPToNRatio(double p_to_n_ratio_);
+ // Get height of the standard cell taken by active transistors
+ double getActiveHeight() const;
+ void setActiveHeight(double active_height_);
+ // Get total height of the standard cell including overheads
+ double getTotalHeight() const;
+ void setTotalHeight(double total_height_);
+
+ // Construct the full model of the standard cell and cache
+ // its contents to use for future copies of the standard cell
+ virtual void cacheStdCell(StdCellLib* cell_lib_, double drive_strength_) = 0;
+
+ protected:
+ // Build the model, note that this is only available if the
+ // standard cell has been cached (via cacheStdCellModel)
+ virtual void constructModel() = 0;
+ virtual void updateModel() = 0;
+
+ private:
+ // The PMOS to NMOS ratio
+ double m_p_to_n_ratio_;
+ // The height of the standard cell taken by active transitors
+ double m_active_height_;
+ // The total height of the standard cell including overheads
+ double m_total_height_;
+
+ }; // class StdCell
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_STD_CELLS_STDCELL_H__
+
diff --git a/ext/dsent/model/std_cells/StdCellLib.cc b/ext/dsent/model/std_cells/StdCellLib.cc
new file mode 100644
index 000000000..dfe32012b
--- /dev/null
+++ b/ext/dsent/model/std_cells/StdCellLib.cc
@@ -0,0 +1,180 @@
+#include "model/std_cells/StdCellLib.h"
+
+#include <cmath>
+
+#include "model/std_cells/StdCell.h"
+#include "model/std_cells/INV.h"
+#include "model/ModelGen.h"
+
+namespace DSENT
+{
+ using std::pow;
+
+ StdCellLib::StdCellLib(TechModel* tech_model_)
+ : m_tech_model_(tech_model_)
+ {
+ m_std_cell_cache_ = new Map<double>();
+ ASSERT((m_tech_model_ != NULL), "[Error] StdCellLib -> tech_model is NULL");
+ createLib();
+ }
+
+ StdCellLib::~StdCellLib()
+ {
+ delete m_std_cell_cache_;
+ }
+
+ const TechModel* StdCellLib::getTechModel() const
+ {
+ return m_tech_model_;
+ }
+
+ StdCell* StdCellLib::createStdCell(const String& std_cell_name_, const String& instance_name_) const
+ {
+ // Create the standard cell
+ StdCell* created_cell = ModelGen::createStdCell(std_cell_name_, instance_name_, getTechModel());
+ // Grab the variants of each standard cell
+ String driving_strength_str = getTechModel()->get("StdCell->AvailableSizes");
+ // Set library properties for the standard cell
+ created_cell->setPToNRatio(getPToNRatio());
+ created_cell->setActiveHeight(getActiveHeight());
+ created_cell->setTotalHeight(getTotalHeight());
+ created_cell->setAvailableDrivingStrengths(driving_strength_str);
+ return created_cell;
+ }
+
+ // Get PMOS to NMOS ratio
+ double StdCellLib::getPToNRatio() const
+ {
+ return m_p_to_n_ratio_;
+ }
+
+ void StdCellLib::setPToNRatio(double p_to_n_ratio_)
+ {
+ m_p_to_n_ratio_ = p_to_n_ratio_;
+ }
+
+ // Get height of the standard cell taken by active transistors
+ double StdCellLib::getActiveHeight() const
+ {
+ return m_active_height_;
+ }
+
+ void StdCellLib::setActiveHeight(double active_height_)
+ {
+ m_active_height_ = active_height_;
+ }
+
+ // Get total height of the standard cell including overheads
+ double StdCellLib::getTotalHeight() const
+ {
+ return m_total_height_;
+ }
+
+ void StdCellLib::setTotalHeight(double total_height_)
+ {
+ m_total_height_ = total_height_;
+ }
+
+ void StdCellLib::createLib()
+ {
+ Log::printLine("Standard cell library creation for tech model " + getTechModel()->get("Name"));
+
+ // Get technology parameters
+ double nmos_eff_res = getTechModel()->get("Nmos->EffResWidth");
+ double pmos_eff_res = getTechModel()->get("Pmos->EffResWidth");
+ double gate_min_width = getTechModel()->get("Gate->MinWidth");
+
+ // Create standard cell common parameters
+ double pn_ratio = pmos_eff_res / nmos_eff_res;
+ double nmos_unit_width = gate_min_width;
+ double pmos_unit_width = gate_min_width * pn_ratio;
+
+ // Derive the height of each cell in the standard cell library, as well as the max Nmos and Pmos widths
+ double std_cell_total_height = getTechModel()->get("StdCell->Tracks").toDouble() *
+ (getTechModel()->get("Wire->Metal1->MinWidth").toDouble() + getTechModel()->get("Wire->Metal1->MinSpacing").toDouble());
+ double std_cell_active_height = std_cell_total_height / getTechModel()->get("StdCell->HeightOverheadFactor").toDouble();
+
+ Log::printLine("Standard cell P-to-N ratio (Beta) = " + (String) pn_ratio);
+ Log::printLine("Standard cell NMOS unit width = " + (String) nmos_unit_width);
+ Log::printLine("Standard cell PMOS unit width = " + (String) pmos_unit_width);
+ Log::printLine("Standard cell active height = " + (String) std_cell_active_height);
+ Log::printLine("Standard cell total height = " + (String) std_cell_total_height);
+
+ setPToNRatio(pn_ratio);
+ setActiveHeight(std_cell_active_height);
+ setTotalHeight(std_cell_total_height);
+
+ const vector<String>& cell_sizes = getTechModel()->get("StdCell->AvailableSizes").split("[,]");
+ // Create cached standard cells
+ for (unsigned int i = 0; i < cell_sizes.size(); ++i)
+ {
+ StdCell* inv = createStdCell("INV", "CachedINV");
+ inv->cacheStdCell(this, cell_sizes[i].toDouble());
+ delete inv;
+
+ StdCell* nand2 = createStdCell("NAND2", "CachedNAND2");
+ nand2->cacheStdCell(this, cell_sizes[i].toDouble());
+ delete nand2;
+
+ StdCell* nor2 = createStdCell("NOR2", "CachedNOR2");
+ nor2->cacheStdCell(this, cell_sizes[i].toDouble());
+ delete nor2;
+
+ StdCell* mux2 = createStdCell("MUX2", "CachedMUX2");
+ mux2->cacheStdCell(this, cell_sizes[i].toDouble());
+ delete mux2;
+
+ StdCell* xor2 = createStdCell("XOR2", "CachedXOR2");
+ xor2->cacheStdCell(this, cell_sizes[i].toDouble());
+ delete xor2;
+
+ StdCell* addf = createStdCell("ADDF", "CachedADDF");
+ addf->cacheStdCell(this, cell_sizes[i].toDouble());
+ delete addf;
+
+ StdCell* dffq = createStdCell("DFFQ", "CachedDFFQ");
+ dffq->cacheStdCell(this, cell_sizes[i].toDouble());
+ delete dffq;
+
+ StdCell* latq = createStdCell("LATQ", "CachedLATQ");
+ latq->cacheStdCell(this, cell_sizes[i].toDouble());
+ delete latq;
+
+ StdCell* or2 = createStdCell("OR2", "CachedOR2");
+ or2->cacheStdCell(this, cell_sizes[i].toDouble());
+ delete or2;
+
+ StdCell* and2 = createStdCell("AND2", "CachedAND2");
+ and2->cacheStdCell(this, cell_sizes[i].toDouble());
+ delete and2;
+ }
+
+ Log::printLine("Standard cell library creation - End");
+ return;
+ }
+
+ StdCellLib* StdCellLib::clone() const
+ {
+ StdCellLib* new_lib = new StdCellLib(m_tech_model_);
+ return new_lib;
+ }
+
+ const String StdCellLib::genDrivingStrengthString(const vector<double>& driving_strength_) const
+ {
+ String ret_str = "[";
+ for(int i = 0; i < (int)driving_strength_.size() - 1; ++i)
+ {
+ ret_str += String(driving_strength_[i]) + ", ";
+ }
+ ret_str += String(driving_strength_[driving_strength_.size() - 1]);
+ ret_str += "]";
+ return ret_str;
+ }
+
+ Map<double>* StdCellLib::getStdCellCache() const
+ {
+ return m_std_cell_cache_;
+ }
+
+} // namespace DSENT
+
diff --git a/ext/dsent/model/std_cells/StdCellLib.h b/ext/dsent/model/std_cells/StdCellLib.h
new file mode 100644
index 000000000..74c09149e
--- /dev/null
+++ b/ext/dsent/model/std_cells/StdCellLib.h
@@ -0,0 +1,63 @@
+#ifndef __DSENT_MODEL_STD_CELLS_STDCELLLIBS_H__
+#define __DSENT_MODEL_STD_CELLS_STDCELLLIBS_H__
+
+#include "util/CommonType.h"
+
+namespace DSENT
+{
+ class TechModel;
+ class StdCell;
+ class LibertyFile;
+
+ class StdCellLib
+ {
+ public:
+ StdCellLib(TechModel* tech_model_);
+ ~StdCellLib();
+
+ public:
+ // Get the technology model pointer
+ const TechModel* getTechModel() const;
+ // Create a standard cell by name and instance name
+ StdCell* createStdCell(const String& std_cell_name_, const String& instance_name_) const;
+
+ // Get PMOS to NMOS ratio
+ double getPToNRatio() const;
+ void setPToNRatio(double p_to_n_ratio_);
+ // Get height of the standard cell taken by active transistors
+ double getActiveHeight() const;
+ void setActiveHeight(double active_height_);
+ // Get total height of the standard cell including overheads
+ double getTotalHeight() const;
+ void setTotalHeight(double total_height_);
+ // Get the standard cell library cache of values
+ Map<double>* getStdCellCache() const;
+ // Create a list of standard cells
+ void createLib();
+
+ // Return a copy of this instance
+ StdCellLib* clone() const;
+
+ private:
+ // Disabled copy constructor. Use clone to perform copy operation
+ StdCellLib(const StdCellLib& std_cell_lib_);
+ // Generate driving strength string
+ const String genDrivingStrengthString(const vector<double>& driving_strength_) const;
+
+ private:
+ // Technology model pointer
+ TechModel* m_tech_model_;
+ // The PMOS to NMOS ratio
+ double m_p_to_n_ratio_;
+ // The height of the standard cell taken by active transitors
+ double m_active_height_;
+ // The total height of the standard cell including overheads
+ double m_total_height_;
+ // Std cell values cache
+ Map<double>* m_std_cell_cache_;
+
+ }; // class StdCellLib
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_STD_CELLS_STDCELLLIBS_H__
+
diff --git a/ext/dsent/model/std_cells/XOR2.cc b/ext/dsent/model/std_cells/XOR2.cc
new file mode 100644
index 000000000..5b57b55e5
--- /dev/null
+++ b/ext/dsent/model/std_cells/XOR2.cc
@@ -0,0 +1,345 @@
+#include "model/std_cells/XOR2.h"
+
+#include <cmath>
+
+#include "model/PortInfo.h"
+#include "model/EventInfo.h"
+#include "model/TransitionInfo.h"
+#include "model/std_cells/StdCellLib.h"
+#include "model/std_cells/CellMacros.h"
+#include "model/timing_graph/ElectricalNet.h"
+#include "model/timing_graph/ElectricalDriver.h"
+#include "model/timing_graph/ElectricalLoad.h"
+#include "model/timing_graph/ElectricalDelay.h"
+
+namespace DSENT
+{
+ using std::ceil;
+ using std::max;
+
+ XOR2::XOR2(const String& instance_name_, const TechModel* tech_model_)
+ : StdCell(instance_name_, tech_model_)
+ {
+ initProperties();
+ }
+
+ XOR2::~XOR2()
+ {}
+
+ void XOR2::initProperties()
+ {
+ return;
+ }
+
+ void XOR2::constructModel()
+ {
+ // All constructModel should do is create Area/NDDPower/Energy Results as
+ // well as instantiate any sub-instances using only the hard parameters
+
+ createInputPort("A");
+ createInputPort("B");
+ createOutputPort("Y");
+
+ createLoad("A_Cap");
+ createLoad("B_Cap");
+ createDelay("A_to_Y_delay");
+ createDelay("B_to_Y_delay");
+ createDriver("Y_Ron", true);
+
+ ElectricalLoad* a_cap = getLoad("A_Cap");
+ ElectricalLoad* b_cap = getLoad("B_Cap");
+ ElectricalDelay* a_to_y_delay = getDelay("A_to_Y_delay");
+ ElectricalDelay* b_to_y_delay = getDelay("B_to_Y_delay");
+ ElectricalDriver* y_ron = getDriver("Y_Ron");
+
+ getNet("A")->addDownstreamNode(a_cap);
+ getNet("B")->addDownstreamNode(b_cap);
+ a_cap->addDownstreamNode(a_to_y_delay);
+ b_cap->addDownstreamNode(b_to_y_delay);
+ a_to_y_delay->addDownstreamNode(y_ron);
+ b_to_y_delay->addDownstreamNode(y_ron);
+ y_ron->addDownstreamNode(getNet("Y"));
+
+ // Create Area result
+ // Create NDD Power result
+ createElectricalAtomicResults();
+ // Create XOR2 Event Energy Result
+ createElectricalEventAtomicResult("XOR2");
+
+ getEventInfo("Idle")->setStaticTransitionInfos();
+
+ return;
+ }
+
+ void XOR2::updateModel()
+ {
+ // Get parameters
+ double drive_strength = getDrivingStrength();
+ Map<double>* cache = getTechModel()->getStdCellLib()->getStdCellCache();
+
+ // Standard cell cache string
+ String cell_name = "XOR2_X" + (String) drive_strength;
+
+ // Get timing parameters
+ getLoad("A_Cap")->setLoadCap(cache->get(cell_name + "->Cap->A"));
+ getLoad("B_Cap")->setLoadCap(cache->get(cell_name + "->Cap->B"));
+
+ getDelay("A_to_Y_delay")->setDelay(cache->get(cell_name + "->Delay->A_to_Y"));
+ getDelay("B_to_Y_delay")->setDelay(cache->get(cell_name + "->Delay->B_to_Y"));
+
+ getDriver("Y_Ron")->setOutputRes(cache->get(cell_name + "->DriveRes->Y"));
+
+ // Set the cell area
+ getAreaResult("Active")->setValue(cache->get(cell_name + "->ActiveArea"));
+ getAreaResult("Metal1Wire")->setValue(cache->get(cell_name + "->ActiveArea"));
+
+ return;
+ }
+
+ void XOR2::evaluateModel()
+ {
+ return;
+ }
+
+ void XOR2::useModel()
+ {
+ // Get parameters
+ double drive_strength = getDrivingStrength();
+ Map<double>* cache = getTechModel()->getStdCellLib()->getStdCellCache();
+
+ // Standard cell cache string
+ String cell_name = "XOR2_X" + (String) drive_strength;
+
+ // Propagate the transition info and get the 0->1 transtion count
+ propagateTransitionInfo();
+ double P_A = getInputPort("A")->getTransitionInfo().getProbability1();
+ double P_B = getInputPort("B")->getTransitionInfo().getProbability1();
+ double A_num_trans_01 = getInputPort("A")->getTransitionInfo().getNumberTransitions01();
+ double B_num_trans_01 = getInputPort("B")->getTransitionInfo().getNumberTransitions01();
+ double Y_num_trans_01 = getOutputPort("Y")->getTransitionInfo().getNumberTransitions01();
+
+ // Calculate leakage
+ double leakage = 0;
+ leakage += cache->get(cell_name + "->Leakage->!A!B") * (1 - P_A) * (1 - P_B);
+ leakage += cache->get(cell_name + "->Leakage->!AB") * (1 - P_A) * P_B;
+ leakage += cache->get(cell_name + "->Leakage->A!B") * P_A * (1 - P_B);
+ leakage += cache->get(cell_name + "->Leakage->AB") * P_A * P_B;
+ getNddPowerResult("Leakage")->setValue(leakage);
+
+ // Get VDD
+ double vdd = getTechModel()->get("Vdd");
+
+ // Get capacitances
+ double a_b_cap = cache->get(cell_name + "->Cap->A_b");
+ double b_b_cap = cache->get(cell_name + "->Cap->B_b");
+ double y_cap = cache->get(cell_name + "->Cap->Y");
+ double y_load_cap = getNet("Y")->getTotalDownstreamCap();
+
+ // Calculate XOR Event energy
+ double xor2_event_result = 0.0;
+ xor2_event_result += a_b_cap * A_num_trans_01;
+ xor2_event_result += b_b_cap * B_num_trans_01;
+ xor2_event_result += (y_cap + y_load_cap) * Y_num_trans_01;
+ xor2_event_result *= vdd * vdd;
+ getEventResult("XOR2")->setValue(xor2_event_result);
+
+ return;
+ }
+
+ void XOR2::propagateTransitionInfo()
+ {
+ // Get input signal transition info
+ const TransitionInfo& trans_A = getInputPort("A")->getTransitionInfo();
+ const TransitionInfo& trans_B = getInputPort("B")->getTransitionInfo();
+
+ double max_freq_mult = max(trans_A.getFrequencyMultiplier(), trans_B.getFrequencyMultiplier());
+ const TransitionInfo& scaled_trans_A = trans_A.scaleFrequencyMultiplier(max_freq_mult);
+ const TransitionInfo& scaled_trans_B = trans_B.scaleFrequencyMultiplier(max_freq_mult);
+
+
+ double A_prob_00 = scaled_trans_A.getNumberTransitions00() / max_freq_mult;
+ double A_prob_01 = scaled_trans_A.getNumberTransitions01() / max_freq_mult;
+ double A_prob_10 = A_prob_01;
+ double A_prob_11 = scaled_trans_A.getNumberTransitions11() / max_freq_mult;
+ double B_prob_00 = scaled_trans_B.getNumberTransitions00() / max_freq_mult;
+ double B_prob_01 = scaled_trans_B.getNumberTransitions01() / max_freq_mult;
+ double B_prob_10 = B_prob_01;
+ double B_prob_11 = scaled_trans_B.getNumberTransitions11() / max_freq_mult;
+
+ // Set output transition info
+ double Y_prob_00 = A_prob_00 * B_prob_00 +
+ A_prob_01 * B_prob_01 +
+ A_prob_10 * B_prob_10 +
+ A_prob_11 * B_prob_11;
+ double Y_prob_01 = A_prob_00 * B_prob_01 +
+ A_prob_01 * B_prob_00 +
+ A_prob_10 * B_prob_11 +
+ A_prob_11 * B_prob_10;
+ double Y_prob_11 = A_prob_00 * B_prob_11 +
+ A_prob_01 * B_prob_10 +
+ A_prob_10 * B_prob_01 +
+ A_prob_11 * B_prob_00;
+
+ // Check that probabilities add up to 1.0 with some finite tolerance
+ ASSERT(LibUtil::Math::isEqual((Y_prob_00 + Y_prob_01 + Y_prob_01 + Y_prob_11), 1.0),
+ "[Error] " + getInstanceName() + "Output transition probabilities must add up to 1 (" +
+ (String) Y_prob_00 + ", " + (String) Y_prob_01 + ", " + (String) Y_prob_11 + ")!");
+
+ // Turn probability of transitions per cycle into number of transitions per time unit
+ TransitionInfo trans_Y(Y_prob_00 * max_freq_mult, Y_prob_01 * max_freq_mult, Y_prob_11 * max_freq_mult);
+ getOutputPort("Y")->setTransitionInfo(trans_Y);
+ return;
+ }
+
+ // Creates the standard cell, characterizes and abstracts away the details
+ void XOR2::cacheStdCell(StdCellLib* cell_lib_, double drive_strength_)
+ {
+ // Get parameters
+ double gate_pitch = cell_lib_->getTechModel()->get("Gate->PitchContacted");
+ Map<double>* cache = cell_lib_->getStdCellCache();
+
+ // Standard cell cache string
+ String cell_name = "XOR2_X" + (String) drive_strength_;
+
+ Log::printLine("=== " + cell_name + " ===");
+
+ // Now actually build the full standard cell model
+ createInputPort("A");
+ createInputPort("B");
+ createOutputPort("Y");
+
+ createNet("A_b");
+ createNet("B_b");
+
+ // Adds macros
+ CellMacros::addInverter(this, "INV1", false, true, "A", "A_b");
+ CellMacros::addInverter(this, "INV2", false, true, "B", "B_b");
+ CellMacros::addTristate(this, "INVZ1", true, true, true, true, "B", "A", "A_b", "Y");
+ CellMacros::addTristate(this, "INVZ2", true, true, true, true, "B_b", "A_b", "A", "Y");
+
+ // I have no idea how to size each of the parts haha
+ CellMacros::updateInverter(this, "INV1", drive_strength_ * 0.500);
+ CellMacros::updateInverter(this, "INV2", drive_strength_ * 0.500);
+ CellMacros::updateTristate(this, "INVZ1", drive_strength_ * 1.000);
+ CellMacros::updateTristate(this, "INVZ2", drive_strength_ * 1.000);
+
+ // Cache area result
+ double area = 0.0;
+ area += gate_pitch * getTotalHeight() * 1;
+ area += gate_pitch * getTotalHeight() * getGenProperties()->get("INV1_GatePitches").toDouble();
+ area += gate_pitch * getTotalHeight() * getGenProperties()->get("INV2_GatePitches").toDouble();
+ area += gate_pitch * getTotalHeight() * getGenProperties()->get("INVZ1_GatePitches").toDouble();
+ area += gate_pitch * getTotalHeight() * getGenProperties()->get("INVZ2_GatePitches").toDouble();
+ cache->set(cell_name + "->ActiveArea", area);
+ Log::printLine(cell_name + "->ActiveArea=" + (String) area);
+
+ // --------------------------------------------------------------------
+ // Leakage Model Calculation
+ // --------------------------------------------------------------------
+ // Cache leakage power results (for every single signal combination)
+ double leakage_00 = 0; //!A, !B
+ double leakage_01 = 0; //!A, B
+ double leakage_10 = 0; //A, !B
+ double leakage_11 = 0; //A, B
+
+ //This is so painful...
+ leakage_00 += getGenProperties()->get("INV1_LeakagePower_0").toDouble();
+ leakage_00 += getGenProperties()->get("INV2_LeakagePower_0").toDouble();
+ leakage_00 += getGenProperties()->get("INVZ1_LeakagePower_010_0").toDouble();
+ leakage_00 += getGenProperties()->get("INVZ2_LeakagePower_101_0").toDouble();
+
+ leakage_01 += getGenProperties()->get("INV1_LeakagePower_0").toDouble();
+ leakage_01 += getGenProperties()->get("INV2_LeakagePower_1").toDouble();
+ leakage_01 += getGenProperties()->get("INVZ1_LeakagePower_011_1").toDouble();
+ leakage_01 += getGenProperties()->get("INVZ2_LeakagePower_100_1").toDouble();
+
+ leakage_10 += getGenProperties()->get("INV1_LeakagePower_1").toDouble();
+ leakage_10 += getGenProperties()->get("INV2_LeakagePower_0").toDouble();
+ leakage_10 += getGenProperties()->get("INVZ1_LeakagePower_100_1").toDouble();
+ leakage_10 += getGenProperties()->get("INVZ2_LeakagePower_011_1").toDouble();
+
+ leakage_11 += getGenProperties()->get("INV1_LeakagePower_1").toDouble();
+ leakage_11 += getGenProperties()->get("INV2_LeakagePower_1").toDouble();
+ leakage_11 += getGenProperties()->get("INVZ1_LeakagePower_101_0").toDouble();
+ leakage_11 += getGenProperties()->get("INVZ2_LeakagePower_010_0").toDouble();
+
+ cache->set(cell_name + "->Leakage->!A!B", leakage_00);
+ cache->set(cell_name + "->Leakage->!AB", leakage_01);
+ cache->set(cell_name + "->Leakage->A!B", leakage_10);
+ cache->set(cell_name + "->Leakage->AB", leakage_11);
+ Log::printLine(cell_name + "->Leakage->!A!B=" + (String) leakage_00);
+ Log::printLine(cell_name + "->Leakage->!AB=" + (String) leakage_01);
+ Log::printLine(cell_name + "->Leakage->A!B=" + (String) leakage_10);
+ Log::printLine(cell_name + "->Leakage->AB=" + (String) leakage_11);
+ // --------------------------------------------------------------------
+
+ // Cache event energy results
+ /*
+ double event_a_flip = 0.0;
+ event_a_flip += getGenProperties()->get("INV1_A_Flip").toDouble() + getGenProperties()->get("INV1_ZN_Flip").toDouble();
+ event_a_flip += getGenProperties()->get("INVZ1_OE_Flip").toDouble() + getGenProperties()->get("INVZ1_OEN_Flip").toDouble();
+ event_a_flip += getGenProperties()->get("INVZ2_OE_Flip").toDouble() + getGenProperties()->get("INVZ2_OEN_Flip").toDouble();
+ cache->set(cell_name + "->Event_A_Flip", event_a_flip);
+ Log::printLine(cell_name + "->Event_A_Flip=" + (String) event_a_flip);
+
+ double event_b_flip = 0.0;
+ event_b_flip += getGenProperties()->get("INV2_A_Flip").toDouble() + getGenProperties()->get("INV2_ZN_Flip").toDouble();
+ event_b_flip += getGenProperties()->get("INVZ1_A_Flip").toDouble();
+ event_b_flip += getGenProperties()->get("INVZ2_A_Flip").toDouble();
+ cache->set(cell_name + "->Event_B_Flip", event_b_flip);
+ Log::printLine(cell_name + "->Event_B_Flip=" + (String) event_b_flip);
+
+ double event_y_flip = 0.0;
+ event_y_flip += getGenProperties()->get("INVZ1_ZN_Flip").toDouble();
+ event_y_flip += getGenProperties()->get("INVZ2_ZN_Flip").toDouble();
+ cache->set(cell_name + "->Event_Y_Flip", event_y_flip);
+ Log::printLine(cell_name + "->Event_Y_Flip=" + (String) event_y_flip);
+ */
+
+ // --------------------------------------------------------------------
+ // Get Node Capacitances
+ // --------------------------------------------------------------------
+ // Build abstracted timing model
+ double a_cap = getNet("A")->getTotalDownstreamCap();
+ double b_cap = getNet("B")->getTotalDownstreamCap();
+ double a_b_cap = getNet("A_b")->getTotalDownstreamCap();
+ double b_b_cap = getNet("B_b")->getTotalDownstreamCap();
+ double y_cap = getNet("Y")->getTotalDownstreamCap();
+
+ cache->set(cell_name + "->Cap->A", a_cap);
+ cache->set(cell_name + "->Cap->B", b_cap);
+ cache->set(cell_name + "->Cap->A_b", a_b_cap);
+ cache->set(cell_name + "->Cap->B_b", b_b_cap);
+ cache->set(cell_name + "->Cap->Y", y_cap);
+ Log::printLine(cell_name + "->Cap->A=" + (String) a_cap);
+ Log::printLine(cell_name + "->Cap->B=" + (String) b_cap);
+ Log::printLine(cell_name + "->Cap->A=" + (String) a_b_cap);
+ Log::printLine(cell_name + "->Cap->B=" + (String) b_b_cap);
+ Log::printLine(cell_name + "->Cap->Y=" + (String) y_cap);
+ // --------------------------------------------------------------------
+
+ // --------------------------------------------------------------------
+ // Build Internal Delay Model
+ // --------------------------------------------------------------------
+ double y_ron = (getDriver("INVZ1_RonZN")->getOutputRes() + getDriver("INVZ2_RonZN")->getOutputRes()) / 2;
+
+ double a_to_y_delay = 0.0;
+ a_to_y_delay += getDriver("INV1_RonZN")->calculateDelay();
+ a_to_y_delay += max(getDriver("INVZ1_RonZN")->calculateDelay(), getDriver("INVZ2_RonZN")->calculateDelay());
+
+ double b_to_y_delay = 0.0;
+ b_to_y_delay += max(getDriver("INVZ1_RonZN")->calculateDelay(), getDriver("INV2_RonZN")->calculateDelay() + getDriver("INVZ2_RonZN")->calculateDelay());
+
+ cache->set(cell_name + "->DriveRes->Y", y_ron);
+ cache->set(cell_name + "->Delay->A_to_Y", a_to_y_delay);
+ cache->set(cell_name + "->Delay->B_to_Y", b_to_y_delay);
+ Log::printLine(cell_name + "->DriveRes->Y=" + (String) y_ron);
+ Log::printLine(cell_name + "->Delay->A_to_Y=" + (String) a_to_y_delay);
+ Log::printLine(cell_name + "->Delay->B_to_Y=" + (String) b_to_y_delay);
+ // --------------------------------------------------------------------
+
+ return;
+ }
+
+} // namespace DSENT
+
diff --git a/ext/dsent/model/std_cells/XOR2.h b/ext/dsent/model/std_cells/XOR2.h
new file mode 100644
index 000000000..95f9a54b3
--- /dev/null
+++ b/ext/dsent/model/std_cells/XOR2.h
@@ -0,0 +1,34 @@
+#ifndef __DSENT_MODEL_STD_CELLS_XOR2_H__
+#define __DSENT_MODEL_STD_CELLS_XOR2_H__
+
+#include "util/CommonType.h"
+#include "model/std_cells/StdCell.h"
+
+namespace DSENT
+{
+ class XOR2 : public StdCell
+ {
+ public:
+ XOR2(const String& instance_name_, const TechModel* tech_model_);
+ virtual ~XOR2();
+
+ public:
+ // Set a list of properties' name needed to construct model
+ void initProperties();
+
+ // Cache the standard cell
+ void cacheStdCell(StdCellLib* cell_lib_, double drive_strength_);
+
+ protected:
+ // Build the model
+ virtual void constructModel();
+ virtual void updateModel();
+ virtual void evaluateModel();
+ virtual void useModel();
+ virtual void propagateTransitionInfo();
+
+ }; // class XOR2
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_STD_CELLS_XOR2_H__
+
diff --git a/ext/dsent/model/timing_graph/ElectricalDelay.cc b/ext/dsent/model/timing_graph/ElectricalDelay.cc
new file mode 100644
index 000000000..e87a77be9
--- /dev/null
+++ b/ext/dsent/model/timing_graph/ElectricalDelay.cc
@@ -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
index 000000000..d3d3d3a8c
--- /dev/null
+++ b/ext/dsent/model/timing_graph/ElectricalDelay.h
@@ -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
index 000000000..9456ef067
--- /dev/null
+++ b/ext/dsent/model/timing_graph/ElectricalDriver.cc
@@ -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
index 000000000..604206b5d
--- /dev/null
+++ b/ext/dsent/model/timing_graph/ElectricalDriver.h
@@ -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
index 000000000..bf8600fd8
--- /dev/null
+++ b/ext/dsent/model/timing_graph/ElectricalDriverMultiplier.cc
@@ -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
index 000000000..62b14569f
--- /dev/null
+++ b/ext/dsent/model/timing_graph/ElectricalDriverMultiplier.h
@@ -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
index 000000000..a20d6459d
--- /dev/null
+++ b/ext/dsent/model/timing_graph/ElectricalLoad.cc
@@ -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
index 000000000..551eccf85
--- /dev/null
+++ b/ext/dsent/model/timing_graph/ElectricalLoad.h
@@ -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
index 000000000..09baa77e5
--- /dev/null
+++ b/ext/dsent/model/timing_graph/ElectricalNet.cc
@@ -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
index 000000000..b96bfea91
--- /dev/null
+++ b/ext/dsent/model/timing_graph/ElectricalNet.h
@@ -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
index 000000000..d8b2bfd13
--- /dev/null
+++ b/ext/dsent/model/timing_graph/ElectricalTimingNode.cc
@@ -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
index 000000000..01c6497da
--- /dev/null
+++ b/ext/dsent/model/timing_graph/ElectricalTimingNode.h
@@ -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
index 000000000..dd7b4330a
--- /dev/null
+++ b/ext/dsent/model/timing_graph/ElectricalTimingOptimizer.cc
@@ -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
index 000000000..c0c850e0b
--- /dev/null
+++ b/ext/dsent/model/timing_graph/ElectricalTimingOptimizer.h
@@ -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
index 000000000..83d583c53
--- /dev/null
+++ b/ext/dsent/model/timing_graph/ElectricalTimingTree.cc
@@ -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
index 000000000..4dfbff8a7
--- /dev/null
+++ b/ext/dsent/model/timing_graph/ElectricalTimingTree.h
@@ -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
index 000000000..5922177ad
--- /dev/null
+++ b/ext/dsent/tech/TechModel.cc
@@ -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
index 000000000..92e5a30ac
--- /dev/null
+++ b/ext/dsent/tech/TechModel.h
@@ -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
index 000000000..e2087a12d
--- /dev/null
+++ b/ext/dsent/tech/tech_models/Bulk22LVT.model
@@ -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
index 000000000..9a90bdaf9
--- /dev/null
+++ b/ext/dsent/tech/tech_models/Bulk32LVT.model
@@ -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 32nm LVT process
+Name = Bulk32LVT
+
+# Supply voltage used in the circuit and for characterizations (V)
+Vdd = 0.9
+# Temperature (K)
+Temperature = 340
+
+# =============================================================================
+# Parameters for transistors
+# =============================================================================
+
+# Contacted gate pitch (m)
+Gate->PitchContacted = 0.160e-6
+
+# Min gate width (m)
+Gate->MinWidth = 0.120e-6
+
+# Gate cap per unit width (F/m)
+Gate->CapPerWidth = 0.950e-9
+# Source/Drain cap per unit width (F/m)
+Drain->CapPerWidth = 0.640e-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.890e-3
+Pmos->EffResWidth = 1.270e-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.78
+Pmos->EffResStackRatio = 0.66
+
+#------------------------------------------------------------------------------
+# 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 = 55e-9
+# Min spacing (m)
+Wire->Metal1->MinSpacing = 55e-9
+# Resistivity (Ohm-m)
+Wire->Metal1->Resistivity = 4.00e-8
+# Metal thickness (m)
+Wire->Metal1->MetalThickness = 100.0e-9
+# Dielectric thickness (m)
+Wire->Metal1->DielectricThickness = 100.0e-9
+# Dielectric constant
+Wire->Metal1->DielectricConstant = 3.2
+
+# Local wire, 1.0X of the M1 pitch
+# Min width (m)
+Wire->Local->MinWidth = 55e-9
+# Min spacing (m)
+Wire->Local->MinSpacing = 55e-9
+# Resistivity (Ohm-m)
+Wire->Local->Resistivity = 4.00e-8
+# Metal thickness (m)
+Wire->Local->MetalThickness = 100.0e-9
+# Dielectric thickness (m)
+Wire->Local->DielectricThickness = 100.0e-9
+# Dielectric constant
+Wire->Local->DielectricConstant = 3.2
+
+# Intermediate wire, 2.0X 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, 3.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/Bulk45LVT.model b/ext/dsent/tech/tech_models/Bulk45LVT.model
new file mode 100644
index 000000000..d8015c522
--- /dev/null
+++ b/ext/dsent/tech/tech_models/Bulk45LVT.model
@@ -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
index 000000000..335e1e832
--- /dev/null
+++ b/ext/dsent/tech/tech_models/Photonics.model
@@ -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
index 000000000..292e40ab0
--- /dev/null
+++ b/ext/dsent/tech/tech_models/TG11LVT.model
@@ -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
index 000000000..e8c9705bb
--- /dev/null
+++ b/ext/dsent/util/CommonType.h
@@ -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
index 000000000..a12a30070
--- /dev/null
+++ b/ext/dsent/util/Config.cc
@@ -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
index 000000000..910f5ca8c
--- /dev/null
+++ b/ext/dsent/util/Config.h
@@ -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
index 000000000..6af0a275a
--- /dev/null
+++ b/ext/dsent/util/Constants.cc
@@ -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
index 000000000..4447e6991
--- /dev/null
+++ b/ext/dsent/util/Constants.h
@@ -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
index 000000000..f2a1b23ea
--- /dev/null
+++ b/ext/dsent/util/Result.cc
@@ -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
index 000000000..96f0e5805
--- /dev/null
+++ b/ext/dsent/util/Result.h
@@ -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__
+