diff options
Diffstat (limited to 'ext/dsent')
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__ + |