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:
Nilay Vaish 2014-10-11 15:02:23 -05:00
parent a098fad174
commit e8ed7b1d1b
183 changed files with 25714 additions and 0 deletions

423
ext/dsent/DSENT.cc Normal file
View 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
View 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
View 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
View 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
View 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.

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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__

View 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

View 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
View 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_;
}
}

View 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__

View 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();
}
}

View 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__

View 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
View 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
View 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__

View 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
View 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__

View file

@ -0,0 +1,7 @@
#include "MathUtil.h"
namespace LibUtil
{
const double Math::epsilon = 1e-15;
} // namespace LibUtil

View 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__

View 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

View 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
View 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
View 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
View file

@ -0,0 +1,10 @@
#include "DSENT.h"
int main(int argc, char** argv)
{
DSENT::DSENT::run(argc-1, argv+1);
return 0;
}

View 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

View 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__

View 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

View 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
View 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
View 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
View 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

View 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__

View 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

View 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__

View 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

View 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__

View 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

View 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__

View 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

View 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__

View 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

View 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__

View 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

View 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__

View 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

View 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__

View 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

View 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__

View 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

View 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__

View 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

View 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__

View 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

View 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__

View 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

View 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__

View 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

View 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__

View 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

View 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__

View 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

View 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__

View 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

View 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__

View 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

View 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__

View 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

View 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__

View 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

View 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__

View 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

View 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__

View 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

View 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__

View 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

View 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__

View 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

View 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__

View 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

View 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__

View 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

View 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__

View 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

View 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__

View 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

View 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__

View 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

View 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__

View 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

View 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__

View 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

View 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__

View 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