ext: add the source code for DSENT
This patch adds a tool called DSENT to the ext/ directory. DSENT is a tool that models power and area for on-chip networks. The next patch adds a script for using the tool.
This commit is contained in:
parent
a098fad174
commit
e8ed7b1d1b
183 changed files with 25714 additions and 0 deletions
423
ext/dsent/DSENT.cc
Normal file
423
ext/dsent/DSENT.cc
Normal file
|
@ -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
|
||||
|
64
ext/dsent/DSENT.h
Normal file
64
ext/dsent/DSENT.h
Normal file
|
@ -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__
|
||||
|
19
ext/dsent/LICENSE
Normal file
19
ext/dsent/LICENSE
Normal file
|
@ -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.
|
55
ext/dsent/Makefile
Normal file
55
ext/dsent/Makefile
Normal file
|
@ -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
|
374
ext/dsent/README
Normal file
374
ext/dsent/README
Normal file
|
@ -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.
|
||||
|
84
ext/dsent/configs/electrical-clos.cfg
Normal file
84
ext/dsent/configs/electrical-clos.cfg
Normal file
|
@ -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
|
57
ext/dsent/configs/electrical-link.cfg
Normal file
57
ext/dsent/configs/electrical-link.cfg
Normal file
|
@ -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
|
||||
|
81
ext/dsent/configs/electrical-mesh.cfg
Normal file
81
ext/dsent/configs/electrical-mesh.cfg
Normal file
|
@ -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
|
40
ext/dsent/configs/example.cfg
Normal file
40
ext/dsent/configs/example.cfg
Normal file
|
@ -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
|
||||
|
112
ext/dsent/configs/photonic-clos.cfg
Normal file
112
ext/dsent/configs/photonic-clos.cfg
Normal file
|
@ -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
|
||||
|
75
ext/dsent/configs/photonic-link.cfg
Normal file
75
ext/dsent/configs/photonic-link.cfg
Normal file
|
@ -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
|
||||
|
131
ext/dsent/configs/router.cfg
Normal file
131
ext/dsent/configs/router.cfg
Normal file
|
@ -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
|
||||
|
22
ext/dsent/libutil/Assert.h
Normal file
22
ext/dsent/libutil/Assert.h
Normal file
|
@ -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__
|
||||
|
239
ext/dsent/libutil/Calculator.cc
Normal file
239
ext/dsent/libutil/Calculator.cc
Normal file
|
@ -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
|
||||
|
86
ext/dsent/libutil/Calculator.h
Normal file
86
ext/dsent/libutil/Calculator.h
Normal file
|
@ -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__
|
||||
|
144
ext/dsent/libutil/Config.cc
Normal file
144
ext/dsent/libutil/Config.cc
Normal file
|
@ -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_;
|
||||
}
|
||||
}
|
||||
|
37
ext/dsent/libutil/Config.h
Normal file
37
ext/dsent/libutil/Config.h
Normal file
|
@ -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__
|
||||
|
17
ext/dsent/libutil/Exception.cc
Normal file
17
ext/dsent/libutil/Exception.cc
Normal file
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
29
ext/dsent/libutil/Exception.h
Normal file
29
ext/dsent/libutil/Exception.h
Normal file
|
@ -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__
|
||||
|
37
ext/dsent/libutil/LibUtil.h
Normal file
37
ext/dsent/libutil/LibUtil.h
Normal file
|
@ -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__
|
||||
|
86
ext/dsent/libutil/Log.cc
Normal file
86
ext/dsent/libutil/Log.cc
Normal file
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
43
ext/dsent/libutil/Log.h
Normal file
43
ext/dsent/libutil/Log.h
Normal file
|
@ -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__
|
||||
|
43
ext/dsent/libutil/Makefile
Normal file
43
ext/dsent/libutil/Makefile
Normal file
|
@ -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)
|
||||
|
242
ext/dsent/libutil/Map.h
Normal file
242
ext/dsent/libutil/Map.h
Normal file
|
@ -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__
|
||||
|
7
ext/dsent/libutil/MathUtil.cc
Normal file
7
ext/dsent/libutil/MathUtil.cc
Normal file
|
@ -0,0 +1,7 @@
|
|||
#include "MathUtil.h"
|
||||
|
||||
namespace LibUtil
|
||||
{
|
||||
const double Math::epsilon = 1e-15;
|
||||
} // namespace LibUtil
|
||||
|
21
ext/dsent/libutil/MathUtil.h
Normal file
21
ext/dsent/libutil/MathUtil.h
Normal file
|
@ -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__
|
||||
|
177
ext/dsent/libutil/OptionParser.cc
Normal file
177
ext/dsent/libutil/OptionParser.cc
Normal file
|
@ -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
|
57
ext/dsent/libutil/OptionParser.h
Normal file
57
ext/dsent/libutil/OptionParser.h
Normal file
|
@ -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__
|
||||
|
347
ext/dsent/libutil/String.cc
Normal file
347
ext/dsent/libutil/String.cc
Normal file
|
@ -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
|
||||
|
218
ext/dsent/libutil/String.h
Normal file
218
ext/dsent/libutil/String.h
Normal file
|
@ -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__
|
||||
|
10
ext/dsent/main.cc
Normal file
10
ext/dsent/main.cc
Normal file
|
@ -0,0 +1,10 @@
|
|||
|
||||
#include "DSENT.h"
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
DSENT::DSENT::run(argc-1, argv+1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
871
ext/dsent/model/ElectricalModel.cc
Normal file
871
ext/dsent/model/ElectricalModel.cc
Normal file
|
@ -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
|
||||
|
244
ext/dsent/model/ElectricalModel.h
Normal file
244
ext/dsent/model/ElectricalModel.h
Normal file
|
@ -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__
|
||||
|
86
ext/dsent/model/EventInfo.cc
Normal file
86
ext/dsent/model/EventInfo.cc
Normal file
|
@ -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
|
||||
|
32
ext/dsent/model/EventInfo.h
Normal file
32
ext/dsent/model/EventInfo.h
Normal file
|
@ -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__
|
||||
|
698
ext/dsent/model/Model.cc
Normal file
698
ext/dsent/model/Model.cc
Normal file
|
@ -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
|
||||
|
223
ext/dsent/model/Model.h
Normal file
223
ext/dsent/model/Model.h
Normal file
|
@ -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__
|
||||
|
306
ext/dsent/model/ModelGen.cc
Normal file
306
ext/dsent/model/ModelGen.cc
Normal file
|
@ -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
|
||||
|
30
ext/dsent/model/ModelGen.h
Normal file
30
ext/dsent/model/ModelGen.h
Normal file
|
@ -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__
|
||||
|
277
ext/dsent/model/OpticalModel.cc
Normal file
277
ext/dsent/model/OpticalModel.cc
Normal file
|
@ -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
|
143
ext/dsent/model/OpticalModel.h
Normal file
143
ext/dsent/model/OpticalModel.h
Normal file
|
@ -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__
|
||||
|
35
ext/dsent/model/PortInfo.cc
Normal file
35
ext/dsent/model/PortInfo.cc
Normal file
|
@ -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
|
||||
|
37
ext/dsent/model/PortInfo.h
Normal file
37
ext/dsent/model/PortInfo.h
Normal file
|
@ -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__
|
||||
|
70
ext/dsent/model/TransitionInfo.cc
Normal file
70
ext/dsent/model/TransitionInfo.cc
Normal file
|
@ -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
|
||||
|
50
ext/dsent/model/TransitionInfo.h
Normal file
50
ext/dsent/model/TransitionInfo.h
Normal file
|
@ -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__
|
||||
|
241
ext/dsent/model/electrical/BarrelShifter.cc
Normal file
241
ext/dsent/model/electrical/BarrelShifter.cc
Normal file
|
@ -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
|
||||
|
34
ext/dsent/model/electrical/BarrelShifter.h
Normal file
34
ext/dsent/model/electrical/BarrelShifter.h
Normal file
|
@ -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__
|
||||
|
400
ext/dsent/model/electrical/BroadcastHTree.cc
Normal file
400
ext/dsent/model/electrical/BroadcastHTree.cc
Normal file
|
@ -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
|
||||
|
54
ext/dsent/model/electrical/BroadcastHTree.h
Normal file
54
ext/dsent/model/electrical/BroadcastHTree.h
Normal file
|
@ -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__
|
||||
|
321
ext/dsent/model/electrical/DFFRAM.cc
Normal file
321
ext/dsent/model/electrical/DFFRAM.cc
Normal file
|
@ -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
|
||||
|
33
ext/dsent/model/electrical/DFFRAM.h
Normal file
33
ext/dsent/model/electrical/DFFRAM.h
Normal file
|
@ -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__
|
||||
|
235
ext/dsent/model/electrical/Decoder.cc
Normal file
235
ext/dsent/model/electrical/Decoder.cc
Normal file
|
@ -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
|
||||
|
33
ext/dsent/model/electrical/Decoder.h
Normal file
33
ext/dsent/model/electrical/Decoder.h
Normal file
|
@ -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__
|
||||
|
378
ext/dsent/model/electrical/DemuxTreeDeserializer.cc
Normal file
378
ext/dsent/model/electrical/DemuxTreeDeserializer.cc
Normal file
|
@ -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
|
||||
|
33
ext/dsent/model/electrical/DemuxTreeDeserializer.h
Normal file
33
ext/dsent/model/electrical/DemuxTreeDeserializer.h
Normal file
|
@ -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__
|
||||
|
434
ext/dsent/model/electrical/MatrixArbiter.cc
Normal file
434
ext/dsent/model/electrical/MatrixArbiter.cc
Normal file
|
@ -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
|
||||
|
33
ext/dsent/model/electrical/MatrixArbiter.h
Normal file
33
ext/dsent/model/electrical/MatrixArbiter.h
Normal file
|
@ -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__
|
||||
|
347
ext/dsent/model/electrical/Multiplexer.cc
Normal file
347
ext/dsent/model/electrical/Multiplexer.cc
Normal file
|
@ -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
|
||||
|
34
ext/dsent/model/electrical/Multiplexer.h
Normal file
34
ext/dsent/model/electrical/Multiplexer.h
Normal file
|
@ -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__
|
||||
|
214
ext/dsent/model/electrical/MultiplexerCrossbar.cc
Normal file
214
ext/dsent/model/electrical/MultiplexerCrossbar.cc
Normal file
|
@ -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
|
||||
|
38
ext/dsent/model/electrical/MultiplexerCrossbar.h
Normal file
38
ext/dsent/model/electrical/MultiplexerCrossbar.h
Normal file
|
@ -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__
|
||||
|
226
ext/dsent/model/electrical/MuxTreeSerializer.cc
Normal file
226
ext/dsent/model/electrical/MuxTreeSerializer.cc
Normal file
|
@ -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
|
||||
|
33
ext/dsent/model/electrical/MuxTreeSerializer.h
Normal file
33
ext/dsent/model/electrical/MuxTreeSerializer.h
Normal file
|
@ -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__
|
||||
|
239
ext/dsent/model/electrical/OR.cc
Normal file
239
ext/dsent/model/electrical/OR.cc
Normal file
|
@ -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
|
||||
|
36
ext/dsent/model/electrical/OR.h
Normal file
36
ext/dsent/model/electrical/OR.h
Normal file
|
@ -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__
|
||||
|
305
ext/dsent/model/electrical/RepeatedLink.cc
Normal file
305
ext/dsent/model/electrical/RepeatedLink.cc
Normal file
|
@ -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
|
||||
|
44
ext/dsent/model/electrical/RepeatedLink.h
Normal file
44
ext/dsent/model/electrical/RepeatedLink.h
Normal file
|
@ -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__
|
||||
|
106
ext/dsent/model/electrical/RippleAdder.cc
Normal file
106
ext/dsent/model/electrical/RippleAdder.cc
Normal file
|
@ -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
|
||||
|
30
ext/dsent/model/electrical/RippleAdder.h
Normal file
30
ext/dsent/model/electrical/RippleAdder.h
Normal file
|
@ -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__
|
||||
|
270
ext/dsent/model/electrical/SeparableAllocator.cc
Normal file
270
ext/dsent/model/electrical/SeparableAllocator.cc
Normal file
|
@ -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
|
||||
|
33
ext/dsent/model/electrical/SeparableAllocator.h
Normal file
33
ext/dsent/model/electrical/SeparableAllocator.h
Normal file
|
@ -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__
|
||||
|
218
ext/dsent/model/electrical/TestModel.cc
Normal file
218
ext/dsent/model/electrical/TestModel.cc
Normal file
|
@ -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
|
||||
|
32
ext/dsent/model/electrical/TestModel.h
Normal file
32
ext/dsent/model/electrical/TestModel.h
Normal file
|
@ -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__
|
||||
|
536
ext/dsent/model/electrical/router/Router.cc
Normal file
536
ext/dsent/model/electrical/router/Router.cc
Normal file
|
@ -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
|
||||
|
46
ext/dsent/model/electrical/router/Router.h
Normal file
46
ext/dsent/model/electrical/router/Router.h
Normal file
|
@ -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__
|
||||
|
201
ext/dsent/model/electrical/router/RouterInputPort.cc
Normal file
201
ext/dsent/model/electrical/router/RouterInputPort.cc
Normal file
|
@ -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
|
||||
|
33
ext/dsent/model/electrical/router/RouterInputPort.h
Normal file
33
ext/dsent/model/electrical/router/RouterInputPort.h
Normal file
|
@ -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__
|
||||
|
199
ext/dsent/model/electrical/router/RouterSwitchAllocator.cc
Normal file
199
ext/dsent/model/electrical/router/RouterSwitchAllocator.cc
Normal file
|
@ -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
|
||||
|
33
ext/dsent/model/electrical/router/RouterSwitchAllocator.h
Normal file
33
ext/dsent/model/electrical/router/RouterSwitchAllocator.h
Normal file
|
@ -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__
|
||||
|
489
ext/dsent/model/network/ElectricalClos.cc
Normal file
489
ext/dsent/model/network/ElectricalClos.cc
Normal file
|
@ -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
|
||||
|
37
ext/dsent/model/network/ElectricalClos.h
Normal file
37
ext/dsent/model/network/ElectricalClos.h
Normal file
|
@ -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__
|
||||
|
296
ext/dsent/model/network/ElectricalMesh.cc
Normal file
296
ext/dsent/model/network/ElectricalMesh.cc
Normal file
|
@ -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
|
||||
|
37
ext/dsent/model/network/ElectricalMesh.h
Normal file
37
ext/dsent/model/network/ElectricalMesh.h
Normal file
|
@ -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__
|
||||
|
512
ext/dsent/model/network/PhotonicClos.cc
Normal file
512
ext/dsent/model/network/PhotonicClos.cc
Normal file
|
@ -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
|
||||
|
37
ext/dsent/model/network/PhotonicClos.h
Normal file
37
ext/dsent/model/network/PhotonicClos.h
Normal file
|
@ -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__
|
||||
|
106
ext/dsent/model/optical/GatedLaserSource.cc
Normal file
106
ext/dsent/model/optical/GatedLaserSource.cc
Normal file
|
@ -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
|
||||
|
33
ext/dsent/model/optical/GatedLaserSource.h
Normal file
33
ext/dsent/model/optical/GatedLaserSource.h
Normal file
|
@ -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__
|
||||
|
105
ext/dsent/model/optical/LaserSource.cc
Normal file
105
ext/dsent/model/optical/LaserSource.cc
Normal file
|
@ -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
|
||||
|
33
ext/dsent/model/optical/LaserSource.h
Normal file
33
ext/dsent/model/optical/LaserSource.h
Normal file
|
@ -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__
|
||||
|
364
ext/dsent/model/optical/OpticalLinkBackendRx.cc
Normal file
364
ext/dsent/model/optical/OpticalLinkBackendRx.cc
Normal file
|
@ -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
|
||||
|
39
ext/dsent/model/optical/OpticalLinkBackendRx.h
Normal file
39
ext/dsent/model/optical/OpticalLinkBackendRx.h
Normal file
|
@ -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__
|
||||
|
355
ext/dsent/model/optical/OpticalLinkBackendTx.cc
Normal file
355
ext/dsent/model/optical/OpticalLinkBackendTx.cc
Normal file
|
@ -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
|
||||
|
39
ext/dsent/model/optical/OpticalLinkBackendTx.h
Normal file
39
ext/dsent/model/optical/OpticalLinkBackendTx.h
Normal file
|
@ -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__
|
||||
|
121
ext/dsent/model/optical/OpticalTestModel.cc
Normal file
121
ext/dsent/model/optical/OpticalTestModel.cc
Normal file
|
@ -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
|
||||
|
30
ext/dsent/model/optical/OpticalTestModel.h
Normal file
30
ext/dsent/model/optical/OpticalTestModel.h
Normal file
|
@ -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__
|
||||
|
338
ext/dsent/model/optical/RingDetector.cc
Normal file
338
ext/dsent/model/optical/RingDetector.cc
Normal file
|
@ -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
|
||||
|
54
ext/dsent/model/optical/RingDetector.h
Normal file
54
ext/dsent/model/optical/RingDetector.h
Normal file
|
@ -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__
|
||||
|
77
ext/dsent/model/optical/RingFilter.cc
Normal file
77
ext/dsent/model/optical/RingFilter.cc
Normal file
|
@ -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
|
||||
|
30
ext/dsent/model/optical/RingFilter.h
Normal file
30
ext/dsent/model/optical/RingFilter.h
Normal file
|
@ -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__
|
||||
|
403
ext/dsent/model/optical/RingModulator.cc
Normal file
403
ext/dsent/model/optical/RingModulator.cc
Normal file
|
@ -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
|
||||
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue